《大话数据结构》8——数据结构-栈(代码、实例、应用、概念)

一、栈是什么:

栈是限定仅在表尾进行插入和删除操作的线性表。

二、栈的基本理解

1.栈的基本理解
(1)栈顶:允许插入和删除的一端称为栈顶。
(2)栈底:另一端称为栈底。
(3)空栈:不含任何数据元素的栈称为空栈。
(4)栈又称为后进先出的线性表,简称LIFO结构。
(5)栈首先是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。
(6)栈的插入操作,叫做进栈,也称为压栈,入栈。
(7)栈的删除操作:叫做出栈,也叫弹栈。

2.进栈和出栈变化形式
实例3个元素,就有5种可能的出栈次序。
现在有3个整型数字元素1,2,3依次进栈。
(1)1,2,3进,3,2,1,出——》321
(2)1进1出。2进2出。3进3出——》123
(3)1,2,进,2,出。1.出。3进。3出——》213
(4)1进1出2进3进3出2出——》132
(5)1进2进2出3进3出1出——》231

三、栈的抽象数据类型

ADT 栈(Stack)
Data 
	同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
	InitStack(*S):初始化操作,建立一个空的栈。
	DestroyStack(*S):若栈存在,则销毁它.
	ClearStack(*S):将栈清空。
	StackEmpty(S):若栈非空,返回true,否则返回false.
	GetTop(S*e):若栈存在且非空,用e返回S的栈顶元素.
	Push(*S,e):若栈S存在,在栈顶插入新元素e.
	Pop(*S,*e):删除栈顶的元素,并用e返回其值。
	StacktLength(S):返回栈中的元素个数。
endADT

四、栈的顺序存储结构及实现

1.栈的顺序存储结构
顺序栈:栈是线性表的特例,栈的顺序存储结构也是线性表的顺序存储的简化。
(1)栈的结构定义:

//栈的结构定义
typedef int SElemType;//这里是int类型,之后可以根据实际情况设定
typedef struct
{
	SElemType data[MAXSIZE];
	int top;//用于栈顶指针 
 }SqStack; 

(2)图的示例:
在这里插入图片描述

2.栈的顺序存储结构-进栈操作
(1)图的示例:
在这里插入图片描述

(2)进栈操作Push代码:


//对于进栈操作push
//插入元素e为新栈顶元素
Status Push(SqStack *S,SElemType *e)
{
	if(S->top == MAXSIZE-1)//栈满
	{
		return ERROR;
	 } 
	 S->top++;//栈顶指针加1
	 S->data[S->top]=e;//将新插入的元素赋值给栈顶空间
	 return OK; 
 } 

3.栈的顺序存储结构-出栈操作
出栈操作代码实现:

//对于出栈操作pop 
//若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK。否则返回ERROR。 
Status Pop(SqStack *S,SElemType *e)
{
	if(S->top ==-1)//栈空 
	{
		return ERROR;
	 } 
	
	 *e=S->data[S->top];//将要删除的栈顶元素赋值给e 
	  S->top++;//栈顶指针减一 
	 return OK; 
 } 

五、两栈共享空间

1.栈的顺序存储还是很方便的。但是因为只准栈顶进出元素,所以不存在线性表的插入和删除需要移动元素的问题。
2.栈的缺陷,必须事先确定数组存储空间大小,万一不够用,就需要用编程手段来扩展数组的容量,非常麻烦。
3.对于一个栈,我们必须考虑周全设计出合适大小的数组来处理。
4.对于相同类型的栈,我们可以最大限度的利用其事先开辟的存储空间进行操作
(1)如果我们有两个相同类型的栈,我们为他们各自开辟了数组空间。
我们可以像下边处理:
在这里插入图片描述
(2)关键思路就是,它们在数组的两端,向中间靠拢。
top1和top2是栈顶的指针,只要他们不见面,两个栈就可以一直使用。
(3)栈空:top1=-1;top2=n
栈满:top1+1==top2;
(4)两栈共享空间的结构代码如下:

/两栈共享空间
typedf struct
{
	SElemType data[MAXSIZE];
	int top1;
	int top2;
 }SqDoubleStack;

(5)共享空间的push 方法:
除了要插入元素值参数外,还需要一个判断是栈1 还是栈2的栈号参数stackNumber;
插入元素的代码如下:

//两栈共享空间插入元素
//插入元素e作为新栈顶元素
 Status Push(SqStack *S,SElemType *e,int stackNumber)
{
	if(S->top1+1==S->top2)//栈满
	{
		return ERROR;
	 } 
	 if(stackNumber==1)//栈1有元素进栈
	 	 S->data[++S->top1]=e;//将新插入的元素赋值给栈顶空间
    else if(stackNumber==2) 
	     S->data[--S->top2]=e;
	 
	 return OK; 
 } 

(6)共享空间的pop方法:
参数就只是判断是栈1还是栈2的参数stackNumber。
代码如下:

//两栈共享空间删除元素
 Status Pop(SqStack *S,SElemType *e,int stackNumber)
{
	if(S->top1+1==S->top2)//栈满
	{
		return ERROR;
	 } 
	 if(stackNumber==1){
		if(S->top1==-1)//栈空 
			{
				return ERROR;
			 } 	 		
	 	*e=S->data[S->top1--];
    } 
    else if(stackNumber==2){ 
		if(S->top2==MAXSIZE)//栈空 
			{
				return ERROR;
			 } 	 		
		*e=S->data[S->top2++];    
	}     
	 return OK; 
 } 

六、栈的链式存储结构(简称链栈)及实现

1.栈的链式存储结构
对于栈链来说,是不需要头结点的。
空栈:top=NULL。
代码如下:
在这里插入图片描述

2.栈的链式存储结构-进栈操作
在这里插入图片描述
在这里插入图片描述

3.栈的链式存储结构-出栈操作
在这里插入图片描述
4.链栈时间复杂度:
都是O(1)

5.何时用链栈:
如果栈的使用过程元素变化不可预料,有时候很小,有时候很大,那么最好是链栈。
反之,如果变化在可控范围内,建议使用顺序栈会更好一点。

七、栈的作用

栈的引入简化了程序设计的问题,划分了不同的关注层次,使得思考范围变小。
数组的话,还要考虑数组的下标增删等细节问题。

八、栈的应用-递归

1.栈有一个很重要的应用,在程序设计语言中实现了递归。
2.递归例子:斐波那契数列(Fibonacci).
3.什么是递归:
我们把一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称为递归函数。
每个递归定义必须至少有一个条件,满足时递归不再进行,即不再引用自身二十返回值退出。

九、栈的应用-四则运算表达式求值

1.后缀(逆波兰)表示法定义:
一种不需要括号的后缀表达法,我们把它称为逆波兰表示。
所有的符号运算都要在运算数字后边出现。

2.后缀表达式计算结果
(1)后缀表达式:9 3 1-3*+10 2/+
(2)规则:从左到右遍历所有的表达式和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶的两个数字出栈,进行运算,运算结果进栈,一直到最终的结果。
(3)过程如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(4)最终结果
9+(3-1)*3+10/2=20.

3.中缀表达式转后缀表达式
(1)9+(3-1)*3+10/2=20.标准的四则运算我们叫中缀表达式。
(2)题目要求是转换
(3)转换规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
(4)具体过程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值