当前位置: 首页 > 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.dtcms.com/a/308022.html

相关文章:

  • CUDA系列之CUDA安装与使用
  • freeRTOS 消息队列
  • Cesium 快速入门(三)Viewer:三维场景的“外壳”
  • 【MySQL】MySQL大偏移量查询优化方案
  • 若依框架-前端二次开发快速入门简述
  • [硬件电路-109]:模拟电路 - 自激振荡器的原理,一种把直流能量转换成交流信号的装置!
  • Linux软件包管理器深度解析:从概念到实战
  • React开发依赖分析
  • TRAE 软件使用攻略
  • 快速搭建Node.js服务指南
  • python制作的软件工具安装包
  • c# net6.0+ 安装中文智能提示
  • 前端框架Vue3(二)——Vue3核心语法之OptionsAPI与CompositionAPI与setup
  • 超体积指标(Hypervolume Indicator,S 度量)详析
  • 【JMeter】性能测试脚本录制及完善
  • 辐射源定位方法简述
  • 【BUUCTF系列】[HCTF 2018]WarmUp1
  • 网络编程-IP
  • 计算机网络:什么是光猫
  • Hyperbrowser MCP:重新定义网页抓取与浏览器自动化的AI驱动工具
  • Solr升级9.8.0启动异常UnsupportedOperationException known Lucene classes
  • Tauri vs Electron 的全面对比
  • 生产管理升级:盘古IMS MES解锁全链路可控可溯,激活制造效率
  • LCM中间件入门(2):LCM核心实现原理解析
  • 牛客练习赛142 第四次忍界大战 并查集
  • 永磁同步电机无速度算法--直流误差抑制自适应二阶反推观测器
  • Gemini Fullstack LangGraph Quickstart(DeepSeek+Tavily版本)
  • 【React】diff 算法
  • Elasticsearch 索引及节点级别增删改查技术
  • 基于单片机胎压检测/锅炉蒸汽压力/气压检测系统