栈的定义

栈是一种特殊的线性表,它的逻辑结构和线性表相同,只是运算规则与线性表相比有了更多的限制,其实之后会接触的一种数据结构——队列也是特殊的线性表,但队列不在本篇讨论的范围了。栈与队列都可以称作运算受限的线性表

具体来讲它的定义,栈是限制在表的一端进行插入和删除的线性表。允许插入、删除的这一端称为栈顶,而距离栈顶最远的(即另一个固定端)称为栈底,当表中没有元素时成为空栈。因为只能在一端插入或删除,所以我们可以说栈是按“后进先出”的规则进行操作,称为后进先出的线性表,简称LIFO表。栈的插入操作我们称为进栈,又叫做入栈;栈的删除操作我们称为出栈,又叫做弹栈。
如上图,栈像极了一个容器,我们可以往里面放东西,而要拿东西出来的时候,我们只能拿位于容器上面的东西。那按照这种说法,是不是最先进栈的元素一定最后一个出栈呢?答案是非也。

我们举个例子,现有三个元素1、2、3,要将这三个元素依次进栈,出栈的顺序有几种呢。

  • 1、2、3依次进栈,出栈的顺序就是3、2、1。
  • 1进,2进,2出,1出,3进,3出,出栈的顺序是2、1、3。
  • 1进,1出,2进,3进,3出,2出,出栈的顺序是1、3、2。
  • 1进,2进,2出,3进,3出,1出,出栈的顺序是2、1、3。
  • 1进,1出,2进,2出,3进,3出,出栈的顺序是1、2、3。

上述情况可知,元素出栈的形式是多变的。

栈的基本操作

我们在上面说过:栈是一种特殊的线性表,那么也和线性表一样分为两类:顺序栈链栈(下图)。

定义

顺序栈我们可以用数组来表示,通常来说,0 下标端设为栈底,并且用一个栈顶指针top来表示,比如当栈内有 5 个元素,那么栈顶元素的下标就是 4,即 top = 4 ,由此推出,若栈此时为空栈时,栈顶指针 top = -1 ,入栈时,栈顶指针加 1。

// define Status
typedef enum Status {ERROR = 0, SUCCESS = 1
} Status;// define element type
typedef int ElemType;// define struct of stack
typedef struct SqStack {ElemType *elem;int top;int size;            //定义栈的大小
} SqStack;

链栈和链表就差不多了,与顺序栈相比,同样是需要一个栈顶指针指向栈顶,进栈和出栈采用类似链表中的插入、删除接口来完成,值得注意的是,栈的主要运算是在栈顶插入、删除,显然在链表的头部作栈顶最方便(插入采用前插法)。

// define Status
typedef enum Status {ERROR = 0, SUCCESS = 1
} Status;// define element type
typedef int ElemType;// define struct of stack
typedef struct StackNode
{ElemType data;struct StackNode *next;
}StackNode, *LinkStackPtr;//define pointer of stack
typedef struct LinkStack{LinkStackPtr top;int   count;
}LinkStack;

初始化

链栈中我们为 s->top 申请了内存空间,而这个空间是指针的空间,不是栈的空间, s->top 只是一个指针,s-> top->next才是 s->top指针所指的栈顶元素。

//基于数组的顺序栈
Status initStack(SqStack *s,int sizes)
{s->elem = (ElemType*)malloc(sizes * sizeof(ElemType));if (!s->elem)return ERROR;s->top = -1;s->size = sizes;return SUCCESS;
}//基于链表的链栈
Status initLStack(LinkStack *s)
{s->top = (LinkStackPtr)malloc(sizeof(StackNode));if (!s->top)return ERROR;s->count = 0;return SUCCESS;
}

判断栈是否为空

这个接口其实特别简单,要判断栈是否为空,顺序栈就是看 s->top 是不是等于 -1;链栈就是看 s->count 是不是等于 0(也可以看 s->top->next 是否为NULL)

//基于数组的顺序栈
Status isEmptyStack(SqStack *s)
{return s->top == -1;
}//基于链表的链栈
Status isEmptyLStack(LinkStack *s)
{return s->count == 0;
}

读栈顶元素

当然是要瞧瞧栈顶指针指的那个位置啦

//基于数组的顺序栈
Status getTopStack(SqStack *s,ElemType *e)
{if (s->top == -1)return ERROR;*e = s->elem[s->top];return SUCCESS;
}//基于链表的链栈
tatus getTopLStack(LinkStack *s,ElemType *e)
{if(s->count == 0 || !s->top)return ERROR;*e = s->top->next->data;return SUCCESS;
}

清空

这里的清空并不是销毁,清空只是把所有元素出栈而已,栈还是可以继续使用的。

//基于数组的顺序栈
Status clearStack(SqStack *s)
{if (!s)return ERROR;s->top = -1;return SUCCESS;
}//基于链表的链栈
Status clearLStack(LinkStack *s)
{LinkStackPtr ptem, p = s->top->next;            //p指向栈顶元素if (!s->top)return ERROR;while (p){                     //这里也可以循环调用出栈接口ptem = p->next;free(p);                  //free栈顶元素p = ptem;}s->count = 0;                  //计数器归零return SUCCESS;
}

销毁

要把我们申请的内存空间全部free

//基于数组的顺序栈
Status destroyStack(SqStack *s)
{if (!s)return ERROR;free(s->elem);return SUCCESS;
}//基于链表的链栈
Status destroyLStack(LinkStack *s)
{LinkStackPtr ptem, p = s->top->next;if (!s->top)return ERROR;while (s->count != 0){          //这里也可以调用清空接口ptem = p->next;free(p);s->top->next = ptem;s->count--;}free(s->top);return SUCCESS;
}

栈长

栈的长度直接看 s->top 和 s->count 的值就可以啦

//基于数组的顺序栈
Status stackLength(SqStack *s,int *length)
{if (!s)return ERROR;*length = s->top + 1;return SUCCESS;
}//基于链表的链栈
Status LStackLength(LinkStack *s,int *length)
{if (!s->top)return ERROR;*length = s->count;return SUCCESS;
}

进栈

因为顺序栈需要我们事先定义栈的大小,所以在进栈操作前,要先判断栈是否已满;而链栈在某个层面上说是没有大小限制的,可以随便进栈,除非内存满了。

//基于数组的顺序栈
Status pushStack(SqStack *s,ElemType data)
{if (!s || s->top == s->size - 1)       //判断栈是否已满return ERROR;s->top++;s->elem[s->top] = data;return SUCCESS;
}//基于链表的链栈
Status pushLStack(LinkStack *s,ElemType data)
{StackNode *p;if(!s->top)return ERROR;p = (StackNode*)malloc(sizeof(StackNode));p->data = data;p->next = s->top->next;s->top->next = p;s->count++;return SUCCESS;
}

出栈

出栈也要判断一下栈是否已空

//基于数组的顺序栈
Status popStack(SqStack *s)
{if (!s || s->top == -1)       //这里也可以调用 “判断栈是否为空” 接口return ERROR;s->top--;return SUCCESS;
}//基于链表的链栈
Status popLStack(LinkStack *s, ElemType *data)
{LinkStackPtr ptem, p = s->top->next;if(!s->top || s->count == 0)            //这里也可以调用 “判断栈是否为空” 接口return ERROR;*data = p->data;                     //出栈的元素存储到 dataptem = p->next;free(p);s->top->next = ptem;s->count--;return SUCCESS;
}

参考:
算法与数据结构(C语言版) 主编·邓玉洁

数据结构:栈(C语言实现)相关推荐

  1. 表达式求值(数据结构栈,c语言版)

    表达式求值 一.实验题目 1.案例分析 2.案例实现 3.算法步骤 4.算法描述 二.工具环境 三.实验问题 四.实验代码 一.实验题目 1.案例分析 任何一个表达式都是由操作数(operand)运算 ...

  2. 数据结构——栈(C语言)

    C语言实现栈 github代码下载 一. 栈的概念及结构 二.栈的实现 2.1 栈的存储定义 2.2 栈的初始化 2.3 入栈 2.4 出栈 2.5 获取栈顶元素 2.6 获取栈中有效元素个数 2.7 ...

  3. 数据结构-栈(C语言代码)

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

  4. c语言 栈结构存放数据类型,数据结构——栈的详解

    栈和队列是两种重要的线性结构,从数据结构的角度看,栈和队列也是线性表,其特殊性在于栈和队列的基本操作是线性表的子集.他们是操作受限的线性表,因此,可称为限定性的数据结构.但从数据类型角度看,他们是和线 ...

  5. 数据结构(C语言版) 第 三 章 栈与队列 知识梳理 + 作业习题详解

    目录 一.栈 0.栈的基本概念 1.栈的实现 2.栈与递归 3.Hanoi塔问题 二.队列 0.队列的基本概念 1.队列的实现 2.循环队列 2.1循环队列的相关条件和公式: 3.链队列 4.链队列完 ...

  6. java语言链栈_Java语言实现数据结构栈代码详解

    近来复习数据结构,自己动手实现了栈.栈是一种限制插入和删除只能在一个位置上的表.最基本的操作是进栈和出栈,因此,又被叫作"先进后出"表. 首先了解下栈的概念: 栈是限定仅在表头进行 ...

  7. 11.0、C语言数据结构——栈

    11.0.C语言数据结构--栈 栈的定义:         栈是一种重要的线性结构,可以这样讲,栈是前面讲过的线性表的一种具体形式:         官方定义:栈(stack)是一个 后进先出(Las ...

  8. c语言特殊计算器设计报告,C语言数据结构栈计算器的实现课题设计报告书

    C语言数据结构栈计算器的实现课题设计报告书 (13页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 目录1. 课程设计任务 12. 需求分析 ...

  9. 资料分享:送你一本《数据结构(C语言版)》电子书!

    要想写出可复用.可扩展.易维护.灵活性好的代码,「数据结构」这一关必须要过啊! 在数据结构与算法的众多教材中,奉为经典的当属清华大学严蔚敏老师的著作.很多学校也选择这本书作为考研指定教材. 正在学习数 ...

  10. 资料分享:送你一本《数据结构(C#语言版)》电子书!

    对于信息类专业的学生而言,数据结构与算法是一门必修的课程.只有学好这门课程,熟练掌握线性表.栈.队列.树.图等基本结构,以及在这些结构上的各种算法,才能利用计算机去解决实际问题. 如何学好这门课程呢, ...

最新文章

  1. SQL Server各种日期计算方法
  2. 《从零构建前后分离web项目》:开篇 - 纵观WEB历史演变
  3. 数据结构 - 二叉排序树
  4. C#链接数据库增删改查的例子
  5. Hive动态分区 参数配置及语法
  6. vmware虚拟机中ubuntu上网问题
  7. 《阿里巴巴中国总裁叶朋:B2B从1.0向2.0的升级》阅读整理
  8. 在ASP.NET AJAX中使用应用程序服务和本地化(5):自定义应用程序服务的服务器端实现...
  9. DOM.getBoundingClientRect()
  10. appscan如何进行web端安全性测试_如何进行WEB安全性测试?
  11. Atitit.现在的常用gui技术与gui技术趋势评价总结
  12. 防范非法用户入侵系统秘籍
  13. 云计算平台能够提供计算服务器,云计算平台提供了什么服务器
  14. PSP游戏下载地址大全
  15. stm32+TB6612驱动直流电机
  16. 无法处理文件 Snoop\Forms\BindingMap.resx,因为它位于 Internet 或受限区域中,或者文件上具有 Web 标记。要想处理这些文件,请删除 Web 标记。
  17. 读博太孤独?你不是一个人!
  18. caj文献里的参考文献拷贝到word中格式错乱问题
  19. Python 十进制到六进制
  20. 百度地图API学习---隐藏百度版权标志

热门文章

  1. mc方块云服务器地址,我的世界方块大陆服务器地址ip-城镇|开荒|纯净|生存(我的世界1.14.4版本)...
  2. 希沃展台如何使用_简单又实用的希沃视频展台
  3. c语言csae中没有break,条件语句2
  4. McAfee迈克菲安全软件的垃圾性以及win10的脆弱性
  5. 黑马程序员 一步一步往上爬 学习毕老师java视频的第03,04天
  6. 阿里云智能客服系统:包括智能导航、客服助手、智能外呼、呼叫中心、在线客服、智能培训等。经阿里内部多年实际使用演变而来,功能齐全,产品化程度高,可本地化部署。有需要的可以联系我。
  7. 输入框回车多个文本_CAD制图初学入门:回车键和空格键在CAD软件中的作用
  8. 中国信通院发布《数据中心白皮书(2022年)》
  9. 2022-2028年中国航空轮胎行业市场发展潜力及投资风险预测报告
  10. 提高英语听力最好的学习方法