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

数据结构第4问:什么是栈?

栈的特点

“栈”这个名字来源于它的形象比喻和数据结构的特点。

栈(Stack)在英文中原意是“堆叠”或者“一摞东西堆起来”,就像我们生活中把盘子或书本一层一层叠放起来一样。这个比喻很形象地反映了栈的数据操作规则:

  • 后进先出(LIFO,last in first out) :最后放上去的元素(最后入栈)会最先被取出(先出栈),就像你从一摞盘子中拿盘子时,最上面的盘子最容易取出。

因此,把这种后进先出操作的线性数据结构称为“栈”,就是基于这种“堆叠”的形象和操作方式的直观描述。

栈其实就是规定了只允许在一端进行插入或删除操作的线性表。其中:

  1. 栈顶(Top):即线性表允许进行插入和删除操作的一端。
  2. 栈底(Bottom):即不允许进行插入和删除操作的另一端。

栈的基本操作

InitStack(&S);		// 初始化一个空栈S
StackEmpty(S);		// 判断是否为空栈,是空栈则返回true,不是空栈返回false
Push(&S, x);		// 入栈,若栈S未满,则将x加入使之成为新栈顶
Pop(&S, x);			// 出栈,若栈S非空,则弹出栈顶元素,并用x返回
GetTop(S,&x);		// 读栈顶元素,但不出栈,若栈S非空,则用x返回栈顶元素
DestroyStack(&S);	// 销毁栈,并释放栈S占用的内存空间

栈的顺序存储结构

采用顺序存储结构的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时设置一个标记(top指针)指示当前栈顶元素的位置。

静态分配内存空间的顺序栈实例

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>#define MaxSize 100typedef struct
{int data[MaxSize];    // 栈元素存放空间int top;              // 栈顶指针
}stack;// 初始化一个空栈S
bool initStack(stack *S)
{S->top = -1;    // 第一个栈元素是从0开始的,所以栈顶指针为-1return true;
}// push,入栈,若栈S未满,则将x加入使之成为新栈顶
bool push(stack *S, int data)
{if(S->top < MaxSize - 1){S->data[++S->top] = data;return true;}return false;
}// pop,出栈,若栈S非空,则弹出栈顶元素,并用x返回
bool pop(stack *S, int *value)
{if (S->top == -1)  // 栈空return false;if (value != NULL)*value = S->data[S->top--];return true;
}// 读栈顶元素,但不出栈,若栈S非空,则用x返回栈顶元素
bool GetTop(stack S,int *value)
{if (S.top == -1)  // 栈空判断return false;if (value != NULL)*value = S.data[S.top];return true;
}// 销毁栈,并释放栈S占用的内存空间
bool DestroyStack(stack *S)
{S->top = -1;return true;
}// 判断栈空或非空,是空栈则返回true,不是空栈返回false
bool StackEmpty(stack *S)
{if(S->top == -1)return true;elsereturn false;
}

栈的链式存储结构

用链式存储结构的栈叫链栈,优点是便于多个栈共享存储空间和提高效率,且不存在栈满上溢的情况。通常使用单链表来实现,并且规定所有操作在表头进行。链栈有两种区分:有带节点的和不带头节点的。

动态分配内存空间且不带头节点的链栈实例

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>// 链式结构的栈
typedef struct Linknode
{int data;struct Linknode *next;
} linkstack;// 无头节点的链栈初始化
bool init_linkstack_no_head(linkstack **L)
{*L = NULL;return true;
}// 入栈,适合无头节点的链栈
bool push_node_no_head(linkstack **L, int data)
{linkstack *new_node = malloc(sizeof(linkstack));new_node->data = data;new_node->next = *L;*L = new_node;return true;
}// 出栈,适合无头节点的链栈
bool pop_node_no_head(linkstack **L, int *data)
{if (*L == NULL)return false; // 空栈,无法弹出linkstack *node;node = *L;*data = (*L)->data;(*L) = (*L)->next;free(node);return true;
}// 读栈顶元素,但不出栈,若栈S非空,则用data返回栈顶元素
bool GetTop_node(linkstack *L, int *data)
{if (L == NULL)return false;*data = L->data;return true;
}// 判断栈空或非空,是空栈则返回true,不是空栈返回false
bool judge_stack_empty(linkstack *L)
{if (L == NULL)return true;elsereturn false;
}// 销毁栈,并释放栈S占用的内存空间
bool destroy_stack_node(linkstack **L)
{if (*L == NULL)return false;linkstack *current;while (*L != NULL){current = *L;    // 保存当前节点地址*L = (*L)->next; // 栈顶指向下一节点free(current);   // 释放当前节点}*L = NULL;return true;
}

动态分配内存空间且带头节点的链栈实例

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>// 有头节点的链栈初始化
bool init_linkstack_have_head(linkstack **L)
{*L = malloc(sizeof(linkstack));if (*L == NULL)return false;(*L)->next = NULL;return true;
}// 入栈,适合有头节点的链栈
bool push_node_have_head(linkstack *L, int data)
{if (L == NULL)return false;linkstack *new_node = malloc(sizeof(linkstack));if (new_node == NULL)return false;new_node->data = data;new_node->next = L->next;L->next = new_node;return true;
}// 出栈,适合有头节点的链栈
bool pop_node_have_head(linkstack *L, int *data)
{// 空栈或者栈内只有头节点if (L == NULL || L->next == NULL)return false; // 创建临时变量存放要弹出的栈元素linkstack *node = L->next;*data = node->data;L->next = node->next;free(node);return true;
}// 读栈顶元素,但不出栈,若栈S非空,则用data返回栈顶元素,适合有头节点的链栈
bool GetTop_node_have_head(linkstack *L, int *data)
{if (L == NULL || L->next == NULL)return false;*data = L->next->data;return true;
}// 判断栈空或非空,是空栈则返回true,不是空栈返回false,适合有头节点的链栈
bool judge_stack_empty_have_head(linkstack *L)
{if (L == NULL || L->next == NULL)return true;elsereturn false;
}// 销毁栈,并释放栈S占用的内存空间,适合有头节点的链栈
bool destroy_stack_node_have_head(linkstack **L)
{// 头指针的指针本身不存在 或 头指针指向空,没有头节点// L 本身是一个二级指针,存放了头指针的地址// *L 是头指针,即指向链栈第一个节点的指针if (L == NULL || *L == NULL)return false;linkstack *current;while (*L != NULL){current = *L;    // 保存当前节点地址*L = (*L)->next; // 栈顶指向下一节点free(current);   // 释放当前节点}*L = NULL;return true;
}
http://www.lryc.cn/news/606157.html

相关文章:

  • BR/EDR PHY帧结构及其具体内容
  • 51c自动驾驶~合集12
  • python基础语法3,组合数据类型(简单易上手的python语法教学)(课后习题)
  • 从0到1了解热部署
  • 一天两道力扣(7)
  • 力扣 hot100 Day61
  • 银河麒麟桌面操作系统:自定义截图快捷键操作指南
  • 机器人学和自动化领域中的路径规划方法
  • 解决Git升级后出现的问题
  • 国产芯+单北斗防爆终端:W5-D防爆智能手机,助力工业安全通信升级
  • 将开发的软件安装到手机:环境配置、android studio设置、命令行操作
  • ClickHouse vs PostgreSQL:数据分析领域的王者之争,谁更胜一筹?
  • 2683. 相邻值的按位异或
  • USRP捕获手机/路由器数据传输信号波形(中)
  • DeepCompare文件深度对比软件:智能差异分析与可视化功能深度解析
  • visual studio 安装总结
  • 搭建文件共享服务器samba————附带详细步骤
  • Kubernetes (K8s) 部署Doris
  • Redis过期策略
  • 【嵌入式电机控制#23】BLDC:开环运动控制框架
  • 设计模式:命令模式 Command
  • 法国声学智慧 ,音响品牌SK (SINGKING AUDIO) 重构专业音频边界
  • Web开发-PHP应用原生语法全局变量数据接受身份验证变量覆盖任意上传(代码审计案例)
  • HighgoDB查询慢SQL和阻塞SQL
  • 电商项目_性能优化_高并发缓存一致性
  • 当过滤条件不符合最左前缀时,如何有效利用索引? | OceanBase SQL 优化实践
  • 0731 IO进程基础
  • FATFS文件系统
  • 从“救火”到“先知”:润建曲尺运维大模型如何重构网络运维价值链
  • 科研快报 |无人机+AI:广东防控基孔热背后的技术革命