• I 栈的概念
    • I.I 栈
    • I.II 压栈
    • I.III 出栈
  • II.栈的实现
    • II.I图解
    • II.II代码的实现
      • II.II.I 大体框架
      • II.II.II 栈的初始化
      • II.II.III 入栈
      • II.II.IV 栈的销毁
      • II.II.V判断栈是否为空
      • II.II.VI出栈
      • II.II.VII获取栈顶元素
      • II.II.VIII获取栈中有效元素个数
  • III 全部代码
  • IV 总结

I 栈的概念

I.I 栈

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

I.II 压栈

栈的插入操作叫做进栈/压栈/入栈,入数据再栈顶。

I.III 出栈

栈的说着拿出操作叫做出栈。出数据也在栈顶。

II.栈的实现

II.I图解

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。数组的实现我们可以画个图理解理解,如图所示:

链表指针稍微复杂了些。
进栈出栈的示意图为:

II.II代码的实现

下面我们就用数组的形式来实现栈

II.II.I 大体框架

当我们对于链表的学习已经完成后,我们感受到数组的书写相对简单一些,和顺序表的书写一样,我们先创建三个test.c,Stack.c,Stack.h的文件。再头文件中创建结构体,代码如下:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int STDataType;
typedef struct Stack
{STDataType* a;int capacity;int top;
}ST;

接着书写我们要实现的接口函数:

void StackInit(ST* ps);
void StackPush(ST* ps, STDataType x);
void StackDestroy(ST* ps);
void StackPop(ST* ps);
STDataType StackTop(ST* ps);
int StackSize(ST* ps);// size指向栈顶的下一个
bool StackEmpty(ST* ps); //判断栈是否为空

注意:我们在使用boll这个函数的时候需要引入一个头文件stdbool.h。这样才能正常使用。

II.II.II 栈的初始化

代码如下:

void StackInit(ST* ps)
{assert(ps);ps->a = NULL;ps->capacity = 0;ps->top = 0;
}

简洁明了,一目了然。先断言,后变空,最后两个指向0.(顺口溜)然后我们就嘎嘎写完了。
在这里ps->top可以有两种写法。一种是上面代码将其变为0,另外一种就是将其变为-1。

II.II.III 入栈

和上上期我们说的顺序表一样,断言以后。我们首先考虑的是空间是否足够满不满的问题。满了,咱就给它扩容。一顿操作之后。我们通过指针指向了新的空间,最后实现入栈的操作,代码如下:

void StackPush(ST* ps, STDataType x)
{assert(ps);//考虑空间是否已满的情况if (ps->top == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);if (tmp == NULL){printf("realloc fail\n");exit(-1);}elseps->a = tmp;ps->capacity = newCapacity;}ps->a[ps->top] = x;ps->top++;
}

II.II.IV 栈的销毁

我们直接将ps->a给free掉,剩下照常,代码如下:

void StackDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->top = 0;
}

II.II.V判断栈是否为空

第一种方法,如果我们ps指向的top为真,那我们就返回真值否则返回假。

 if (ps -> top == 0){return true;}else{return false;}

事实上我们可以只用一行代码搞定这上面的内容

bool StackEmpty(ST* ps) //判断栈是否为空
{assert(ps);/**    if (ps -> top == 0){return true;}else{return false;}*/return ps->top == 0;
}

咱直接return 。

II.II.VI出栈

出栈我们首先要用到上面判断栈是否为空,判断后直接top–就完啦。

void StackPop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));ps->top--;
}

II.II.VII获取栈顶元素

同上判断栈是否为空,判断后我们注意由于我们初始化栈的时候ps->top=0因此我们的top指向的是后面一个元素,获取的时候就要减减来找到。

STDataType StackTop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}

II.II.VIII获取栈中有效元素个数

int StackSize(ST* ps)
{assert(ps);return ps->top;// size指向栈顶的下一个,
}

额,依然不复杂。写道这里我们所有关于栈的书写就写完了。

III 全部代码

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 capacity;int top;
}ST;void StackInit(ST* ps);// 初始化栈
void StackPush(ST* ps, STDataType x);// 入栈
void StackDestroy(ST* ps);// 销毁栈
void StackPop(ST* ps);// 出栈
STDataType StackTop(ST* ps);// 获取栈顶元素
int StackSize(ST* ps);// 获取栈中有效元素个数
bool StackEmpty(ST* ps); //判断栈是否为空

Stack.c

#include "Stack.h"void StackInit(ST* ps)
{assert(ps);ps->a = NULL;ps->capacity = 0;ps->top = 0;
}void StackPush(ST* ps, STDataType x)
{assert(ps);//考虑空间是否已满的情况if (ps->top == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity);if (tmp == NULL){printf("realloc fail\n");exit(-1);}elseps->a = tmp;ps->capacity = newCapacity;}ps->a[ps->top] = x;ps->top++;
}void StackDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->top = 0;
}void StackPop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));ps->top--;
}STDataType StackTop(ST* ps)
{assert(ps);assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}int StackSize(ST* ps)
{assert(ps);return ps->top;// size指向栈顶的下一个,
}bool StackEmpty(ST* ps) //判断栈是否为空
{assert(ps);/**    if (ps -> top == 0){return true;}else{return false;}*/return ps->top == 0;
}

test.c

#include "Stack.h"void TestStack1()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);StackPop(&st);StackPop(&st);StackPop(&st);StackPop(&st);//printf("%d", StackTop(&st));StackDestroy(&st);
}void TestStack2()
{ST st;StackInit(&st);StackPush(&st, 1);StackPush(&st, 2);StackPush(&st, 3);StackPush(&st, 4);printf("%d ", StackTop(&st));StackPop(&st);                   // 3 和 4出栈了printf("%d ", StackTop(&st));StackPop(&st);           StackPush(&st, 5);StackPush(&st, 6);while (!StackEmpty(&st)) // 我们要先取栈顶的数据{printf("%d ", StackTop(&st));StackPop(&st);}StackDestroy(&st);
}int main()
{TestStack1();TestStack2();return 0;}

运行结果完美的实现了先进后出,后进先出的原则

在main函数中我们已经先将3和4先出栈了,所以他们先打印出来,然后才是6521。

IV 总结

经过开始的顺序表的书写以及链表的学习应用,我们发现栈的书写还是相对容易的。要想学好数据结构还是要多多练习,多刷OJ题,希望我的文章对你能有所帮助,欢迎各位大佬在评论区纠正我的错误。期待的话,请多多给我点赞吧

数据结构-栈详解(大概)相关推荐

  1. 数据结构-栈详解(类C语言版)

    目录 栈的定义 概念 栈的抽象数据类型定义 顺序栈的基本操作 存储方式 顺序栈的表示 顺序栈的初始化 顺序栈判断是否为空 清空顺序栈 销毁顺序栈 顺序栈的入栈 顺序栈的出栈 取顺序栈的栈顶元素 链栈的 ...

  2. 数据结构-链栈详解(很朴实的那种)

    链栈的设计与运行 1.链栈 提起链栈,很容易就想到单链表,不过链栈确实可以看做是受限的单链表,因为只能在链表头部进行操作,所以在链栈中也不再附加头结点,栈顶指针就是链表的头指针. 老话一句,实践一遍, ...

  3. java数据结构-链表详解

    文章目录 1.数据结构-链表详解 1.1单链表 1.1.1单链表节点的尾部添加 1.1.2单链表节点的自动排序添加 1.1.3单链表节点的修改 1.1.4单链表节点的删除 1.2单链表面试题 1.2. ...

  4. ceph存储原理_赠书 | Linux 开源存储全栈详解——从Ceph到容器存储

    // 留言点赞赠书我有书,你有故事么?留言说出你的存储故事留言点赞前两名,免费送此书截止日期12.27号12.30号公布名单 // 内容简介 本书致力于帮助读者形成有关Linux开源存储世界的细致的拓 ...

  5. openstack架构详解图_英特尔顶级技术专家合力缔造精品:Linux开源网络全栈详解...

    日常水开篇 自1991年诞生起,Linux已经走过了接近三十年.Linux早已没有了问世时的稚气,正在各个领域展示自己成熟的魅力. 以Linux为基础,也衍生出了各种开源生态,例如网络和存储.而生态离 ...

  6. Struts2值栈详解

    Struts2值栈详解 基本介绍 ValueStack是Struts2的一个接口,字面意义为值栈,OgnlValueStack是 ValueStack的实现类,客 户端发起一个请求,struts2架构 ...

  7. Linux开源存储全栈详解

    最近和同事一起整了本书<Linux开源存储全栈详解:从Ceph到容器存储>,把Linux开源存储相关的项目做了个梳理,对于想了解或参与存储相关项目开发的人来说,应该会是个不错的参考.这里把 ...

  8. 【数据结构】共享栈详解 判断共享栈满条件栈顶指针变化详解记忆方法例题

    摘要:简单易懂,详细地介绍共享栈概念,指针,判断共享栈栈满条件以及记忆方法等 目录 共享栈概念 栈顶指针&变化详解 栈顶指针种类的记忆方法 判断栈满条件 判断栈满条件的记忆方法 例题 解题思路 ...

  9. 【数据结构】栈详解——压栈/入栈 | 弹栈/出栈 | 获取栈顶元素

    栈 顺序栈 栈的定义 栈(stack)又名堆栈,它是一种运算受限的线性表.限定仅在表尾进行插入和删除操作的线性表.这一端被称为栈顶,相对地,把另一端称为栈底.向一个栈插入新元素又称作进栈.入栈或压栈, ...

最新文章

  1. solidity 编程练习_学习Solidity编程语言并开始为区块链开发
  2. 网络推广外包——网络推广外包指出网站优化首先考虑关键词分类
  3. 【python之路14】发送邮件实例
  4. 程序员面试金典 - 面试题 17.07. 婴儿名字(并查集)
  5. AWS还是Firebase?在移动应用后端应该使用哪个?
  6. 正则表达式中的开头和结尾
  7. 快递送不上门,谁的锅?
  8. mybatis学习笔记(五):mybatis 逆向工程
  9. 龙芯2f灵珑一体机debian6系统重装
  10. Unity 与 UE4 双引擎版本四叉树的创建与可视化
  11. 【STC15】串行口1的相关寄存器解读
  12. HEVC之CU、PU、TU分析
  13. Overloaded operators
  14. 1 is not JSON serializable的解决方案
  15. 关于python教学
  16. android 接口sign,[原创]小米APP登录接口env、envkey、sign、hash算法
  17. 中国加油!武汉加油!
  18. 【JavaWeb学习】—iframe标签(四)
  19. 飞机行李托运java代码_CSS3 飞机行李托运单(含条形码)
  20. windows10驱动 x64--- 3环代码加载驱动(二)

热门文章

  1. fuzzy仿真 MATLAB,基于MATLAB的FUZZY控制器的设计和仿真
  2. win10系统截图快捷键
  3. Unity游戏安卓和苹果游戏中植入广告增加收入
  4. 小米机器人 尘盒配件_小米机器人怎么取出尘盒
  5. 兔子繁殖 c语言编程,c语言写的兔子繁殖- 斐波那契数列.每次只显示前两个.
  6. 一个30岁工控人的自白
  7. 机器学习中的Encoder和Decoder到底是什么
  8. android然后让list刷新到底部,Android笔记之:App列表之下拉刷新的使用
  9. python查找元素在列表中位置
  10. 带通滤波器幅频特性曲线图_滤波器和对讲机技术解析!