数据结构11: 栈(Stack)的概念和应用及C语言实现
栈,线性表的一种特殊的存储结构。与学习过的线性表的不同之处在于栈只能从表的固定一端对数据进行插入和删除操作,另一端是封死的。

栈的“先进后出”原则
使用栈存储数据元素,对数据元素的“存”和“取”有严格的规定:数据按一定的顺序存储到栈中,当需要调取栈中某数据元素时,需要将在该数据元素之后进栈的先出栈,该数据元素才能从栈中提取出来。
如图 1 ,栈中存放了 4 个数据元素,进栈的顺序是 A 先进栈,然后 B 进,然后 C 进,最后 D 进栈;当需要调取 A 时,首先 D 出栈,然后 C 出栈,然后 B 出栈,最后 A 才能出栈被调用。
就好比只有一个门的车库(每次仅允许一辆车通过),每辆车好比一个数据元素,只有离门最近的车先开出来,里边的车才能出来;最里边的车是最先开进去的,注定要最后出来。
栈操作数据元素的方法
栈操作数据元素只有两种动作:
- 数据元素用栈的数据结构存储起来,称为“入栈”,也叫“压栈”。
- 数据元素由于某种原因需要从栈结构中提取出来,称为“出栈”,也叫“弹栈”。
栈的两种表示方式
既然栈也是线性表,那么它就同样有线性表的两种表示形式:顺序栈 和 链式栈(简称“链栈”)。
栈的“上溢”和“下溢”
栈存储结构调取栈中数据元素时,要避免出现“上溢”和“下溢”的情况:
“上溢”:在栈已经存满数据元素的情况下,如果继续向栈内存入数据,栈存储就会出错。
“下溢”:在栈内为空的状态下,如果对栈继续进行取数据的操作,就会出错。
栈的“上溢”和“下溢”,可以总结为:栈满还存会“上溢”,栈空再取会“下溢”。
对于栈的两种表示方式来说,顺序栈两种情况都有可能发生;而链栈由于“随时需要,随时申请空间”的存储结构,不会出现“上溢”的情况。
顺序栈
顺序栈的实现采用的是数组。
在顺序栈中设定一个随时指向栈顶元素的变量(一般命名为 top ),当 top 的值为 -1 时,说明数组中没有数据,即栈中没有数据元素,为“空栈”;只要数据元素进栈,top 就加 1 ;数据元素出栈, top 就减 1 。
例如,使用顺序栈的存储结构将(’a’,’b’,’c’,’d’)四个元素逐个压栈并输出栈顶元素。
实现代码:
#include <stdio.h>
//元素elem进栈
int push(char *a, int top, char elem)
{
a[++top] = elem;
return top;
}
//数据元素出栈
int pop(char *a, int top)
{
if (top == -)
{
printf("空栈");
return -;
}
printf("弹栈元素:%c\n", a[top]);
top--;
return top;
}
int main()
{
char a[];
int top = -;
top=push(a, top, 'a');
top=push(a, top, 'b');
top=push(a, top, 'c');
top=push(a, top, 'd');
top=pop(a, top);
top=pop(a, top);
top=pop(a, top);
top=pop(a, top);
top=pop(a, top);
return ;
}
输出结果:
弹栈元素:d
弹栈元素:c
弹栈元素:b
弹栈元素:a
空栈
链栈
链栈,用线性表的链式存储结构实现。
链栈一般不需要创建头结点,头结点会增加程序的复杂性,只需要创建一个头指针就可以了。
用链表表示栈时,用链表头结点的一端作为栈的栈顶端,这样做的好处是当数据元素压栈或者弹栈时,直接使用头指针就可以完成,不需要增设额外的指针。
例如,用链栈实现将(’a’,’b’,’c’,’d’)四个数据元素压栈,再依次弹栈:
#include <stdio.h>
#include <stdlib.h>
typedef struct lineStack
{
char data;
struct lineStack *next;
}lineStack;
lineStack* push(lineStack * stack,char a)
{
lineStack *line = (lineStack*)malloc(sizeof(lineStack));
line->data = a;
line->next = stack;
stack = line;
return stack;
}
lineStack *pop(lineStack *stack)
{
if (stack)
{
lineStack *p = stack;
stack = stack->next;
printf("弹栈元素:%c ", p->data);
if (stack)
{
printf("栈顶元素:%c\n", stack->data);
}
else
{
printf("栈已空\n");
}
free(p);
}
else
{
printf("栈内没有元素");
return stack;
}
return stack;
}
int main()
{
lineStack *stack = NULL;
stack = push(stack, 'a');
stack = push(stack, 'b');
stack = push(stack, 'c');
stack = push(stack, 'd');
stack = pop(stack);
stack = pop(stack);
stack = pop(stack);
stack = pop(stack);
stack = pop(stack);
return ;
}
输出结果: 弹栈元素:d 栈顶元素:c
弹栈元素:c 栈顶元素:b
弹栈元素:b 栈顶元素:a
弹栈元素:a 栈已空
栈内没有元素
总结
实际生活中使用手机时,屏幕页面的跳转使用的就是栈结构(跳转页面时,前一个页面会被存储到栈中;做回退操作时会回到上一个页面,这是进栈页面出栈的效果)。另外在求 n!时,可以通过函数的递归来实现,这个过程的底层就用到了栈结构。
除此之外,数制转换和括号匹配问题也可以用栈来解决(下节介绍)。
数据结构11: 栈(Stack)的概念和应用及C语言实现的更多相关文章
- Python与数据结构[1] -> 栈/Stack[0] -> 链表栈与数组栈的 Python 实现
栈 / Stack 目录 链表栈 数组栈 栈是一种基本的线性数据结构(先入后出FILO),在 C 语言中有链表和数组两种实现方式,下面用 Python 对这两种栈进行实现. 1 链表栈 链表栈是以单链 ...
- 数据结构之栈(Stack)
什么是栈(Stack) 栈是一种遵循特定操作顺序的线性数据结构,遵循的顺序是先进后出(FILO:First In Last Out)或者后进先出(LIFO:Last In First Out). 比如 ...
- [ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)
再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习. 首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个 ...
- Python与数据结构[1] -> 栈/Stack[1] -> 中缀表达式与后缀表达式的转换和计算
中缀表达式与后缀表达式的转换和计算 目录 中缀表达式转换为后缀表达式 后缀表达式的计算 1 中缀表达式转换为后缀表达式 中缀表达式转换为后缀表达式的实现方式为: 依次获取中缀表达式的元素, 若元素为操 ...
- 线性数据结构之栈——Stack
Linear data structures linear structures can be thought of as having two ends, whose items are order ...
- 数据结构之栈(stack)的实现
一.栈 1.定义 栈的英文为(stack),是一种数据结构 栈是一个先入后出(FILO-First In Last Out)的有序列表. 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同 ...
- C# 数据结构 栈 Stack
栈和队列是非常重要的两种数据结构,栈和队列也是线性结构,线性表.栈和队列这三种数据结构的数据元素和元素的逻辑关系也相同 差别在于:线性表的操作不受限制,栈和队列操作受限制(遵循一定的原则),因此栈和队 ...
- 【Java数据结构学习笔记之二】Java数据结构与算法之栈(Stack)实现
本篇是java数据结构与算法的第2篇,从本篇开始我们将来了解栈的设计与实现,以下是本篇的相关知识点: 栈的抽象数据类型 顺序栈的设计与实现 链式栈的设计与实现 栈的应用 栈的抽象数据类型 栈是 ...
- 数据结构之栈(stack)
1,栈的定义 栈:先进后出的数据结构,如下图所示,先进去的数据在底部,最后取出,后进去的数据在顶部,最先被取出. 栈常用操作: s=Stack() 创建栈 s.push(item) 将数据item放在 ...
随机推荐
- SQL属性第一个值不被选中,属性默认第一个值
把 Please Choose Color 属性名设置为不可选的 UPDATE `products_attributes` SET `attributes_display_only` = '1' WH ...
- nignx 重启
sudo /opt/nginx/sbin/nginx -s stop sudo /opt/nginx/sbin/nginx
- leetcode645
vector<int> findErrorNums(vector<int>& nums) { ; int S[N]; int n = nums.size(); ; i ...
- Shell编程实战 1.1 监控思路架构介绍
监控思路,架构介绍 需求:使用shell定制各种个性化的告警工具,但需要统一化管理,规范化管理. 思路:指定一个脚本包,包含主程序,子程序,配置文件,邮件引擎,输出日志等. 主程序:作为脚本的入口,是 ...
- java代码调用数据库存储过程
由于前边有写java代码调用数据库,感觉应该把java调用存储过程也写一下,所以笔者补充该篇! package testSpring; import java.sql.CallableStatemen ...
- Tiny4412 Uboot
1. Build uboot a) 安装好toolchain (arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz)并设置好 环境变量PATH,保证可以正常使用. b) 解 ...
- 每天一道算法题(14)——N个降序数组,找到最大的K个数
题目: 假定有20个有序数组,每个数组有500个数字,降序排列,数字类型32位uint数值,现在需要取出这10000个数字中最大的500个. 思路 (1).建立大顶堆,维度为数组的个数,这里为20( ...
- linux ORACLE备份还原(EXP\IMP)
一.Oracle导入导出 1.Oracle的备份是Oracle操作中常见的工作,常见的备份方案有:逻辑备份(IMP&EXP命令进行备份).物理文件备份(脱机及联机备份).利用RMAN(Reco ...
- WCF客户端调用并行最大同时只支持两个请求
做项目的时候发现 频繁调用WCF服务时 明明一次性发起了几十个请求 而在服务端记录的日志却显示出现了排队的迹象 并且都是最大并发数为2 在网上狂搜 大家给出来的解决方法都是增加web.config里面 ...
- ZROI2018普转提day2t3
传送门 分析 考试的时候sb了......我们发现可以按照先序遍历将一棵树变成一个序列,而不需要删的数的数量便是最长上升子序列的长度,但是还有一个问题就是如果在5和7之间有3个空的位置就无法填入合法的 ...