栈和队列

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
设计思路:用栈暂存左括号
应用3 :表达式求值
设计思路:用栈暂存运算符
应用4:汉诺仪(Hanoi)塔
设计思路:用栈实现递归调用
例 表达式求值
1)问题的提出 假若我们想在计算机上设计一个小计算器(程序), 其功能为:从键盘上输入一个算术表达式(由运算符操 作数构成的字符串),在屏目上显示输出表达式的求值结 果。 显然这个小计算器程序应该对你键入的表达式进行求 值。在该程序中如何对键入的表达式求值呢?又如,高 级语言中都有表达式,例赋值语句:变量=表达式;该 语句的执行过程为:先求出表达式的值, 然后将其值赋 给赋值号左边的变量。这个表达式的值是如何求出的?
我们看到:进行运算的算符i是当前扫描过的运算 符中优先级最高者,同时,也是到当前最后被保存的运 算符,由此可见,可以利用两个栈分别保存扫描过程中 遇到的操作数和运算符。
6 算法思想:
设定两栈:操作符栈 OPTR ,操作数栈 OPND 栈初始化:设操作数栈 OPND 为空;操作符栈 OPTR 的栈底 元素为表达式起始符 ‘#’; 依次读入字符:是操作数则入OPND栈,是操作符则要判断: if 操作符 < 栈顶元素,则退栈、计算,结果压入OPND栈; 操作符 = 栈顶元素且不为‘#’,脱括号(弹出左括号); 操作符 > 栈顶元素,压入OPTR栈。
问:堆栈是什么?它与一般线性表有什么不同?
答:堆栈是一种特殊的线性表,它只能在表的一端 (即栈顶)进行插入和删除运算。 与一般线性表的区别:仅在于运算规则不同。
一般线性表 逻辑结构:一对一 存储结构:顺序表、链表 运算规则:随机存取 堆栈 逻辑结构:一对一 存储结构:顺序栈、链栈 运算规则:后进先出(LIFO)
数据结构课程的内容
受限的线 性表
第三章
3.1 栈(Stack)
1. 定义 2. 逻辑结构 3. 存储结构 4. 运算规则 5. 实现方式
栈和队列
3.2 队列(Queue)
1. 定义 2. 逻辑结构 3. 存储结构 4. 运算规则 5. 实现方式
3.1 栈
1.定义 2.逻辑结构 3.存储结构 4.运算规则 5.实现方式
s
top
99 . . . 3 2 1 0
a3 a2 a1 a0
(栈顶)
(栈底)
链栈示意图
s
top
a4 a3
a2 a1
^
(栈顶)
(栈底)
表和栈的操作区别——对线性表s= (a0,a1,
顺序表V[n]
高地址
…. ,
an-1)
顺序栈S
表尾
高地址
an-1 …… v[i] ai ……
低地址
an an-1 …… ai …… a1 a0
an-1 ai ai-1
e an-1
ai ai-1
a0
STACK_INIT_SIZE
a0
STACK_INIT_SIZE
S.stacksize
e 进栈前
e 进栈后

进栈操作算法 int StackPush( SeqStack *s , DataType x )
{
if ( s -> Top >= MAXStackSize )return 0;
… …
a1 ^ a1 ^
h
h -> Next = p -> Next;
问:为什么要设计堆栈?它有什么独特用途? 答:
1.
调用函数或子程序非它莫属;
2.
3.Βιβλιοθήκη 递归运算的有力工具;用于保护现场和恢复现场;
4.
简化了程序设计的问题。
应用1:数制转换(十转N)
设计思路:用栈暂存低位值
应用2:括号匹配的检验
else
{ s -> Stack[s -> Top] = x; s ->top ++ return } } 1;
出栈操作算法
功能:栈顶元素退栈 int StackPop(SeqStack *S,DataType *d) { if(s->top <= 0) return 0; else { s->top - *d = s->stack(S->top) return 1; } }
> >
>
> >
>
< >
>
< >
>
< <
<
> >
>
> >
> > =
<
> <
<
> <
<
> <
<
> <
<
<
=
>
5
算符优先算法 我们再来分析一下表达式5+4 (1+2)- 6 计算过程:
5+4 (1+2)- 6
后面也许有优先级 更大的算符
从左向右扫描表达式:
遇操作数——保存;
遇运算符号j——与前面的刚扫描过的运算符i比较 若i<j 则保存j,(因此已保存的运算符的优先关系为 1<2<3<4) 若i>j 则说明i是已扫描的运算符中优先级最高者,可进行运算; 若i = j 则i为(,j 为 ),说明括号内的式子已计算完,需要消去括号;
top
D C B A D top C B A D C B A top D C B A
top
低地址L
核心语句: Pop ( ); Pop ( ); Printf( Pop () );
顺序栈中的POP函数 status Pop( ) { if(top=L) { 下溢 } else { y=v[--top]; return(y); } }
1)链式栈可用线性链表 表示; 2)链式栈的栈顶指针就 是链表的头指针; 3)进栈操作就是在该线 性链表第一个元素结点 之前插入一个新结点, 出栈操作就是删除链表 的第一个元素结点。
S
(简称链栈)
Data next
an-1
an-2
栈顶
a0
链式栈图示
栈底
链栈的结构可定义为:
typedef struct SNode
堆栈的顺序存储结构 (简称顺序栈)
S.top n n-1 i-1 i-2 1 0
an-1
ai ai-1
a1 a0
STACK_INIT_SIZE
当栈用顺序结构存储时, 栈的基本操作如建空栈、 进栈、出栈等操作如何实现?
S.base
S.stacksize

初始化算法 void StackInitiate (SeqStack *s ) { s -> Top = 0; }

进栈操作算法
功能:元素e进栈; 进栈操作主要步骤:
1)S是否已满,若栈满,重新分配存储空间;
2)将元素e写入栈顶; 3)修改栈顶指针,使栈顶指针指向栈顶元素的下(后面)一个 位置;
进栈操作图示
S.top S.top n n-1 i-1 i-2 S.base 0 n+1 n n-1 i-1 i-2 S.base S.stacksize 0
{ DataType } LSNode; Data; struct SNode *Next;
进栈操作算法
h h p ①

an
an x

an-1
an-1
… …
a1 ^ a1 ^
p -> Next = h -> Next; ②
h -> Next = p;
退栈操作算法
h an p an an-1 an-1
例2:一个栈的输入序列是12345,若在入栈的过 程中允许出栈,则栈的输出序列43512可能实现 吗?12345的输出呢? 答: 43512不可能实现,主要是其中的12顺序不能实现;
12345的输出可以实现,只需压入一个立即弹出一个 即可。
例3:如果一个栈的输入序列为123456,能否得 到435612和135426的出栈序列?
1=2:1的优先级等于2
1>2:1的优先级高于2
由四则运算法则,可得到如下的算符优先关系
表:
注:θ1 θ2 是相邻算 符, θ1在左, θ2在右
算符间的优先关系表
θ1 θ2
+ >
>
* <
/ <
( <
) >
# >
注:θ1 代表栈顶运算符,θ2代表当前扫描读到的 运算符
+ * / (
) #
出栈操作图示
S.top
n n-1 i-1 i-2
an-1
ai ai-1 a0
STACK_INIT_SIZE
S.top
n-2 i-1 i-2
an-2
e
ai ai-1
a0
STACK_INIT_SIZE
S.base
0
S.base S.stacksize
0
S.stacksize
出栈操作前
出栈操作后
☞ 堆栈的链式存储结构
栈顶top
a1 a0
表头
低地址
栈底base
写入:v[i]= ai 读出: x= v[i]
压入:PUSH (an+1) 弹出: POP (x)
前提:一定要预设栈顶指针top!
入栈操作——例如用堆栈存放(A,B,C,D) (注意要遵循“后进先出” 原则)
高地址M
低地址L
top A
B top A
top C B A

表达式求值 ( 这是栈应用的典型例子 ) 这里,表达式求值的算法是 “算符优先法”。 例如:3*(7 – 2 ) (1)要正确求值,首先了解算术四则运算的规则: a. 从左算到右 b. 先乘除,后加减
c. 先括号内,后括号外
base=NULL;
base=top; top-base=stacksize;

堆栈的顺序存储结构
(简称顺序栈)
利用一维数组定义顺序栈,用指示器top指示当前 栈顶位置 #define MAXStackSize <最大元素数> typedef struct { DataType Stack[ MAXStackSize]; int Top; } SeqStack;
top D C B A
top
核心语句: top=L; Push (A); Push (B); Push (C); Push (D);
顺序栈中的PUSH函数 status Push(ElemType x) { if(top>M){上溢} else v[top++]=x; }
高地址M
出栈操作——例如从栈中取出‘B’ (注意要遵循“后进先出” 原则)
答: 435612中到了12顺序不能实现; 135426可以实现。
例4:设依次进入一个栈的元素序列为c,a,b, d,则可得到出栈的元素序列是: A)a,b,c,d C)b,c,d,a B)c,d,a,b D)a,c,d,b
答: A、D可以( B、C不行)。
讨论:有无通用的判别原则? 有。在可能的输出序列中,不存在这样的输入序列 i,j,k,能同时满足 i<j<k 和 Pj<Pk<Pi
例1:一个栈的输入序列为123,若在入栈的过程中 允许出栈,则可能得到的出栈序列是什么? 答: 可以通过穷举所有可能性来求解:
① 1入1出, 2入2出,3入3出, ② 1入1出, 2、3入3、2出, ③ 1、2入,2出, 3入3出, ④ 1、2入,2、1出,3入3出, ⑤ 1、2、3入,3、2、1出, 合计有5种可能性。 即123; 即132; 即231; 即213; 即321;
补充1:
若入栈动作使地址向高端增长,称为“向上生成”的栈;
若入栈动作使地址向低端增长,称为“向下生成”的栈;
对于向上生成的栈 入栈口诀:堆栈指针top先压后加(v[top++]=x);
出栈口诀:堆栈指针top先减后弹(y=v[--top]) 。
补充2:栈不存在的条件:
栈为空 的条件 : 栈满的条件 :
2) 表达式的构成 操作数+运算符+界符(如括号)
3) 表达式的求值:
例 5+6 (1+2)- 4 按照四则运算法则,上述表达式的计算过程为: 5+6 (1+2)- 4=5+6 3- 4 = 5+18-4= 23-4=19
3 2 1 4
表达式中运算符的运算顺序为:
1
+
2

3
+
4
-
4)算符优先关系表(是提供给计算机用的表) 表达式中任何相邻运算符1、2的优先关系有: 1<2:1的优先级低于2
限定只能在表的一端进行插入和删除运算的 线性表(只能在栈顶操作) 与同线性表相同,仍为一对一关系。 用顺序栈或链栈存储均可,但以顺序栈更常见 只能在栈顶运算,且访问结点时依照后进先出 (LIFO)或先进后出(FILO)的原则。
关键是编写入栈和出栈函数,具体实现依顺 序栈或链栈的不同而不同。
基本操作有入栈、出栈、读栈顶元素值、建 栈、或判断栈满、栈空等。
―进” =压入=PUSH(x) ―出” =弹出=POP ( y )
栈 是仅在表尾进行插入、删除操作的线性表。 表尾(即 an 端)称为栈顶 top ; 表头(即 a0 端)称为栈底base 例如: 栈 s= (a0 , a1 , a2 a0 称为栈底元素
, ……….,an-1)
an-1 称为栈顶元素
插入元素到栈顶(即表尾)的操作,称为入栈。
从栈顶(即表尾)删除最后一个元素的操作,称为出栈。
标识栈顶当前位置的变量称为栈顶指示器(栈顶指针)。 强调:插入和删除都只能在表的一端(栈顶)进行! (a0, a0, ... , ai -1, ai , ai+1, …, an-1 )
删除
插入
顺序栈示意图
data
相关文档
最新文档