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

大话数据结构之 < 栈>(C语言)

引言:栈(Stack)是一种重要的线性数据结构,它遵循 **“后进先出”(Last In, First Out,简称 LIFO)** 的原则,即最后放入栈中的元素会最先被取出。这种特性使得栈在很多场景中都有广泛应用,比如程序调用的栈帧管理、表达式求值、括号匹配等。本章介绍栈,包括其实现。

1.栈的概念及结构

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端 称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
  • 出栈:栈的删除操作叫做出栈。出数据也在栈顶

2.栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。(即栈是一种基于数组或链表实现的数据结构,其拥有自身的特性)

 

 


数组实现(静态顺序栈)

#include <stdio.h>
#include <stdbool.h>#define MAX_SIZE 100  // 栈的最大容量// 数组实现的栈结构
typedef struct {int data[MAX_SIZE];  // 静态数组存储栈元素int top;             // 栈顶指针
} ArrayStack;// 初始化栈
void initArrayStack(ArrayStack *stack) {stack->top = -1;  // 初始化为-1表示空栈
}// 判断栈是否为空
bool isArrayStackEmpty(ArrayStack *stack) {return stack->top == -1;
}// 判断栈是否已满
bool isArrayStackFull(ArrayStack *stack) {return stack->top == MAX_SIZE - 1;
}// 入栈操作
bool pushArrayStack(ArrayStack *stack, int value) {if (isArrayStackFull(stack)) {printf("栈已满,无法入栈!\n");return false;}stack->data[++stack->top] = value;return true;
}// 出栈操作
bool popArrayStack(ArrayStack *stack, int *value) {if (isArrayStackEmpty(stack)) {printf("栈为空,无法出栈!\n");return false;}*value = stack->data[stack->top--];return true;
}// 获取栈顶元素
bool peekArrayStack(ArrayStack *stack, int *value) {if (isArrayStackEmpty(stack)) {printf("栈为空!\n");return false;}*value = stack->data[stack->top];return true;
}// 打印栈内容
void printArrayStack(ArrayStack *stack) {if (isArrayStackEmpty(stack)) {printf("栈为空!\n");return;}printf("栈内容(从栈底到栈顶): ");for (int i = 0; i <= stack->top; i++) {printf("%d ", stack->data[i]);}printf("\n");
}

链表实现(静态链表栈)

#include <stdio.h>
#include <stdbool.h>#define MAX_NODES 100  // 最大节点数// 链表节点结构
typedef struct StackNode {int data;int next;  // 使用数组下标代替指针
} StackNode;// 链表实现的栈结构
typedef struct {StackNode nodes[MAX_NODES];  // 节点池int top;                     // 栈顶节点下标int freeList;                // 空闲节点链表头int size;                    // 当前栈大小
} LinkedStack;// 初始化栈
void initLinkedStack(LinkedStack *stack) {stack->top = -1;  // 空栈stack->size = 0;// 初始化空闲链表for (int i = 0; i < MAX_NODES - 1; i++) {stack->nodes[i].next = i + 1;}stack->nodes[MAX_NODES - 1].next = -1;  // 结束标记stack->freeList = 0;  // 第一个空闲节点
}// 从空闲链表分配一个节点
int allocateNode(LinkedStack *stack) {if (stack->freeList == -1) {return -1;  // 没有空闲节点}int nodeIndex = stack->freeList;stack->freeList = stack->nodes[nodeIndex].next;return nodeIndex;
}// 释放节点到空闲链表
void freeNode(LinkedStack *stack, int nodeIndex) {stack->nodes[nodeIndex].next = stack->freeList;stack->freeList = nodeIndex;
}// 判断栈是否为空
bool isLinkedStackEmpty(LinkedStack *stack) {return stack->top == -1;
}// 判断栈是否已满
bool isLinkedStackFull(LinkedStack *stack) {return stack->freeList == -1;
}// 入栈操作
bool pushLinkedStack(LinkedStack *stack, int value) {if (isLinkedStackFull(stack)) {printf("栈已满,无法入栈!\n");return false;}int newNode = allocateNode(stack);stack->nodes[newNode].data = value;stack->nodes[newNode].next = stack->top;stack->top = newNode;stack->size++;return true;
}// 出栈操作
bool popLinkedStack(LinkedStack *stack, int *value) {if (isLinkedStackEmpty(stack)) {printf("栈为空,无法出栈!\n");return false;}int topNode = stack->top;*value = stack->nodes[topNode].data;stack->top = stack->nodes[topNode].next;freeNode(stack, topNode);stack->size--;return true;
}// 获取栈顶元素
bool peekLinkedStack(LinkedStack *stack, int *value) {if (isLinkedStackEmpty(stack)) {printf("栈为空!\n");return false;}*value = stack->nodes[stack->top].data;return true;
}// 打印栈内容
void printLinkedStack(LinkedStack *stack) {if (isLinkedStackEmpty(stack)) {printf("栈为空!\n");return;}printf("栈内容(从栈顶到栈底): ");int current = stack->top;while (current != -1) {printf("%d ", stack->nodes[current].data);current = stack->nodes[current].next;}printf("\n");
}

这两种静态实现方式都不使用动态内存分配(malloc/free),适合在资源受限的环境中使用,如嵌入式系统。 


推荐优先使用动态数组实现栈,除非:
1. 栈大小变化极其剧烈且不可预测
2. 元素非常大(移动成本高)
3. 有严格的无上限要求
动态数组实现提供了更好的综合性能,而现代内存分配器和扩容策略(如倍增法)已经大大减少了其缺点。在C语言中,通过合理的realloc策略可以实现高效的动态数组栈。

选择哪种实现取决于具体应用场景、性能要求和资源限制。在大多数现代应用中,动态实现更为常用,因为它提供了更大的灵活性。而在嵌入式系统或对性能有严格要求的场景中,静态实现可能更合适。下面我们来看一下动态实现栈:

3. 动态实现栈(数组)

 #include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
//基本操作: 
// 1.初始化
// 2.销毁
// 3.判空
// 4.压栈
// 5.出栈
// 6.返回栈顶元素
// 7.返回栈中元素个数 //用顺序表实现栈
//栈的性质:后进先出 typedef int STDataType;typedef struct stack{STDataType* a;//指向栈底位置        int top;//已有栈顶元素的个数           int capacity;// 栈容量           }ST;//栈的初始化-- 和顺序表的一系列操作差不多 
void STInit(ST* ps)
{assert(ps); ps->a = (STDataType*)malloc(sizeof(STDataType)*4);if(ps->a == NULL){perror("malloc fail");return;} ps->capacity = 4;//初始化容量为4 ,不够再扩容//ps->top = 0;//top是栈顶元素下一个 ps->top = -1;//top是栈顶元素 }//栈的销毁 
void STDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a=NULL;ps->top=ps->capacity = 0;}//判空 
bool STEmpty(ST* ps)
{assert(ps);return ps->a[ps->top] == 0;
}void STPush(ST* ps, STDataType x)
{assert(ps);if(ps->top + 1 == ps->capacity){STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType)*ps->capacity*2);if(tmp == NULL){perror("realloc fail");return;}ps->a = tmp;ps->capacity *= 2; }ps->a[ps->top+1] = x;ps->top++;
}//出栈 
void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;}//栈中元素个数 
int STSize(ST* ps)
{assert(ps);return ps->top+1;
}//栈顶元素 
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));	return ps->a[ps->top];
}int main()
{ST st;STInit(&st);//初始化//压栈-- 向栈中放入数据STPush(&st,1); STPush(&st,2); STPush(&st,3); STPush(&st,4); STPush(&st,5); //取栈顶元素//根据栈的性质  top == 5 // 打印出来看一下printf("%d\n",STTop(&st));//出栈--弹出栈顶元素STPop(&st);STPop(&st);//Pop两次 -- 那么此时栈顶的元素应该为 3//打印出来看一下printf("%d\n",STTop(&st));STPop(&st);//此时栈中应该只有两个元素了//打印栈中元素的个数printf("%d\n",STSize(&st));//最终结果为 5 //           3//			   2 //销毁栈STDestroy(&st);//以上为一个栈从创建到销毁的完整的过程//能够完成栈的基本操作 return 0;} 

http://www.lryc.cn/news/601081.html

相关文章:

  • Pspice仿真电路:(三十四)如何使用Pspcie进行仿真
  • 每日一题【删除有序数组中的重复项 II】
  • k8s之控制器详解
  • 基于springboot的图书借阅系统
  • mysql-数据表-DDL语句
  • Python爬虫实战:诗词名句网《三国演义》全集
  • Redis C++客户端——通用命令
  • 相机标定相关原理
  • FitCoach AI:基于React+CloudBase的智能健身教练应用开发全解析
  • Ubuntu系统 系统盘和数据盘扩容具体操作
  • S7-200 SMART 数字量 I/O 组态指南:从参数设置到实战案例
  • 6G通感算
  • AI使能的SVD算子:基于深度学习的矩阵分解方法
  • 【计算机组成原理】第一章:计算机系统概述
  • python---元组解包(Tuple Unpacking)
  • Linux内核设计与实现 - 课程大纲
  • 通过redis_exporter监控redis cluster
  • 学习嵌入式的第三十二天-数据结构-(2025.7.24)IO多路复用
  • 数组内存学习
  • 英语听力口语词汇-8.美食类
  • VisionPro系列讲解 - 03 Simulator 模拟器使用
  • 20250726-4-Kubernetes 网络-Service DNS名称解析_笔记
  • MGER实验
  • selenium自动化鼠标和键盘操作
  • 幸福网咖订座点餐小程序的设计与实现
  • Compose笔记(三十八)--CompositionLocal
  • VS Code + LaTeX 绘制电气图完全指南(含 PlantUML 样式参考)
  • 酒店智能门锁SDK新V门锁系统接口函数[2025版]Delphi 7.0——东方仙盟硬件接口库
  • 方正小标宋简3.0,可编辑
  • Python - 100天从新手到大师 - Day6