数据结构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放在 ...
随机推荐
- a(+;-;*;/)b-----demo----bai
页面: <%@ page language="java" import="java.util.*" pageEncoding="UTF-8&qu ...
- SignalR推送服务在Android的实现 SignalA
SignalA是老外写的用于实现.net端推送消息至安卓端的实现,支持版本为android 2.3或以上,由于我的版本最低是2.2,所以只有把源码下下来自己改,如果你觉得太多了可自己编译成jar引用, ...
- appium_python 怎样实现参数化自动生成用例
1.对于一种对同一个页面同一点 要用不同数据测试形成多条测试用例,如果复制的话 会让代码很冗长,并且并不好维护,现在用封装的方法把 不变的代码 和 变化的参数 分别封装,形成动态 生成测试用例 ,主要 ...
- VC用Beep整几首歌听听~~~
//生日快乐歌 #include "stdafx.h"#include <windows.h>void main(void) { unsigned FR ...
- Linux常用的编辑保存退出命令
Vi Vim进入编辑后退出 按ESC后 1.保存退出 :wq :x 最快捷的方法:直接按shift+zz,或者切换到大写模式按ZZ,就可以保存退出了,即是按2下大写的Z.区别::wq 强制性写入文件并 ...
- 部署和调优 1.9 samba 部署和优化-3
实践2 要求:共享一个目录,使用用户名和密码登录后才可以访问,要求可以读写 打开配置文件 vim /etc/samba/smb.conf 改为security = user 在最后面增加一段 [den ...
- xcode编写c/c++静态库使用系统头文件问题
c/c++编写的静态库中有引用ios系统头文件比如: #include <EGL/egl.h> 在xcode编译的时候需要设置静态库程序: Build Settings-Header Se ...
- 用C++的基本算法实现十个数排序
冒泡排序法 原理: 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成. 冒泡排序算法的运作如下 ...
- Eclipse安装Web/JavaEE插件、Eclipse编写HTML代码
1 Eclipse没有Web插件和JavaEE插件咋整 1.1 在Eclipse中菜单help选项中选择install new software选项 1.2 在work with 栏中输入 http: ...
- 在Mac OS里安装和升级Git
在此记录,给自己看,也给别人参考. 进入终端,查看当前Git版本,输入指令:git --version 输入which git回车,可以查看当前git在什么位置 经查,版本:2.10.0,版本较低,为 ...