数据结构专项精讲课程讲义-第三部分-第3章 栈
合集下载
数据结构-Java语言描述 第三章 栈和队列
System.exit(1);
}
栈顶指针top的初始值决
top=-1;
定了后续其他方法的实现
stackArray=(T[])new Object[n];
}
【算法3-2】入栈
public void push(T obj)
{
if(top==stackArray.length-1){
T []p=(T[])new Object [top*2];
(b)元素a2入栈
an … … a2 a1
(c)元素an入栈
an-1 … a2 a1
(d)元素an出栈
a2 a1
(e)元素a3出栈
a1
(f)元素a2出栈
【例3-1】一个栈的输入序列是1、2、3、4、5,若在 入栈的过程中允许出栈,则栈的输出序列4、3、5、1、 2可能实现吗?1、2、3、4、5的输出呢?
型 正序遍历:依次访问栈中每个元素并输出
3.1.2 顺序栈
顺序栈泛型类的定义如下:
public class sequenceStack<T> {
顺序栈中一维数组 的初始长度
final int MaxSize=10;
private T[] stackArray; 存储元素的数组对象
private int top;
public void nextOrder() {
for(int i=top;i>=0;i--) System.out.println(stackArray[i]);
}
【算法3-8】清空栈操作
public void clear() {
top=-1; }
3.1.3 链栈
栈的链接存储结构称为链栈。结点类的定义,同 第二章Node类。
大学数据结构课件--第3章 栈和队列
top top 栈空 F E D C B A
栈满 top-base=stacksize
top
F
E
D C B
top top top top top top base
入栈PUSH(s,x):s[top++]=x; top 出栈 POP(s,x):x=s[--top]; top
base
4
A
3.1 栈
例1:一个栈的输入序列为1,2,3,若在入栈的过程中 允许出栈,则可能得到的出栈序列是什么? 答: 可以通过穷举所有可能性来求解:
3.2 栈的应用举例
二、表达式求值
“算符优先法”
一个表达式由操作数、运算符和界限符组成。 # 例如:3*(7-2*3) (1)要正确求值,首先了解算术四则运算的规则 a.从左算到右 b.先乘除后加减 c.先括号内,后括号外 所以,3*(7-2*3)=3*(7-6)=3*1=3
9
3.2 栈的应用举例
InitStack(S); while (!QueueEmpty(Q))
{DeQueue(Q,d);push(S,d);}
while (!StackEmpty(S)) {pop(S,d);EnQueue(Q,d);} }
第3章 栈和队列
教学要求:
1、掌握栈和队列的定义、特性,并能正确应用它们解决实 际问题;
用一组地址连续的存储单元依次存放从队头到队尾的元素, 设指针front和rear分别指示队头元素和队尾元素的位置。
Q.rear 5 4 Q.rear 3 2 3 2 5 4 Q.rear 3 3 5 4 5 4
F E D C
C B A
Q.front
2 1 0
C B
Q.front 2 1 0
栈满 top-base=stacksize
top
F
E
D C B
top top top top top top base
入栈PUSH(s,x):s[top++]=x; top 出栈 POP(s,x):x=s[--top]; top
base
4
A
3.1 栈
例1:一个栈的输入序列为1,2,3,若在入栈的过程中 允许出栈,则可能得到的出栈序列是什么? 答: 可以通过穷举所有可能性来求解:
3.2 栈的应用举例
二、表达式求值
“算符优先法”
一个表达式由操作数、运算符和界限符组成。 # 例如:3*(7-2*3) (1)要正确求值,首先了解算术四则运算的规则 a.从左算到右 b.先乘除后加减 c.先括号内,后括号外 所以,3*(7-2*3)=3*(7-6)=3*1=3
9
3.2 栈的应用举例
InitStack(S); while (!QueueEmpty(Q))
{DeQueue(Q,d);push(S,d);}
while (!StackEmpty(S)) {pop(S,d);EnQueue(Q,d);} }
第3章 栈和队列
教学要求:
1、掌握栈和队列的定义、特性,并能正确应用它们解决实 际问题;
用一组地址连续的存储单元依次存放从队头到队尾的元素, 设指针front和rear分别指示队头元素和队尾元素的位置。
Q.rear 5 4 Q.rear 3 2 3 2 5 4 Q.rear 3 3 5 4 5 4
F E D C
C B A
Q.front
2 1 0
C B
Q.front 2 1 0
数据结构第3章 栈
4. 判栈空:SEmpty(s) 判栈空: () 初始条件: 已存在 已存在。 初始条件:栈s已存在。 操作结果:若栈空则返回为 ,否则返回为0。 操作结果:若栈空则返回为1,否则返回为 。 5. 判栈满:SFull(s) 判栈满: () 初始条件: 已存在 已存在。 初始条件:栈s已存在。 操作结果:若栈满则返回为 ,否则返回为0。 操作结果:若栈满则返回为1,否则返回为 。 6. 显示栈元素:ShowStack (s) 显示栈元素: 初始条件: 已存在 且非空。 初始条件:栈s已存在 ,且非空。 操作结果:显示栈中所有元素。 操作结果:显示栈中所有元素。
s->top= –1; ; return s; ; }
// 置栈空
(2) 进栈 )
进栈运算是在栈顶位置插入一个新元素x,其算法步骤为: 进栈运算是在栈顶位置插入一个新元素 ,其算法步骤为: (a) 判栈是否为满,若栈满,作溢出处理,并返回 ; 判栈是否为满,若栈满,作溢出处理,并返回0; (b) 若栈未满,栈顶指针 加1; 若栈未满,栈顶指针top加 ; (c) 将新元素 送入栈顶,并返回 。 将新元素x送入栈顶 并返回1。 送入栈顶,
int Push (SeqStack *s, datatype x) , { if (s->top= =MAXLEN–1) return 0; ) ;
// 栈满不能入栈,且返回 0 栈满不能入栈,
else { s->top++; ; s->data[s->top]=x; // 栈不满,则压入元素 ; 栈不满,则压入元素x return 1;} // 进栈成功,返回 进栈成功,返回1 ; }
}
(5)判栈空 )
int SEmpty(SeqStack *s) ( ) { if (s->top= = –1) return 1; ) ; else return 0; ; }
2014考研计算机数据结构专项精讲课程讲义-第三部分-第三章 栈
top1--;return(SPACE[top1+1]); //返回出栈元素。 case2:if(top2==N){printf(“栈空\n”);exit(0);}
top2++;return(SPACE[top2-1]); //返回出栈元素。 (2)栈满条件:top2-top1=1 栈空条件:top1=-1 并且 top2=N //top1=-1 为左栈空,top2=N 为右栈空
2. 当两个栈共享一存储区时,栈利用一维数组 stack(1,n)表示,两栈顶指针为 top[1]与 top[2], 则当栈 1 空时,top[1]为_______,栈 2 空时 ,top[2]为_______,栈满时为_______。 0 n+1 top[1]+1=top[2]
3.表达式 23+((12*3-2)/4+34*5/7)+108/9 的后缀表达式是_______。 23.12.3*2-4/34.5*7/++108.9/+(注:表达式中的点(.)表示将数隔开,如 23.12.3 是三个数)
三、填空 1.设有一个空栈,栈顶指针为 1000H(十六进制),现有输入序列为 1,2,3,4,5,经过 PUSH,PUSH,POP,PUSH,POP,PUSH,PUSH 之 后 , 输 出 序 列 是 _______ , 而 栈 顶 指 针 值 是 _______H。设栈为顺序栈,每个元素占 4 个字节。 23 100CH
3 AB
F#
#-
B*C/D-E↑F# PUSH(OPND,B)
4 AB
# - * *C/D-E↑F# PUSH(OPTR,’*’)
5 ABC
# - * C/D-E↑F#
top2++;return(SPACE[top2-1]); //返回出栈元素。 (2)栈满条件:top2-top1=1 栈空条件:top1=-1 并且 top2=N //top1=-1 为左栈空,top2=N 为右栈空
2. 当两个栈共享一存储区时,栈利用一维数组 stack(1,n)表示,两栈顶指针为 top[1]与 top[2], 则当栈 1 空时,top[1]为_______,栈 2 空时 ,top[2]为_______,栈满时为_______。 0 n+1 top[1]+1=top[2]
3.表达式 23+((12*3-2)/4+34*5/7)+108/9 的后缀表达式是_______。 23.12.3*2-4/34.5*7/++108.9/+(注:表达式中的点(.)表示将数隔开,如 23.12.3 是三个数)
三、填空 1.设有一个空栈,栈顶指针为 1000H(十六进制),现有输入序列为 1,2,3,4,5,经过 PUSH,PUSH,POP,PUSH,POP,PUSH,PUSH 之 后 , 输 出 序 列 是 _______ , 而 栈 顶 指 针 值 是 _______H。设栈为顺序栈,每个元素占 4 个字节。 23 100CH
3 AB
F#
#-
B*C/D-E↑F# PUSH(OPND,B)
4 AB
# - * *C/D-E↑F# PUSH(OPTR,’*’)
5 ABC
# - * C/D-E↑F#
数据结构第3章栈
Elemtype pop(sqstack *s) { /*若栈s不为空,则删除栈顶元素*/ Elemtype x; if(s->top<0) return NULL; /*栈空*/ x=s->stack[s->top]; s->top--; return x; }
13
(4)取栈顶元素操作
Elemtype gettop(sqstack *s) { /*若栈s不为空,则返回栈顶元素*/ If(s->top<0) return NULL; /*栈空*/ return (s->stack[s->top]); }
。
29
算术表达式求值
在计算机中,任何一个表达式都是由: 操作数(operand)、运算符(operator)和 界限符(delimiter)组成的。 其中操作数可以是常数,也可以是变量或常量的 标识符;运算符可以是算术运算体符、关系运算符和 逻辑符;界限符为左右括号和标识表达式结束的结束 符。
30
6
存储结构
栈是一种特殊的线性表,有两种存储方式: 顺序存储结构存储
链式存储结构存储。
7
顺序栈的数组表示
与第二章讨论的一般的顺序存储结构的线性表 一样,利用一组地址连续的存储单元依次存放自 栈底到栈顶的数据元素,这种形式的栈也称为顺 序栈。 使用一维数组来作为栈的顺序存储空间。 设指针top指向栈顶元素的当前位置,以数组 小下标的一端作为栈底。 top=0时为空栈,元素进栈时指针top不断地 加1,当top等于数组的最大下标值时则栈满。
5)假如读出的运算符的优先级不大于运算符栈栈顶运算符
的优先级,则从操作数栈连续退出两个操作数,从运算符栈中 退出一个运算符,然后作相应的运算,并将运算结果压入操作 数栈。此时读出的运算符下次重新考虑(即不读入下一个符号 )。
13
(4)取栈顶元素操作
Elemtype gettop(sqstack *s) { /*若栈s不为空,则返回栈顶元素*/ If(s->top<0) return NULL; /*栈空*/ return (s->stack[s->top]); }
。
29
算术表达式求值
在计算机中,任何一个表达式都是由: 操作数(operand)、运算符(operator)和 界限符(delimiter)组成的。 其中操作数可以是常数,也可以是变量或常量的 标识符;运算符可以是算术运算体符、关系运算符和 逻辑符;界限符为左右括号和标识表达式结束的结束 符。
30
6
存储结构
栈是一种特殊的线性表,有两种存储方式: 顺序存储结构存储
链式存储结构存储。
7
顺序栈的数组表示
与第二章讨论的一般的顺序存储结构的线性表 一样,利用一组地址连续的存储单元依次存放自 栈底到栈顶的数据元素,这种形式的栈也称为顺 序栈。 使用一维数组来作为栈的顺序存储空间。 设指针top指向栈顶元素的当前位置,以数组 小下标的一端作为栈底。 top=0时为空栈,元素进栈时指针top不断地 加1,当top等于数组的最大下标值时则栈满。
5)假如读出的运算符的优先级不大于运算符栈栈顶运算符
的优先级,则从操作数栈连续退出两个操作数,从运算符栈中 退出一个运算符,然后作相应的运算,并将运算结果压入操作 数栈。此时读出的运算符下次重新考虑(即不读入下一个符号 )。
数据结构3_栈
其中,stacksize指示当前栈可使 用的最大容量。 base是栈底指针,在顺序栈中, 它始终指向栈底的位置, 若其值为NULL,表明栈结 构不存在。 Top是栈顶指针,其初值指向栈底, 即top=base作为栈空的标 记,元素入栈,则top指针 递增1,反之,元素出栈, top指针递减1
栈顶指针和栈中元素之间的关系图见后
分析可能出现的不匹配的情况: 1. 到来的右括弧非是所“期待”的; 2. 到来的是“不速之客”; 3. 直到结束,也没有到来所“期待”的
4)栈的应用举例
2)括号匹配的检验
status matching(string& exp) { // 检验表达式中所含括弧是否正确嵌套,若是,则返回 // OK,否则返回ERROR int state = 1; while (i<=length(exp) && state) { swith of exp[i] { case 左括弧: { Push(S,exp[i]); i++; break; } case ")": { if (NOT StackEmpty(S) && GetTop(S) = "(") { Pop(S,e); i++; } else { state = 0 } break; } …… } } if ( state && StackEmpty(S) ) return OK else return ERROR; }
栈和队列
栈和队列都属于线性表,但它们是线性表中的两种特殊情 况,并且也都是最简单的情况。故又称限定性数据结构
由于它们在计算机科学中具有极其重要的作用, 由于它们在计算机科学中具有极其重要的作用,所 以需要专门进行介绍。 以需要专门进行介绍。
数据结构(C语言版)第3章栈
栈和队列是两种特殊的线性表,是操作 受限的线性表,称限定性数据结构。
栈 栈的应用 队列 队列的应用
3.1 栈(stack) stack)
一、 栈的定义:限定仅在表尾进行插入或删除操 栈的定义:限定仅在表尾进行插入或删除操 作的线性表,表尾—栈顶,表头—栈底,不含元 作的线性表,表尾—栈顶,表头—栈底,不含元 素的空表称空栈
3.2 栈的应用举例
由于栈结构具有的后进先出的固有特性, 致使栈成为程序设计中常用的工具。以下是 几个栈应用的例子。 一、栈的应用举例-----数制转换 一、栈的应用举例-----数制转换 十进制N 十进制N和其它进制数的转换是计算机 实现计算的基本问题,其解决方法很多, 实现计算的基本问题,其解决方法很多,其中 一个简单算法基于下列原理: 一个简单算法基于下列原理: N=(n div d)*d+n mod d ( 其中:div为整除运算,mod为求余运算) 其中:div为整除运算,mod为求余运算) 例如 (1348)10=(2504)8,其运算过程 如下:
答:
例4:计算机系2001年考研题(程序设计基础) 计算机系2001年考研题 程序设计基础) 年考研题( 设依次进入一个栈的元素序列为c 设依次进入一个栈的元素序列为c,a,b,d, 则可得到出栈的元素序列是: 则可得到出栈的元素序列是:
A)a A)a,b,c,d b C)b C)b,c,d,a c,d,b
链栈的进栈算法 LinkStack *PUSHLSTACK(LinkStack *top, ElemType x) { LinkStack *p; p=malloc(sizeof(LinkStack)); = p->data=x; p->next=top; = = return p; }
第3章 数据结构—栈
2.栈操作的示意图 . top指针是在栈上进行插入或删除操作的依据,top=-1表示栈空, 指针是在栈上进行插入或删除操作的依据, 表示栈空 表示栈空, 指针是在栈上进行插入或删除操作的依据 top=MAXSIZE-1表示栈满,这是在顺序栈的基本操作中必须考虑到的两 表示栈满, 表示栈满 个重要条件。 个重要条件。
3-2-1 顺序栈
3-2-1 顺序栈 用顺序存储结构实现的栈称为顺序栈, 用顺序存储结构实现的栈称为顺序栈,即利用一组地址连续的存储单元依次 存放自栈底到栈顶的数据元素,同时由于栈的操作的特殊性, 存放自栈底到栈顶的数据元素,同时由于栈的操作的特殊性,还必须附设一 个位置指针top(栈顶指针 来动态地指示栈顶元素在顺序栈中的位置。通常以 栈顶指针)来动态地指示栈顶元素在顺序栈中的位置 个位置指针 栈顶指针 来动态地指示栈顶元素在顺序栈中的位置。 top=-1表示空栈。顺序栈的存储结构可以用 语言中的一维数组来表示。 表示空栈。 语言中的一维数组来表示。 表示空栈 顺序栈的存储结构可以用C语言中的一维数组来表示 注意:在以下程序中, 指向当前栈顶元素, 注意:在以下程序中,top指向当前栈顶元素,即指向当前栈顶元素的存储位 指向当前栈顶元素 置。 1.顺序栈的实现 . 顺序栈可以用C语言描述如下 语言描述如下。 顺序栈可以用 语言描述如下。 #define MAXSIZE 10 int char stack[MAXSIZE]; int top; 也可以用结构体数组实现顺序栈。 也可以用结构体数组实现顺序栈。 #define MAXSIZE 10 #define DataType int typedef struct { DataType stack[MAXSIZE]; int top; }SeqStack; SeqStack *S; ;
《数据结构课件、代码》第3章栈和队列
在Python中,可以使用列表实现栈, 通过使用`append()`方法将元素压入 栈顶,使用`pop()`方法弹出栈顶元素。
栈也可以通过链表实现,其中链表的 头部作为栈顶。
在Java中,可以使用`java.util.Stack` 类实现栈,该类继承自`Vector`类, 提供了丰富的操作方法来管理栈。
总结词
应用场景不同
详细描述
栈常用于实现函数调用、括号匹配等后进 先出的操作。而队列常用于实现任务调度 、缓冲区处理等先进先出的操作。
THANKS
感谢观看
04
栈和队列的算法复杂度分 析
算法时间复杂度分析
栈的常见操作包括push、pop和peek等,其中push和pop操 作的时间复杂度为O(1),而peek操作的时间复杂度也为O(1)。
队列的常见操作包括enqueue、dequeue和peek等,其中 enqueue操作的时间复杂度为O(1),dequeue操作的时间复杂 度为O(n),n为队列中元素的个数,peek操作的时间复杂度为 O(1)。
算法空间复杂度分析
栈的空间复杂度主要取决于其存储方 式,如果使用数组实现,则空间复杂 度为O(n),n为栈中元素的个数;如 果使用链表实现,则空间复杂度为 O(1)。
队列的空间复杂度也取决于其存储方式, 如果使用数组实现,则空间复杂度为 O(n),n为队列中元素的个数;如果使 用链表实现,则空间复杂度为O(1)。
《数据结构课件、代 码》第3章栈和队列
目录
• 栈(Stack) • 队列(Queue) • 栈与队列的应用 • 栈和队列的算法复杂度分析 • 数据结构中的栈和队列与其他数据结构的比较
01
栈(Stack)
栈的定义
01
栈也可以通过链表实现,其中链表的 头部作为栈顶。
在Java中,可以使用`java.util.Stack` 类实现栈,该类继承自`Vector`类, 提供了丰富的操作方法来管理栈。
总结词
应用场景不同
详细描述
栈常用于实现函数调用、括号匹配等后进 先出的操作。而队列常用于实现任务调度 、缓冲区处理等先进先出的操作。
THANKS
感谢观看
04
栈和队列的算法复杂度分 析
算法时间复杂度分析
栈的常见操作包括push、pop和peek等,其中push和pop操 作的时间复杂度为O(1),而peek操作的时间复杂度也为O(1)。
队列的常见操作包括enqueue、dequeue和peek等,其中 enqueue操作的时间复杂度为O(1),dequeue操作的时间复杂 度为O(n),n为队列中元素的个数,peek操作的时间复杂度为 O(1)。
算法空间复杂度分析
栈的空间复杂度主要取决于其存储方 式,如果使用数组实现,则空间复杂 度为O(n),n为栈中元素的个数;如 果使用链表实现,则空间复杂度为 O(1)。
队列的空间复杂度也取决于其存储方式, 如果使用数组实现,则空间复杂度为 O(n),n为队列中元素的个数;如果使 用链表实现,则空间复杂度为O(1)。
《数据结构课件、代 码》第3章栈和队列
目录
• 栈(Stack) • 队列(Queue) • 栈与队列的应用 • 栈和队列的算法复杂度分析 • 数据结构中的栈和队列与其他数据结构的比较
01
栈(Stack)
栈的定义
01
数据结构 chapter 3 - Stack 栈
A 栈满
元素P出栈后
【顺序栈初始化算法】 void StackInitiate (SeqStack *S) { S->top=0; } //时间复杂度: O(1) 【顺序栈判栈非空否算法】 int StackNotEmpty (SeqStack S) { if (S.top<=0) return 0; else return 1; } //时间复杂度: O(1)
例如: {[(( ))]} (()))abc{[]} (()()abc{[]}
))]} ))]} ))]}
左括 号栈
))]}
))]}
)]}
]}
( ( [ {
}
先扫描的左括号最后完成配对,最后扫描的左括号最先完成配对
思想: 1、循环:自左向右扫描表达式串(基本框架),
1.1 当遇到左括号,左括号进栈; 1.2 当遇到右括号,比较当前栈顶(左)括号是否 与之配对,
空,则返回1,否则返回0。 StackPush(S,x) //在栈S的栈顶插入一个值为x 的元素,插入成功返回1,失败返回0。 StackPop(S,x) //删除栈S的栈顶元素,被删除 的栈顶元素通过x带回,删除成功返回 1,失败返回0。 StackTop(S,x) //取栈S中栈顶元素,并由x带回。
1.2.1 若配对,则出栈并继续扫描下一字符; 1.2.2 若不配对,则左右括号出现次序不正确; 1.2.3 若栈空,则右括号多于左括号;
2、扫描结束后,
若栈非空,则左括号多于右括号; 若栈为空,则左右括号配对。
int ExpIsCorrect (char exp[ ], int n) {SeqStack myStack; char c; int i; StackInitiate (&myStack); for (i=0; i<n; i++) { if (exp[i]=='(' || exp[i]=='[' || exp[i]=='{') StackPush (&myStack, exp[i] ); else if (exp[i]==')' && StackNotEmpty(myStack) && StackTop (myStack, &c) && c=='(' ) StackPop (&myStack, &c); else if (exp[i]==')' && StackNotEmpty(myStack) && StackTop (myStack, &c) && c!='(' ) { printf ("圆括号次序不正确\n"); return 0; } else if (exp[i]==']' && StackNotEmpty(myStack) && StackTop (myStack, &c) && c=='[' ) StackPop (&myStack, &c);
元素P出栈后
【顺序栈初始化算法】 void StackInitiate (SeqStack *S) { S->top=0; } //时间复杂度: O(1) 【顺序栈判栈非空否算法】 int StackNotEmpty (SeqStack S) { if (S.top<=0) return 0; else return 1; } //时间复杂度: O(1)
例如: {[(( ))]} (()))abc{[]} (()()abc{[]}
))]} ))]} ))]}
左括 号栈
))]}
))]}
)]}
]}
( ( [ {
}
先扫描的左括号最后完成配对,最后扫描的左括号最先完成配对
思想: 1、循环:自左向右扫描表达式串(基本框架),
1.1 当遇到左括号,左括号进栈; 1.2 当遇到右括号,比较当前栈顶(左)括号是否 与之配对,
空,则返回1,否则返回0。 StackPush(S,x) //在栈S的栈顶插入一个值为x 的元素,插入成功返回1,失败返回0。 StackPop(S,x) //删除栈S的栈顶元素,被删除 的栈顶元素通过x带回,删除成功返回 1,失败返回0。 StackTop(S,x) //取栈S中栈顶元素,并由x带回。
1.2.1 若配对,则出栈并继续扫描下一字符; 1.2.2 若不配对,则左右括号出现次序不正确; 1.2.3 若栈空,则右括号多于左括号;
2、扫描结束后,
若栈非空,则左括号多于右括号; 若栈为空,则左右括号配对。
int ExpIsCorrect (char exp[ ], int n) {SeqStack myStack; char c; int i; StackInitiate (&myStack); for (i=0; i<n; i++) { if (exp[i]=='(' || exp[i]=='[' || exp[i]=='{') StackPush (&myStack, exp[i] ); else if (exp[i]==')' && StackNotEmpty(myStack) && StackTop (myStack, &c) && c=='(' ) StackPop (&myStack, &c); else if (exp[i]==')' && StackNotEmpty(myStack) && StackTop (myStack, &c) && c!='(' ) { printf ("圆括号次序不正确\n"); return 0; } else if (exp[i]==']' && StackNotEmpty(myStack) && StackTop (myStack, &c) && c=='[' ) StackPop (&myStack, &c);
数据结构课件第3篇章栈和队列
循环队列实现原理
01
循环队列定义
将一维数组看作首尾相接的环形结构,通过两个指针(队头和队尾指针)
在数组中循环移动来实现队列的操作。当队尾指针到达数组末端时,再
回到数组起始位置,形成循环。
02
判空与判满条件
在循环队列中,设置一个标志位来区分队列为空还是已满。当队头指针
等于队尾指针时,认为队列为空;当队尾指针加1等于队头指针时,认
栈在函数调用中应用
函数调用栈
在程序执行过程中,每当发生函数调用时,系统会将当前函数的执行上下文压入一个专门的栈中,称为函数调用 栈。该栈用于保存函数的局部变量、返回地址等信息。当函数执行完毕后,系统会从函数调用栈中弹出相应的执 行上下文,并恢复上一个函数的执行状态。
递归调用实现
递归调用是一种特殊的函数调用方式,它通过在函数调用栈中反复压入和弹出同一函数的执行上下文来实现对问 题的分解和求解。在递归调用过程中,系统会根据递归深度动态地分配和管理函数调用栈的空间资源。
栈和队列的应用
栈和队列在计算机科学中有着广泛的应用,如函数调用栈、表达式求 值、缓冲区管理等。
常见误区澄清说明
误区一
栈和队列的混淆。虽然栈和队列都是线性数据结构,但它们的操作方式和应用场景是不同的。栈是后进先出,而队列 是先进先出。
误区二
认为栈和队列只能通过数组实现。实际上,栈和队列可以通过多种数据结构实现,如链表、循环数组等。具体实现方 式取决于应用场景和需求。
后缀表达式求值
利用栈可以方便地实现后缀表达式的求值。具体步骤 为:从左到右扫描表达式,遇到数字则入栈,遇到运 算符则从栈中弹出所需的操作数进行计算,并将结果 入栈,最终栈中剩下的元素即为表达式的结果。
中缀表达式转换为后缀表达式
数据结构讲义3
e = s->data;
p = s; s = s->next; free(p); return OK;
S p
data next A p S
data next A data next S
∧
∧
∧
} // Pop;
9
数据结构
3.2 栈的应用
3.2.1 数制转换
公式: N=(n div d)*d + n mod d (div为整除运算,mod为求余运算)
11
数据结构
3.2 栈的应用--求从起点到终点的简单路径
起点
0 1 2 3 4 5 6 7 8 9 Y
0
1 2 3
•方格的四种类型: · 非墙且未经试探的方格 · 墙 · 已在路径上的方格 · 已试探过的无发展前途的方格 •方向标记:
西3 南2 北4 东1
4
5 6 7 8 9 X
• 起点:(x=1,y=1);
栈顶
an
an-1
……
a2
栈底
a1
2
数据结构
3.1 栈
3.1.2 顺序栈的表示和实现
3 2 1 top base 0 top base
top
D
top
C
B A
base
C
B
base
A
A
typedef struct { SElemType *base ; SElemType *top ; int stacksize ;
(s.stacksize+STACK_INCREMENT)*sizeof(SElemType)); if ( !s.base ) exit ( OVERFLOW );
《数据结构与算法》PPT课堂课件-第3章-栈
6
-
操作数 运算符
6 3 6 操作数
* -
运算符
18
6
-
12
操作数 运算符
操作数 运算符
2021/6/13
15
后缀表达式求值步骤: 1、读入表达式一个字符 2、若是操作数,压入栈,转4 3、若是运算符,从栈中弹出2个数,将运算结果再压入栈 4、若表达式输入完毕,栈顶即表达式值;
若表达式未输入完,转1
3.2.1.1实现:一维数组s[M]
top= -1
5 top
4 top 3 top
top 2
top 1 0 top
栈空
F5 E4 D3 C2 B1 A0 进栈
栈满
top top top top top top top
栈空
F5 E4 D3 C2 B1 A0 出栈
栈顶指针top,指向实际栈顶 后的空位置,初值为-1
式处理结束。从操作T数2=栈C弹/D出表达T式3=结T果2+。T1
202求值
中缀表达式 a*b+c a+b*c a+(b*c+d)/e
后缀表达式(RPN) ab*c+ abc*+ abc*d+e/+
中缀表达式:操作数栈和运算符栈
p计算 2+4-3*6
4
2
+
操作数 运算符
2021/6/13
1# 紫色 2# 黄色 3# 红色 4# 绿色
(7)
(2) (6)
(1) (3) (4)
(5)
12 3 4567
1 2 32 342 43 3 1
17
例:已知字符串的内容为b%-y-3*y↑2, 利用栈的进栈和退栈操作将其转换成 by-%3y2 ↑ *-试给出进栈和退栈的操作序列。
数据结构课件-第3章-栈和队列资料
这三种情况对应到栈的操作即为: 1.和栈顶的左括弧不相匹配; 2.栈中并没有左括弧等在哪里; 3.栈中还有左括弧没有等到和它相匹配的右括弧。
栈也有两种存储表示:顺序存储和链式存储
顺序存储结构简称为顺序栈 链式存储结构简称为链栈
"栈顶指针"意为指示栈顶元素在栈中的位置,但它的值 实际是栈中元素的个数,和顺序表中的 length 值的意义 相同。
3.1栈 3.1.2 栈的存储表示和操作的实现
一、顺序栈类型的定义
//结构定义:
typedef struct {
StackLength(S) 初始条件:栈 S 已存在。 操作结果:返回栈 S 中元素个数,即栈的长度
GetTop(S, &e) 初始条件:栈 S 已存在且非空。 操作结果:用 e 返回S的栈顶元素。
Push (&S, e) 初始条件:栈 S 已存在。 操作结果:插入元素 e 为新的栈顶元素。
Pop (&S, &e) 初始条件:栈 S 已存在且非空。 操作结果:删除 S 的栈顶元素,并用 e 返回其值。
3.2.2 括弧匹配检验
假设表达式中允许包含两种括号:圆括号和方括号
其正确的匹配:如([ ]())或[([ ][ ])]等 错误的匹配:[( ])或([ ]( )或 ( ( ) ) )等
现在的问题是,要求检验一个给定表达式中的括弧是否 正确匹配?
问题分析: 方法可用“期待的急迫程度”这个概念来描述。
bool Pop (Stack &S, ElemType &e); //若栈不空,则删除S的栈顶元素,用e返回其值, //并返回TRUE;否则返回FALSE。
void StackTraverse (Stack S, void (*visit(ElemType )) //依次对S的每个元素调用函数 visit( ), //一旦 visit( ) 失败,则操作失败。
栈也有两种存储表示:顺序存储和链式存储
顺序存储结构简称为顺序栈 链式存储结构简称为链栈
"栈顶指针"意为指示栈顶元素在栈中的位置,但它的值 实际是栈中元素的个数,和顺序表中的 length 值的意义 相同。
3.1栈 3.1.2 栈的存储表示和操作的实现
一、顺序栈类型的定义
//结构定义:
typedef struct {
StackLength(S) 初始条件:栈 S 已存在。 操作结果:返回栈 S 中元素个数,即栈的长度
GetTop(S, &e) 初始条件:栈 S 已存在且非空。 操作结果:用 e 返回S的栈顶元素。
Push (&S, e) 初始条件:栈 S 已存在。 操作结果:插入元素 e 为新的栈顶元素。
Pop (&S, &e) 初始条件:栈 S 已存在且非空。 操作结果:删除 S 的栈顶元素,并用 e 返回其值。
3.2.2 括弧匹配检验
假设表达式中允许包含两种括号:圆括号和方括号
其正确的匹配:如([ ]())或[([ ][ ])]等 错误的匹配:[( ])或([ ]( )或 ( ( ) ) )等
现在的问题是,要求检验一个给定表达式中的括弧是否 正确匹配?
问题分析: 方法可用“期待的急迫程度”这个概念来描述。
bool Pop (Stack &S, ElemType &e); //若栈不空,则删除S的栈顶元素,用e返回其值, //并返回TRUE;否则返回FALSE。
void StackTraverse (Stack S, void (*visit(ElemType )) //依次对S的每个元素调用函数 visit( ), //一旦 visit( ) 失败,则操作失败。
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
vol(3)+5 9 vol(2)+3 6 vol(1)+4 2 vol(0)+2 0
=vol(0)+2+4+3+5 =0+2+4+3+5 =14
4. 试推导出当总盘数为 n 的 Hanoi 塔的移动次数。 设 Hn 为 n 个盘子的 Hanoi 塔的移动次数。(假定 n 个盘子从钢针 X 移到钢针 Z,可借助钢针 Y) 则 Hn =2Hn-1+1 //先将 n-1 个盘子从 X 移到 Y,第 n 个盘子移到 Z,再将那 n-1 个移 到Z =2(2Hn-2+1)+1 =22 Hn-2+2+1 =22(2Hn-3+1)+2+1 =23 Hn-3+22+2+1 · · · k = 2 Hn-k+2k-1 +2k-2 +…+21 +20 =2n-1 H1+2n-2+2n-3+…+21+20 因为 H1=1,所以原式 Hn=2n-1+2n-2+…+21+20=2n-1 故总盘数为 n 的 Hanoi 塔的移动次数是 2n-1。 5. 用栈实现将中缀表达式 8-(3+5)*(5-6/2)转换成后缀表达。 中缀表达式 exp1 转为后缀表达式 exp2 的规则如下: 设操作符栈 s,初始为空栈后,压入优先级最低的操作符‘#’ 。对中缀表达式从左向右扫描, 遇操作数,直接写入 exp2;若是操作符(记为 w) ,分如下情况处理,直至表达式 exp1 扫 描完毕。 (1)w 为一般操作符(’+’,’-‘,’*’,’/’等) ,要与栈顶操作符比较优先级,若 w 优先级高 于栈顶操作符,则入栈;否则,栈顶运算符退栈到 exp2,w 再与新栈顶操作符作上述比较 处理,直至 w 入栈。 (2)w 为左括号(’(’) ,w 入栈。 (3)w 为右括号(’)’) ,操作符栈退栈并进入 exp2,直到碰到左括号为止,左括号退栈(不 能进入 exp2) ,右括号也丢掉,达到 exp2 中消除括号的目的。 (4)w 为‘#’ ,表示中缀表达式 exp1 结束,操作符栈退栈到 exp2,直至碰到‘#’ ,退栈, 整个操作结束。 这里,再介绍一种简单方法。中缀表达式转为后缀表达式有三步:首先,将中缀表达式中所
四、应用题 1. 有 5 个元素,其入栈次序为:A,B,C,D,E,在各种可能的出栈次序中,以元 素 C,D 最先出栈(即 C 第一个且 D 第二个出栈)的次序有哪几个? 答:三个:CDEBA,CDBEA,CDBAE 2.(1) 什么是递归程序? (2) 递归程序的优、缺点是什么? (3) 递归程序在执行时,应借助于什么来完成? (4) 递归程序的入口语句、出口语句一般用什么语句实现? 答: (1)一个函数在结束本函数之前,直接或间接调用函数自身,称为递归。例如,函数 f 在执行中,又调用函数 f 自身,这称为直接递归;若函数 f 在执行中,调用函数 g,而 g 在 执行中,又调用函数 f,这称为间接递归。在实际应用中,多为直接递归,也常简称为递归。 (2)递归程序的优点是程序结构简单、清晰,易证明其正确性。缺点是执行中占内存空 间较多,运行效率低。 (3)递归程序执行中需借助栈这种数据结构来实现。 (4)递归程序的入口语句和出口语句一般用条件判断语句来实现。递归程序由基本项和 归纳项组成。基本项是递归程序出口,即不再递归即可求出结果的部分;归纳项是将原来问 题化成简单的且与原来形式一样的问题,即向着“基本项”发展,最终“到达”基本项。 3. 设有下列递归算法: FUNCTION vol(n:integer):integer; x :integer: VAR BEGIN IF n=0 THEN vol:=0 ELSE BEGIN read(x);vol:=vol(n-1)+x; END; END; int voi(int n) { int x; if(n=0) return 0; else read(x); return vol(n-1)+x; } 如该函数被调用时,参数 n 值为 4,读入的 x 值依次为 5,3,4,2,函数调用结束时返回值 vol 为多少?用图示描述函数执行过程中,递归工作栈的变化过程。 答:函数调用结束时 vol=14。执行过程图示如下: vol(4) vol(4)=vol(3)+5 14 =vol(2)+3+5 =vol(1)+4+3+5
栈
4. 表达式 a*(b+c)-d 的后缀表达式是( B )。 A.abcd*+B. abc+*dC. abc*+dD. -+*abcd 5. 设计一个判别表达式中左,右括号是否配对出现的算法,采用( D )数据结构最佳。 A.线性表的顺序存储结构 B. 队列 C. 线性表的链式存储结构 D. 栈 二、判断题 1. 消除递归不一定需要使用栈,此说法( √ ) 2. 栈是实现过程和函数等子程序所必需的结构。 ( √ ) 3. 两个栈共用静态存储空间,对头使用也存在空间溢出问题。 ( √ ) 4.两个栈共享一片连续内存空间时,为提高内存利用率,减少溢出机会,应把两个栈的栈 底分别设在这片内存空间的两端。 ( √ ) 5. 即使对不含相同元素的同一输入序列进行两组不同的合法的入栈和出栈组合操作,所得 的输出序列也一定相同。 ( × ) 6. 有 n 个数顺序 (依次) 进栈, 出栈序列有 Cn 种, Cn=[1/ (n+1) ]* (2n) !/[(n!)*(n!)]。 ( √ ) 三、填空 1.设有一个空栈,栈顶指针为 1000H(十六进制),现有输入序列为 1,2,3,4,5,经过 PUSH,PUSH,POP,PUSH,POP,PUSH,PUSH 之 后 , 输 出 序 列 是 _______ , 而 栈 顶 指 针 值 是 _______H。设栈为顺序栈,每个元素占 4 个字节。 23 100CH 2. 当两个栈共享一存储区时, 栈利用一维数组 stack(1,n)表示, 两栈顶指针为 top[1]与 top[2], 则当栈 1 空时,top[1]为_______,栈 2 空时 ,top[2]为_______,栈满时为_______。 0 n+1 top[1]+1=top[2] 3.表达式 23+((12*3-2)/4+34*5/7)+108/9 的后缀表达式是_______。 23.12.3*2-4/34.5*7/++108.9/+(注:表达式中的点(.)表示将数隔开,如 23.12.3 是三个数)
6. 有递归算法如下: FUNCTION sum (n:integer):intger; BEGIN IF n=0 THEN sum:=0 ELSE BEGIN read(x);sum:=sum(n-1)+x END; END; int sum(int n) { if(n=0) return 0; else read(x); return sum(n-1)+x } 设初值 n=4,读入 x=4,9,6,2 问:(1) 若 x 为局部变量时;该函数递归结束后返回调用程序的 sum=? 并画出在递归过 程中栈状态的变化过程; (2) 若 x 为全程变量递归结束时返回调用程序的 sum=? 答: (1)sum=21。当 x 为局部变量时,每次递归调用,都要给局部变量分配存储单元,故 x 数值 4,9,6 和 2 均保留,其递归过程示意图如下:
sum(4) 21 sum(3)+4 17 sum(2)+9 8 sum(1)+6 2 sum(0)+2 (x=4) (x=9) (x=6) (x=2)
0 (2) sum=8,当 x 为全局变量时,在程序的整个执行期间,x 只占一个存储单元,先后读 入的 4 个数(4,9,6,2),仅最后一个起作用。当递归调用结束,逐层返回时 sum:=sum(n-1)+x 表 达式中,x 就是 2,所以结果为 sum=8。 7. 画出对算术表达式 A-B*C/D-E↑F 求值时操作数栈和运算符栈的变化过程。 步 骤 初 始 1 2 3 4 5 6 7 8 A A AB AB ABC AT(T=B*C) ATD AT(T=T/D) T(T=A-T) opnd 栈 optr 栈 # # ###-* #-* #-/ #-/ ##输入字符 A-B*C/D-E ↑ F# A-B*C/D-E ↑ F# -B*C/D-E ↑ F# B*C/D-E↑F# *C/D-E↑F# C/D-E↑F# /D-E↑F# D-E↑F# -E↑F# 主要操作 PUSH(OPTR,’#’) PUSH(OPND,A) PUSH(OPTR,’-’) PUSH(OPND,B) PUSH(OPTR,’*’) PUSH(OPND,C) PUSH(OPND,POP(OPND)*POP(OPND)) PUSH(OPTR,’/’) PUSH(OPND,D) x=POP(OPND);y=POP(OPND) PUSH(OPND,y/x); x=POP(OPND);y=POP(OPND); PUSH(OPND,y-x) PUSH(OPTR,’-’) PUSH(OPND,E) PUSH(OPTR, ‘↑’) PUSH(OPND,F) X=POP(OPND) Y=POP(OPND) POP(OPTR) PUSH(OPND,y↑x) x=POP(OPND) y=POP(OPND) POP(OPTR) PUSH(OPND,y-x)(S=E ↑ F) R(R=T-S)
## -↑ # -↑ ##
E↑F# ↑F# F# #
8.在某程序中,有两个栈共享一个一维数组空间 SPACE[N]、SPACE[0]、SPACE[N-1] 分 别是两个栈的栈底。 (1)对栈 1、栈 2,试分别写出(元素 x)入栈的主要语句和出栈的主要语句。 (2)对栈 1、栈 2,试分别写出栈满、栈空的条件。 答:设 top1 和 top2 分别为栈 1 和 2 的栈顶指针 (1)入栈主要语句 if(top2-top1==1) {printf(“栈满\n”); exit(0);} case1:top1++;SPACE[top1]=x; //设 x 为入栈元素。 case2:top2--;SPACE[top2]=x; 出栈主要语句 case1:if(top1==-1) {printf( “栈空\n” ) ;exit(0) ;} top1--;return(SPACE[top1+1]) ; //返回出栈元素。 ;} case2:if(top2==N){printf( “栈空\n” ) ;exit(0) top2++;return(SPACE[top2-1]) ; //返回出栈元素。 (2)栈满条件:top2-top1=1 栈空条件:top1=-1 并且 top2=N //top1=-1 为左栈空,top2=N 为右栈空 五、算法设计题 1 .设从键盘输入一整数的序列:a1, a2, a3,…,an,试编写算法实现:用栈结构存储输入 的整数, 当 ai≠-1 时, 将 ai 进栈; 当 ai=-1 时, 输出栈顶整数并出栈。 算法应对异常情况 (入 栈满等)给出相应的信息。 #define maxsize 栈空间容量 void InOutS(int s[maxsize]) //s 是元素为整数的栈,本算法进行入栈和退栈操作。 {int top=0; //top 为栈顶指针,定义 top=0 时为栈空。 for(i=1; i<=n; i++) //n 个整数序列作处理。 {scanf(“%d”,&x); //从键盘读入整数序列。 if(x!=-1) // 读入的整数不等于-1 时入栈。 if(top==maxsize-1){printf(“栈满\n”);exit(0);}else s[++top]=x; //x 入栈。 else //读入的整数等于-1 时退栈。 {if(top==0){printf(“栈空\n”);exit(0);} else printf(“出栈元素是%d\n”,s[top--]);}} }//算法结束。 2. 设表达式以字符形式已存入数组 E[n]中,‘#’为表达式的结束符,试写出判断表达式中括 号(‘(’和‘)’)是否配对的 C 语言描述算法:EXYX(E); (注:算法中可调用栈操作的基本 算法。) 答:[题目分析]判断表达式中括号是否匹配,可通过栈,简单说是左括号时进栈,右括号时 退栈。 退栈时, 若栈顶元素是左括号, 则新读入的右括号与栈顶左括号就可消去。 如此下去, 输入表达式结束时,栈为空则正确,否则括号不匹配。 int EXYX(char E[],int n) //E[]是有 n 字符的字符数组,存放字符串表达式,以‘#’结束。本算法判断表达式中圆