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

【数据结构】——栈(Stack)的原理与实现

目录

  • 一. 栈的认识
    • 1. 栈的基本概念
    • 2.栈的基本操作
  • 二. 栈的核心优势
    • 1. 高效的时间复杂度
    • 2. 简洁的逻辑设计
    • 3. 内存管理优化
  • 三. 栈的代码实现
    • 1.栈的结构定义
    • 2. 栈的初始化
    • 3. 入栈 (动态扩容)
    • 4. 出栈
    • 5. 取栈顶数据
    • 6. 判断栈是否为空
    • 7. 获取栈的数据个数
    • 8.销毁
    • 9.完整代码展示
  • 总结

一. 栈的认识

1. 栈的基本概念

栈是一种特殊的线性表,只允许在固定的一端进行插入和删除元素的操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵循后进先出的原则。

  • 压栈: 栈的插入操作叫做进栈/压栈/入栈,入数据的元素在栈顶。
  • 出栈: 栈的出栈也叫删除操作,出数据也在栈顶。

在这里插入图片描述

2.栈的基本操作

操作描述时间复杂度
Push(x)将元素x压入栈顶O(1)
Pop()出栈弹出元素O(1)
Top()返回栈顶元素不出栈O(1)
Empty()检查栈是否为空O(1)
Size()返回栈中元素数量O(1)

二. 栈的核心优势

1. 高效的时间复杂度

  • 入栈、出栈、取栈顶均为常数时间O(1)操作,适合高频调用场景。
  • 专注“顶部”操作,避免不必要的复杂度。
  • 对比其他数据结构:
    数组:随机访问快O(1),但插入删除中间元素移动数据O(n);
    链表:插入删除中间元素快O(1),但随机访问慢O(n);

2. 简洁的逻辑设计

  • 减少代码的复杂度,设计更简单。
  • 通过压栈和出栈自动维护操作顺序,无需手动跟踪索引指针。

3. 内存管理优化

  • 局部性原理:栈操作集中在顶部,数据访问具有空间局部性,利用CPU缓存命中。
  • 动态扩容策略:栈实现如动态数组通过按需扩容平衡时间和空间效率。

三. 栈的代码实现

1.栈的结构定义

typedef struct Stack
{STDataType* a; // 动态数组,存储栈里的元素int top;       // 栈顶指针(初始为0,表示空栈)int capacity; // 栈的最大容量
}ST;
  • a:用指针指向一块内存。
  • top:指向当前栈顶的元素初始为0,表示空栈
  • capacity:栈的最大容量

2. 栈的初始化

//初始化
void STInit(ST* pst)
{pst->a = NULL;//top指向栈顶数据的下一个位置pst->capacity = pst->top = 0;
}
  • 初始化指针赋值为NULL,capacity和top赋值为0。

3. 入栈 (动态扩容)

//入栈
void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->capacity == pst->top){int newcapacity = pst->top == 0 ? 4 : 2 * pst->capacity;STDataType* newnode = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));if (newnode == NULL){perror("realloc fail");exit(-1);}pst->a = newnode;pst->capacity = newcapacity;}pst->a[pst->top] = x;pst->top++;
}
  • 当capacity等于top时,如果为空则开辟4个空间,不为空时开辟当前空间的二倍。
  • 将插入的值先存放在top下标位置再top++。

4. 出栈

//出栈
void STPop(ST* pst)
{assert(pst && pst->top>0);pst->top--;
}
  • 直接top- - 限制访问完成出栈。

5. 取栈顶数据

//取栈顶数据
STDataType STTop(ST* pst)
{assert(pst && pst->top>0);return pst->a[pst->top - 1];
}
  • top的位置是在最后一个元素的下一个位置,所以取栈顶数据直接取top减1的下标。

6. 判断栈是否为空

//判空
bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}
  • 返回值是bool类型,如果top == 0则返回true。

7. 获取栈的数据个数

//获取数据个数
int STSize(ST* pst)
{assert(pst);return pst->top;
}
  • 因为栈的位置是从0开始的,所以直接返回top就是栈内部的数据个数。

8.销毁

//销毁
void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}
  • 释放掉开辟的空间,将开辟的空间置为NULL,把top和capacity也置为空。

9.完整代码展示

  • Stack.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include<stdbool.h>typedef int STDataType;typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;//初始化
void STInit(ST* pst);//销毁
void STDestroy(ST* pst);//入栈
void STPush(ST* pst, STDataType x);//出栈
void STPop(ST* pst);//取栈顶数据
STDataType STTop(ST* pst);//判空
bool STEmpty(ST* pst);//获取数据个数
int STSize(ST* pst);
  • Stack.c
#include "Stack.h"//初始化
void STInit(ST* pst)
{pst->a = NULL;//top指向栈顶数据的下一个位置pst->capacity = pst->top = 0;
}//销毁
void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}//入栈
void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->capacity == pst->top){int newcapacity = pst->top == 0 ? 4 : 2 * pst->capacity;STDataType* newnode = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));if (newnode == NULL){perror("realloc fail");exit(-1);}pst->a = newnode;pst->capacity = newcapacity;}pst->a[pst->top] = x;pst->top++;
}//出栈
void STPop(ST* pst)
{assert(pst && pst->top>0);pst->top--;
}//取栈顶数据
STDataType STTop(ST* pst)
{assert(pst && pst->top>0);return pst->a[pst->top - 1];
}//判空  等于0就为真
bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}//获取数据个数
int STSize(ST* pst)
{assert(pst);return pst->top;
}

在这里插入图片描述
入栈顺序为:1 2 3 4 5
出栈顺序为:5 4 3 2 1

总结

根据上述讲解,相信大家对栈有更深层的理解了。栈是程序运行时内存管理的核心区域之一,遵循后进先出原则,由操作系统或运行时环境自动分配和释放,无需显式干预。其设计目标是高效管理函数调用和局部变量,但受限于固定大小,需谨慎使用以避免溢出。合理的使用栈能让程序又快又稳,滥用则容易崩溃。本篇文章到这里就结束了,感谢大家的阅读,你们的点赞收藏加关注就是博主最大的动力。


《前期回顾》

【数据结构】——顺序表链表(超详细解析!!!)
C语言——结构体指南(小白一看就懂!!!)
力扣(LeetCode) ——移除链表元素(C语言)

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

相关文章:

  • 最新Coze(扣子)智能体工作流:用Coze实现「图片生成-视频制作」全自动化,3分钟批量产出爆款内容
  • 自由学习记录(83)
  • 【Unity开发】Unity核心学习(一)
  • 简单了解:CS5803芯片技术解析:HDMI到V-by-One的信号转换
  • BGP特性笔记
  • Cursor替代品:亚马逊出品,Kiro免费使用Claude Sonnet4.0一款更注重流程感的 AI IDE
  • PG靶机 - PayDay
  • lowbit函数
  • 打靶日常-文件上传
  • 《Power Voronoi图的数学原理》
  • latex 中将新的一个section重新从1开始排序,而不是和前面的section继续排序
  • PHP Word 批注处理工程设计方案(基于 `docx` 模板 + 批注驱动)
  • 【Word VBA Zotero 引用宏错误分析与改正指南】【解决[21–23]参考文献格式插入超链接问题】
  • [AI React Web] E2B沙箱 | WebGPU | 组件树 | 智能重构 | 架构异味检测
  • Navicat 询问 AI | 优化 SQL 查询
  • 打造专属 React 脚手架:从 0 到 1 开发 CLI 工具
  • Redis中灵活结合SET和SETEX的方法及多语言工具库实现
  • C#自定义日期时间选择器
  • 用python可视化分析海南自贸港封关运作:动因、影响
  • velero 资源备份测试
  • 达梦数据库常见漏洞及处理方案
  • 计算机网络---用户数据报协议User Datagram Protocol(UDP)
  • Unity新手制作跑酷小游戏详细教程攻略
  • CMake笔记:配置(Configure)、生成(Generate)和构建(Build)
  • B站 韩顺平 笔记 (Day 17)
  • c++编程题-笔记
  • 电商双11美妆数据分析
  • 《Foundations and Recent Trends in Multimodal Mobile Agents: A Survey》论文精读笔记
  • 2025年手游防护终极指南:四维防御体系破解DDoS、外挂与协议篡改
  • 从人机协作到情感共鸣:智能销售机器人如何重塑零售体验