当前位置: 首页 > news >正文

【数据结构与算法】走进数据结构的“时间胶囊”——栈

大家好,我是小卡皮巴拉

文章目录

目录

引言

一.栈的基本概念

1.1 定义

1.2 特性

1.3 基本操作

二.栈的实现方式

2.1 顺序栈

2.2 链栈

三.顺序栈的实现

定义顺序栈的结构

初始化

入栈

检查栈是否为空

出栈

销毁

四.链栈的实现

定义链栈的结构

初始化

 入栈

检查栈是否为空

出栈

销毁

兄弟们共勉!!!  


每篇前言

博客主页:小卡皮巴拉 

咱的口号:🌹小比特,大梦想🌹

作者请求:由于博主水平有限,难免会有错误和不准之处,我也非常渴望知道这些错误,恳请大佬们批评斧正。

引言

在数据结构的大家庭中,栈以其独特的“后进先出”特性脱颖而出,就像是一个记录时间流逝的“时间胶囊”。每当有新数据加入时,它就被放置在栈顶,而最早加入的数据则静静地躺在栈底,等待被最后一个取出。

栈不仅是一个简单的数据结构,更是算法设计和程序优化中的得力助手。从函数调用栈的管理到递归问题的求解,栈的身影无处不在。它以其简洁明了的数据操作规则和高效的内存利用方式,成为了程序员们解决复杂问题时的首选工具。

在接下来的篇章中,我们将一起探索栈的奥秘,从定义到特性,再到丰富的应用场景,帮助大家真正掌握这一数据结构的核心知识。

一.栈的基本概念

1.1 定义

栈(Stack)是一种只允许在一端进行插入或删除的线性表。这端被称为栈顶(Top),另一端则被称为栈底(Bottom)。栈遵循后进先出(Last In First Out,LIFO)的原则,即最后插入的元素会第一个被删除。

1.2 特性

  • 后进先出:栈中最后一个插入的元素首先被删除。这是栈最显著的特点,也是它与其他线性表(如数组、链表)的主要区别。

  • 栈顶浮动,栈底固定:栈顶的位置随着元素的入栈和出栈而变化,而栈底则保持不变。

  • 不支持随机访问:栈的结构决定了只能在栈顶进行插入和删除操作,无法直接访问和修改栈中间的元素。

1.3 基本操作

栈的基本操作主要包括以下几种:

  1. 初始化栈:创建一个空栈,并设置栈底指针和栈顶指针。

  2. 判断栈是否为空:检查栈中是否包含元素,若栈为空则返回true,否则返回false。

  3. 入栈操作(Push):将新元素添加到栈顶。若栈未满,则将新元素放入栈中,并更新栈顶指针。

  4. 出栈操作(Pop):从栈顶移除元素。若栈非空,则弹出栈顶元素,并更新栈顶指针。

  5. 读取栈顶元素(GetTop/Peek):返回栈顶元素的值,但不删除它。若栈非空,则返回栈顶元素的值。

  6. 销毁栈:释放栈占用的存储空间。

二.栈的实现方式

栈的实现方式主要有两种:

2.1 顺序栈

利用数组实现,附设一个指针(top)指示当前栈顶元素的位置。顺序栈需要预分配一块连续的存储空间,其优点是访问速度快,但缺点是存在栈满上溢的风险。

2.2 链栈

采用链表实现,通常使用单链表,并规定所有操作都在链表的表头进行。链栈的优点是便于多个栈共享存储空间、不存在栈满上溢的情况,且插入和删除操作的时间复杂度为O(1)。但缺点是需要额外的指针存储空间。

三.顺序栈的实现

定义顺序栈的结构

首先,我们定义了一个名为STDataType的类型别名,它基于int类型。这个类型别名将用于栈中存储的数据元素。

接着,我们定义了一个名为Stack的结构体(通过typedef,我们也可以用ST来引用它)。这个结构体代表了一个栈的数据结构,并包含以下三个成员:

  1. arr:这是一个指向STDataType类型的指针。它用于动态分配数组,以存储栈中的元素。

  2. top:这是一个整型变量,表示栈顶的位置。在栈中,我们通常将数组的最后一个有效元素的位置视为栈顶。注意,这里的top成员变量实际上存储的是栈顶元素的索引(即数组中的位置),而不是指向栈顶元素的指针。因此,栈为空时,top的值通常被初始化为-1或栈的容量减1(取决于栈的实现方式)。

  3. capacity:这是一个整型变量,表示栈的容量,即栈能够存储的最大元素数量。这个值在栈的初始化时被设定,并且决定了为arr成员动态分配多少内存。

函数代码:

typedef int STDataType;
//定义栈的数据结构
typedef struct Stack
{STDataType* arr;int top;//指向栈顶位置int capacity;
}ST;

初始化

STInit函数用于初始化一个栈。它接收一个指向栈的指针ps作为参数。

  1. 检查指针:首先,使用assert确保传入的栈指针ps不是NULL

  2. 设置初始状态

    • 将栈的数组指针ps->arr设置为NULL,表示栈尚未分配存储空间。
    • 将栈顶位置ps->top设置为0,表示栈为空。
    • 将栈容量ps->capacity也设置为0,表示栈当前没有预设容量。

这样,栈就被初始化为一个空栈,准备进行后续的栈操作。

函数代码:

//初始化
void STInit(ST* ps)
{assert(ps);ps->arr = NULL;ps->top = ps->capacity = 0;
}

入栈

StackPush函数用于将一个元素压入栈顶。它接收两个参数:一个指向栈的指针ps和要压入栈的元素x

  1. 检查指针:首先,使用assert确保传入的栈指针ps不是NULL

  2. 检查容量:接着,检查栈是否已满(即栈顶位置ps->top是否等于栈容量ps->capacity)。

    • 如果栈已满,则进行扩容操作。首先计算新的容量newCapacity,如果当前容量为0,则新容量为4(初始容量),否则新容量为当前容量的两倍。
    • 使用realloc函数尝试为栈的数组ps->arr分配新的内存空间。如果realloc失败(返回NULL),则打印错误信息并退出程序。
    • 如果realloc成功,则更新栈的数组指针ps->arr和栈容量ps->capacity
  3. 入栈操作:在确认栈有足够的空间后,将元素x放入栈顶位置(即ps->arr[ps->top]),并将栈顶位置ps->top加1,以指向下一个空位置。

这样,元素x就被成功压入栈顶,栈的栈顶位置和容量(如果需要的话)也得到了更新。

函数代码:

void StackPush(ST* ps, STDataType x)  
{  assert(ps); // 确保栈指针有效  // 检查栈是否已满  if (ps->top == ps->capacity)  {  // 扩容操作  int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;  STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));  if (tmp == NULL)  {  perror("realloc fail!\n");  exit(1); // 扩容失败,退出程序  }  ps->arr = tmp; // 更新栈的数组指针  ps->capacity = newCapacity; // 更新栈的容量  }  // 入栈操作  ps->arr[ps->top++] = x; // 将元素放入栈顶,并更新栈顶位置  
}

检查栈是否为空

StackEmpty函数用于判断一个栈是否为空。它接收一个指向栈的指针ps作为参数,并返回一个布尔值。

  1. 检查指针:首先,使用assert确保传入的栈指针ps不是NULL

  2. 判断栈是否为空:然后,通过比较栈顶位置ps->top是否等于0来判断栈是否为空。如果ps->top等于0,表示栈中没有元素,栈为空;否则,栈不为空。

  3. 返回结果:最后,根据判断结果返回相应的布尔值。如果栈为空,则返回true(或等价地,返回非零值,但在C语言中通常使用true1来表示真);如果栈不为空,则返回false(或等价地,返回零值)。

函数代码:

#include <stdbool.h> // 包含头文件以支持布尔值  bool StackEmpty(ST* ps)  
{  assert(ps); // 确保栈指针有效  return ps->top == 0; // 判断栈是否为空,并返回结果  
}

出栈

StackPop函数用于从栈中移除栈顶元素。它接收一个指向栈的指针ps作为参数,并不返回任何值(即返回类型为void)。

  1. 检查栈是否为空:首先,使用assert宏和StackEmpty函数来确保栈不为空。如果栈为空,则StackEmpty(ps)将返回true(或非零值),导致assert失败,并可能终止程序(这取决于assert宏的具体实现和编译器的设置)。这是一种调试时的安全措施,用于防止对空栈进行出栈操作。

  2. 出栈操作:在确认栈不为空后,通过将栈顶位置ps->top减1来实现出栈操作。这实际上是将栈顶指针向下移动一位,从而“移除”了栈顶元素(但请注意,元素的值仍然保留在内存中,只是不再被视为栈的一部分)。

 函数代码:

#include <assert.h> // 包含头文件以支持assert宏  
#include "stack.h"  // 假设StackEmpty函数和ST结构体定义在这个头文件中  void StackPop(ST* ps)  
{  assert(!StackEmpty(ps)); // 确保栈不为空  --ps->top; // 将栈顶位置减1,实现出栈操作  
}

取栈顶元素

StackTop函数用于获取栈顶元素的值,但不移除该元素。它接收一个指向栈的指针ps作为参数,并返回栈顶元素的值。

  1. 检查栈是否为空:首先,使用assert宏和StackEmpty函数来确保栈不为空。如果栈为空,则StackEmpty(ps)将返回true(或非零值),导致assert失败,可能会终止程序(这取决于assert宏的具体实现和编译器的设置)。这是一种调试时的安全措施,用于防止对空栈进行取栈顶元素操作。

  2. 获取栈顶元素:在确认栈不为空后,通过访问栈数组ps->arr中栈顶位置ps->top的前一个元素(即ps->arr[ps->top - 1])来获取栈顶元素的值。由于栈顶位置ps->top是指向栈中下一个空位置的索引,因此栈顶元素实际上是位于ps->top - 1的索引处。

  3. 返回栈顶元素的值:最后,函数返回栈顶元素的值。

 函数代码:

#include <assert.h> // 包含头文件以支持assert宏  
#include "stack.h"  // 假设StackEmpty函数、ST结构体和STDataType类型定义在这个头文件中  STDataType StackTop(ST* ps)  
{  assert(!StackEmpty(ps)); // 确保栈不为空  return ps->arr[ps->top - 1]; // 返回栈顶元素的值  
}

销毁

STDestroy函数用于释放栈所占用的内存资源,并将栈结构体成员重置为初始状态。它接收一个指向栈的指针ps作为参数,并不返回任何值(即返回类型为void)。

  1. 释放栈数组内存:首先,函数检查栈数组指针ps->arr是否不为NULL。如果不为NULL,说明栈数组已经分配了内存,因此使用free函数释放这块内存。这是为了防止内存泄漏,即程序不再需要的内存没有被释放回系统。

  2. 重置栈结构体成员:在释放栈数组内存后,函数将栈结构体成员ps->arr重置为NULL,表示栈数组指针不再指向任何有效的内存区域。同时,将栈的容量ps->capacity和栈顶位置ps->top都重置为0,表示栈现在是空的,且没有分配任何内存。

函数代码:

#include <stdlib.h> // 包含头文件以支持free函数  
#include "stack.h"  // 假设ST结构体定义在这个头文件中  void STDestroy(ST* ps)  
{  if (ps->arr != NULL)  free(ps->arr); // 释放栈数组内存  ps->arr = NULL;    // 重置栈数组指针为NULL  ps->capacity = 0;  // 重置栈容量为0  ps->top = 0;       // 重置栈顶位置为0  
}

四.链栈的实现

定义链栈的结构

我们定义了两个主要结构来支持链栈的实现:

链栈节点结构 (StackNode):

  • STDataType data;:存储节点中的数据,STDataType 在此例中为 int 类型。
  • struct StackNode* next;:指向链栈中下一个节点的指针。若当前节点为链栈末尾,则此指针为 NULL

链栈结构 (LinkedStack):

  • StackNode* top;:栈顶指针,指向链栈的顶部节点(即最后压入的节点)。若链栈为空,则此指针为 NULL
  • // int capacity;:对于链栈,由于其容量是动态的(随着节点的添加和删除而变化),因此这个容量字段在此场景中通常不需要。它已被注释掉,表明在链栈的实现中不考虑此字段。

链栈(或链式栈)是基于链表实现的栈数据结构,它不需要预先分配固定大小的内存空间,能够动态地增长和缩小。数据压入(push)时,新节点被添加到栈顶;数据弹出(pop)时,栈顶节点被移除。

函数代码:

// 定义栈的数据类型  
typedef int STDataType;// 定义链栈的节点结构  
typedef struct StackNode {STDataType data;struct StackNode* next;
} StackNode;// 定义链栈的结构,包含栈顶指针和栈的容量(对于链栈,容量通常不是必需的,但这里为了完整性保留)  
typedef struct LinkedStack {StackNode* top;// int capacity; // 对于链栈,容量是动态的,因此不需要这个字段  
} LinkedStack;

初始化

函数名:initStack

目的:初始化链栈,确保栈顶指针指向NULL,从而表明链栈当前为空。

参数:LinkedStack* stack,这是一个指向链栈结构体的指针,用于访问和修改链栈的状态。

函数体详细解析:

 stack->top = NULL;

  • 这行代码执行了链栈初始化的核心操作。
  • stack->top 是对链栈结构体中栈顶指针成员的访问。
  • 将 stack->top 设置为 NULL 表示链栈当前不包含任何节点,即栈为空。

函数代码:

// 初始化链栈  
void initStack(LinkedStack* stack) {stack->top = NULL; // 栈顶指针初始化为NULL,表示空栈  
}

 入栈

函数名:push

目的:将新数据压入链栈中,使其成为栈顶元素。

参数:

  • LinkedStack* stack:指向链栈结构体的指针,用于访问和修改链栈的状态。
  • STDataType data:要压入链栈的数据。

函数体详细解析:

  1. 创建新节点
    • StackNode* newNode = (StackNode*)malloc(sizeof(StackNode));
    • 这行代码通过malloc函数动态分配内存,用于存储新节点。
    • sizeof(StackNode)计算了StackNode结构体所需的内存大小。
    • (StackNode*)是类型转换,将void*类型的malloc返回值转换为StackNode*类型。
  2. 内存分配失败处理
    • 检查newNode是否为NULL,以判断内存分配是否成功。
    • 若内存分配失败,则打印错误信息并退出程序。
  3. 设置新节点的数据
    • newNode->data = data;
    • 将函数参数data的值赋给新节点的data成员。
  4. 链接新节点到链栈
    • newNode->next = stack->top;
    • 将新节点的next指针指向当前的栈顶节点。
    • 这一步实现了链栈的“后进先出”(LIFO)特性,因为新节点被放在了链栈的顶部。
  5. 更新栈顶指针
    • stack->top = newNode;
    • 将栈顶指针指向新节点,完成压栈操作。

函数代码:

// 压栈操作  
void push(LinkedStack* stack, STDataType data) {StackNode* newNode = (StackNode*)malloc(sizeof(StackNode)); // 创建新节点  if (!newNode) {printf("Memory allocation failed\n");exit(EXIT_FAILURE);}newNode->data = data; // 设置新节点的数据  newNode->next = stack->top; // 新节点的next指向当前的栈顶节点  stack->top = newNode; // 栈顶指针指向新节点  
}

检查栈是否为空

函数名:isEmpty

目的:判断链栈是否为空。

参数:LinkedStack* stack,指向链栈结构体的指针,用于访问链栈的栈顶指针。

函数体详细解析:

  1. 判断链栈是否为空
    • return stack->top == NULL;
    • 这行代码通过比较栈顶指针stack->top是否为NULL来判断链栈是否为空。
    • stack->topNULL,则链栈为空,函数返回1
    • stack->top不为NULL,则链栈不为空,函数返回0

函数代码:

// 判断链栈是否为空  
int isEmpty(LinkedStack* stack) {return stack->top == NULL;
}

出栈

函数名称:pop

函数目的:从链栈中移除栈顶元素,并返回该元素的数据。

函数参数:

  • LinkedStack* stack:指向链栈结构体的指针,包含了链栈的栈顶指针和可能的其他管理信息。

函数返回值:

  • STDataType:被移除的栈顶元素的数据。

函数体解析:

  1. 检查链栈是否为空
    • if (isEmpty(stack)) { ... }
      • 调用isEmpty函数检查链栈是否为空。
      • 如果链栈为空,则打印错误信息“Stack underflow”,表示尝试从空栈中出栈。
      • 通过exit(EXIT_FAILURE)终止程序。这是一种错误处理方式,也可以选择返回一个特殊值来表示错误,但这里选择直接退出程序。
  2. 移除栈顶元素
    • StackNode* tempNode = stack->top;
      • 创建一个临时指针tempNode,并将其指向当前的栈顶节点。
    • STDataType poppedData = tempNode->data;
      • 从栈顶节点中获取数据,并将其存储在局部变量poppedData中。
    • stack->top = tempNode->next;
      • 将栈顶指针更新为指向下一个节点,这样原来的栈顶节点就被从链栈中移除了。
  3. 释放内存
    • free(tempNode);
    • 释放之前被移除的栈顶节点的内存。这是内存管理的重要步骤,防止内存泄漏。
  4. 返回数据
    • return poppedData;
      • 返回被移除的栈顶元素的数据。

函数代码:

// 出栈操作  
STDataType pop(LinkedStack* stack) {if (isEmpty(stack)) {printf("Stack underflow\n");exit(EXIT_FAILURE); // 或者返回一个特殊值表示错误,这里选择退出程序  }StackNode* tempNode = stack->top; // 临时节点指向栈顶节点  STDataType poppedData = tempNode->data; // 获取栈顶节点的数据  stack->top = tempNode->next; // 栈顶指针指向下一个节点  free(tempNode); // 释放栈顶节点的内存  return poppedData; // 返回出栈的数据  
}

销毁

函数名称destroyStack

函数目的:释放链栈中所有节点的内存,从而销毁链栈。

函数参数

  • LinkedStack* stack:指向链栈结构体的指针,包含了链栈的栈顶指针和可能的其他管理信息。

函数解析

destroyStack函数通过循环调用pop函数来逐个移除链栈中的节点,并在每次移除节点时释放其内存。这个过程会一直持续到链栈为空。

  1. 循环检查链栈是否为空
    • 使用while (!isEmpty(stack))循环,只要链栈不为空,就继续执行循环体内的操作。
  2. 出栈操作
    • 在循环体内,调用pop(stack)函数。pop函数会移除链栈的栈顶节点,并释放其内存。同时,pop函数还会返回被移除节点的数据,但在destroyStack函数中,我们并不关心这个返回值。
  3. 无需额外销毁操作
    • 由于pop函数已经负责释放了所有节点的内存,因此destroyStack函数本身不需要进行额外的销毁操作。但是,为了保持接口的一致性(例如,与其他数据结构的销毁函数保持类似的签名),destroyStack函数还是被保留了下来。
  4. 函数结束
    • 当链栈为空时,isEmpty(stack)将返回truewhile循环将终止,destroyStack函数也随之结束。此时,链栈中的所有节点都已经被释放,链栈已被销毁。

函数代码:

// 销毁链栈(释放所有节点的内存)  
void destroyStack(LinkedStack* stack) {while (!isEmpty(stack)) {pop(stack); // 通过出栈操作释放所有节点的内存  }// 对于链栈,由于我们已经在出栈时释放了所有节点的内存,因此不需要额外的销毁操作  // 但为了保持接口的一致性,这里还是保留了这个函数  
}

兄弟们共勉!!!  

码字不易,求个三连

抱拳了兄弟们!

相关文章:

【数据结构与算法】走进数据结构的“时间胶囊”——栈

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 引言 一.栈的基本概念 1.1 定义 1.2 特性 1.3 基本操作 二.栈的实现方式 2.1 顺序栈 2.2 链栈 三.顺序栈的实现 定义顺序栈的结构 初始化 入栈 检查栈是否为空 出栈 销毁 四.链栈的实现 定义链栈的结构 初始…...

伺服增量式和绝对式的本质区别?

伺服增量式和绝对式的本质区别&#xff1f; 增量式编码器是将位移转换成周期性的电信号&#xff0c;再把这个电信号转变成计数脉冲&#xff0c;用脉冲的个数表示位移的大小。以转动时输出脉冲&#xff0c;通过计数设备来知道其位置&#xff0c;当编码器不动或停电时&#xff0c…...

应对 .DevicData-X-XXXXXXXX 勒索病毒:防御与恢复策略

引言 随着信息技术的快速发展&#xff0c;网络安全问题愈发严峻。勒索病毒作为一种恶性网络攻击手段&#xff0c;已成为企业和个人面临的重大威胁之一。尤其是 .DevicData-X-XXXXXXXX 勒索病毒&#xff0c;其通过加密用户数据并勒索赎金&#xff0c;给受害者带来了巨大的经济损…...

【代码随想录——数组——二刷】

数组 1. 二分查找(704) 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 1.1 二分法的第一种写法 我们定义 target 是在…...

spring-boot(4)

1.VueRouter安装与使用 2.状态管理VueX 3. 4. 5. 6....

深度学习模型:原理、架构与应用

深度学习(Deep Learning)是机器学习中的一个分支,基于人工神经网络的发展,尤其是多层神经网络的研究,使其在语音识别、图像处理、自然语言处理等领域取得了显著进展。深度学习的核心是通过大量数据的训练,学习到数据的内在结构和模式,并且具备自动从复杂的输入中提取特征…...

玩客云Armbian安装Casaos

#armbian安装docker apt install docker.io #armbian判断docker是否正常运行 systemctl status docker #查看版本 docker version #安装casaos方式一 wget -qO- https://get.casaos.io | bash #安装casaos方式二 curl -fsSL https://get.casaos.io | bash...

redis过期提醒

文章目录 redis过期提醒 redis过期提醒 有一次看redis的配置文件发现一个notify-keyspace-events配置&#xff0c;注释里边长篇大论的&#xff0c;那我得看看这是干啥的&#xff0c;看完注释内容&#xff0c;发现不得了了&#xff0c;redis竟然还有过期提醒的功能 接下来得大…...

AnaTraf | 提升网络性能:深入解析网络关键指标监控、TCP重传与TCP握手时间

AnaTraf 网络性能监控系统NPM | 全流量回溯分析 | 网络故障排除工具 在当今的数字化时代&#xff0c;网络的稳定性和性能对企业的运营效率至关重要。无论是内部通信、应用程序的运行&#xff0c;还是对外提供服务&#xff0c;网络都发挥着关键作用。对于网络工程师或IT运维人员…...

黑盒测试和白盒测试的具体方法(附加实际应用中的技巧和注意事项)

黑盒测试的具体方法 黑盒测试有多种具体的方法&#xff0c;以下是几种常见的黑盒测试技术&#xff1a; 等价类划分 定义&#xff1a;将输入数据划分为若干等价类&#xff0c;每个等价类中的数据被认为是等效的。目的&#xff1a;减少测试用例数量&#xff0c;同时覆盖所有可…...

基于ssm的小区物业管理系统

文未可获取一份本项目的java源码和数据库参考。 题目简介&#xff1a; 我国物权法的颁布以及经济的快速发展进一步提升了社区居民对物业服务和物业管理的要求&#xff0c;特别是对于社区安全、社区停车以及社区维修等各个方面提出了更为严格的要求。在这种背景下社区物业必须…...

4本SCI/SSCI期刊更名,10月WOS更新!速看!

期刊动态 2024年10月科睿唯安期刊目录更新 2024年10月22日&#xff0c;科睿唯安更新了WOS期刊目录&#xff0c;此次更新&#xff0c;期刊被编辑除名11本&#xff0c;停止出版1本&#xff0c;4本更名&#xff0c;停产1本&#xff0c;新增63本。 剔除期刊 11本期刊被剔 Enginee…...

麒麟v10系统安装docker镜像

最近把系统搞崩了&#xff0c;又重新安装了一个麒麟系统&#xff0c;yum更新发现不能安装docker&#xff0c;所以这里给出一个安装教程&#xff0c;分享出来&#xff0c;让大家少走弯路&#xff1a; # 配置阿里云 Centos8 镜像源&#xff0c;需要额外的一些依赖&#xff0c;而…...

基于SSM大学校医院信息管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;校医管理&#xff0c;用户管理&#xff0c;在线问诊管理&#xff0c;线上挂号管理&#xff0c;病例记录管理&#xff0c;系统管理 校医账号功能包括&#xff1a;系统首页&#xff0c;个人中心&#xf…...

【JS】如何识别一个变量是不是数组对象

文章目录 1. Array.isArray()语法示例 2. Object.prototype.toString.call()语法示例 3. instanceof 操作符语法示例 4. 检查 constructor属性语法示例 总结 在 JavaScript 中&#xff0c;有几种方法可以用来识别一个变量是否是数组对象。以下是一些常用的方法&#xff1a; 1. …...

探索 Python 幽默之源:pyjokes 库全解析

&#x1f680; 探索 Python 幽默之源&#xff1a;pyjokes 库全解析 1. 背景介绍&#xff1a;为何选择 pyjokes&#xff1f; 在紧张的编程工作中&#xff0c;幽默是一种有效的缓解压力的方式。pyjokes 是一个专为程序员设计的 Python 库&#xff0c;它提供了丰富的单行笑话&am…...

苦寻多时,终于找到!这款免费GIS工具助你轻松搞定地形切片

概述 地形切片是将大范围的地形数据分割成小块&#xff08;切片&#xff09;进行存储和展示的技术&#xff0c;常用于高效的三维地形可视化和动态加载。在实际操作中&#xff0c;可以通过GISBox等工具进行地形切片处理。今天和大家安利的GISBox 是一个用于GIS模型切片、服务分…...

OpenResty性能分析:以HelloWorld服务器为例

软考鸭微信小程序 学软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 在Web开发领域&#xff0c;性能是衡量服务器和应用质量的重要指标之一。对于简单的HelloWorld服务器&#xff0c;虽然其功能有限&#xff0c;但通过对其性能…...

pb生成文件和反射

1.protoc生成文件 指定生成的目录和proto文件路径&#xff0c; protoc --cpp_out./ ./echo.proto // echo.proto syntax "proto3";package echo;option cc_generic_services true;message EchoRequest {string msg 1; }message EchoResponse {string msg 2; }…...

.net framework 3.5sp1安装错误卡住不动怎么解决

解决 .NET Framework 3.5 SP1 安装错误卡住的问题&#xff0c;可以尝试以下几种方法&#xff1a; 1.使用 DISM 工具&#xff1a; 将下载的 NetFx3.cab 文件放置在 C:\Windows 文件夹下。 以管理员身份打开命令提示符&#xff0c;输入以下命令&#xff1a; dism /online /En…...

毕业设计—基于 Inception-ResNet模型的皮肤癌分类系统实现

1.摘要 皮肤癌是人类最常见的恶性肿瘤&#xff0c;主要通过视觉诊断进行初步临床筛查。但是由于皮肤病变外观的细微变化性&#xff0c;使用图像自动分类皮肤病变是一项具有挑战性的任务。本文为了提高深度学习算法在皮肤病检测上的准确率&#xff0c;本文提出了基于Inception和…...

什么是优秀的单元测试?

阅读本文之前&#xff0c;请投票支持这款 全新设计的脚手架 &#xff0c;让 Java 再次伟大&#xff01; 单元测试的质量意义 合理编写单元测试&#xff0c;可使团队工程师告别牛仔式编程&#xff0c;产出易维护的高质量代码。随着单元测试覆盖率的上升&#xff0c;项目会更加…...

服务器安装Anaconda,Anaconda安装Pytorch

1.服务器安装Anaconda 1.1 下载Anaconda 在服务器上直接下载 wget https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh1.2 安装Anaconda bash Anaconda3-2024.06-1-Linux-x86_64.sh然后就显示下面&#xff1a;more 安装过程一直enter即可&#xff0c;…...

YOLO目标检测理论详解,YOLOv1理论知识讲解,超w字精读(学习YOLO框架必备),全网最详细教程

文章目录 前言一、目标检测理论1.目标检测发展史2.目标检测框架理论基础3.本章小结 二、YOLOv1理论知识1.YOLOv1网络结构2.YOLOv1检测原理3.YOLOv1的训练流程&#xff08;1&#xff09;边界框的位置参数&#xff08;2&#xff09;边界框的置信度&#xff08;3&#xff09;类别置…...

SpringBoot3.x和OCR构建车牌识别系统

本专题旨在展示 OCR 技术与 SpringBoot3.x 框架结合的广泛应用。我们会深入探讨它在医疗、金融、教育、交通、零售、公安等多个领域的现实应用。每个应用场景都会提供详细的实例、面临问题的分析与解决策略&#xff0c;以帮助您深入理解 OCR 技术在实践中的关键作用。让我们一同…...

conda 容器学习笔记之一 -- 基础环境配置

1、容器瘦身导致部分应用缺少&#xff0c;需要在非容器环境下部署环境。但为避免破坏现有环境&#xff0c;现有使用conda环境进行隔离管理 创建&#xff1a;conda create -n tts python3.10.0 2、conda 是python环境管理&#xff0c;和python无关的东西比如cann还是会影响 下载…...

Oracle分区表改造(三):通过分区交换和分裂改造为分区表

Oracle分区表改造(三):通过分区交换和分裂改造为分区表 源表数据准备范围分区表改造:非间隔分区创建普通分区表分区交换分区分裂范围分区表改造:间隔分区创建间隔分区表分区交换分区分裂表重命名🐬 创建只有一个分区的分区表, 通过分区交换将原表变成分区表,然后分裂分…...

LeetCode 0908.最小差值 I:思维(遍历)

【LetMeFly】908.最小差值 I&#xff1a;思维&#xff08;遍历&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/smallest-range-i/ 给你一个整数数组 nums&#xff0c;和一个整数 k 。 在一个操作中&#xff0c;您可以选择 0 < i < nums.length 的…...

Python基础之循环语句

在Python的编程世界里&#xff0c;循环结构犹如一把神奇的钥匙&#xff0c;开启高效处理数据和重复执行任务的大门。它赋予程序员强大的力量&#xff0c;让代码充满活力。Python主要有两种类型的循环语句&#xff1a;for循环和while循环。 一、for循环 for循环通常用于遍历一个…...

项目管理软件真的能让敏捷开发变得更简单吗?

敏捷开发是一种以快速交付和适应变化为核心特点的软件开发方法。其特点包括尽早并持续交付、能够驾驭需求变化、版本周期内尽量不加任务、业务与开发协同工作、以人为核心、团队配置敏捷等。 例如&#xff0c;尽早并持续交付可使用的软件&#xff0c;使客户能够更早地体验产品…...