第三章栈和队列.docx
- 文档编号:3246856
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:30
- 大小:48.46KB
第三章栈和队列.docx
《第三章栈和队列.docx》由会员分享,可在线阅读,更多相关《第三章栈和队列.docx(30页珍藏版)》请在冰豆网上搜索。
第三章栈和队列
第三章栈和队列
教学目的与要求
本章的目的是介绍栈和队列的逻辑结构定义及在两种结构上如何实现栈和队列的基本运算。
要求在掌握上和队列的特点的基础上,懂得在什么样的情况下能够使用栈和队列。
重点与难点
本章重点是掌握计算和队列的两种存储结构上实现的基本运算,难点是循环队列中对边界条件的处理。
教学内容
3.1栈
3.1.1栈的定义及其运算
(1)栈:
是限制仅在表的一端进行插入和删除运算的线性表。
允许进行插入和删除的这一端称为栈顶,另一端称为栈底。
当表中没有元素时称为空栈。
(2)栈的特点:
从定义不难看出栈具有后进先出(Lastinfirstout)的特点,简称为LIFO表。
(3)栈的基本运算:
Initstack(S)构造一个空栈。
Stackempty(S)判定栈是否为空,若为空返回true,否则,返回false。
Stackfull(S)判定栈是否已满,若已满返回true,否则,返回false。
该函数只适合于顺序栈。
Push(S,x)进栈操作。
若栈不满,则将元素x压入栈顶。
Pop(S)出栈操作。
若栈S非空,则删除栈顶元素并将该元素返回。
Stacktop(S)读取栈顶元素。
若栈S非空,则返回栈顶元素。
3.1.2顺序栈
1.栈的顺序表示与实现
由于栈是操作受限制的线性表,所以,线性表的存储结构对栈的也适合。
顺序栈类型定义如下:
#defineStacksize100//假定预分配的栈空间最多为100个元素
typedefchardatatype;//假定栈元素的数据类型为char
tefstruct{
datatypedata[Stacksize];//用一维向量data作为栈的存储空间
inttop;//top为栈顶指针
}Seqstack;
可以看出栈被定义为结构类型。
在实际应用中,可根据具体情况使用结构型变量或指向结构型变量的指针变量来表示栈。
2.栈操作中应注意的问题:
(设S是指向栈的指针)
①栈顶指针:
S->top;栈顶元素:
S->data[S->top];
②栈空的判定条件:
S->top==-1;栈满的判定条件:
S-top==Stacksize-1;
③栈中的元素个数:
S->top+1;
④若S是结构型变量则所涉及操作中的S->应改为S.;
3.栈的基本运算在顺序栈上的实现
(1)进栈操作(push(Seqstack*S,datatypex))
基本步骤:
若栈不满,则
栈顶指针加1:
S->top++;
元素入栈:
S->data[S-top]=x;
(2)出栈操作(pop(Seqstack*S))
基本步骤:
若栈非空,则
读取栈顶元素:
x=S->data[S->top];
栈顶指针减1:
S->top--;
返回栈顶元素:
return(x);
【分析】出栈操作和入栈操作是栈的两种重要操作,应注意操作的判定条件。
栈的有效使用空间是0到Stacksize-1,所以,当S->top==-1时,表示栈空;当S->top==Stacksize-1时,表示栈满。
时间复杂度均为O
(1)。
3.1.3链栈
1.链栈及类型定义
栈以链式存储方式存储所形成的存储结构,称为链栈。
就是单链表。
其数据类型定义如下:
typedefstructstacknode{
datatypedata;
structstacknode*next;
}Stacknode;
typedefstruct{
Stacknode*stop;
}Linkstack;
Linkstack*s;
2.链栈操作应注意的问题
与链表不同,链栈的插入和删除操作仅限定在表头位置进行,所以,链栈不需要附加头结点。
链表的头指针就是链栈的栈顶指针:
S->top;
栈顶元素为:
S->top->data。
空栈的判定条件是:
S->top==null.;
只要系统的备用空间能够分配出存储结点就不会发生上溢。
所以,程序员不必考虑链栈栈满的问题。
链栈的操作就是单链表的操作,只需注意栈本身的操作要求即可。
如:
进栈、出栈操作就是在表头进行插入和删除;求栈中的元素个数就是求链表中的结点个数。
3.1.4栈的应用举例
1.设计算法判断一个算术表达式的圆括号是否正确配对。
(提示:
凡遇‘(‘就进栈,遇‘)’就退掉栈顶的‘(‘,表达式扫描完毕,栈应为空)
算法
intbracketsmatch(chara[])
{//设算术表达式以字符串形式存储在数组中
Seqstack*S;
Initstack(S);
intk=0;
while(a[k]!
=’\0’)
if(a[k]=='(')
Push(S,'(');
elseif(a[k]==')')
if(Stackempty(S))
return0;
elsePop(S);
if(Stackempty(S))
return1;
elsereturn0;
}
2.一个双向栈S是在同一向量空间里实现的两个栈,它们的栈底分别设在向量空间的两端。
试为此双向栈设计初始化Initstack(S)、入栈push(S,x,i)和出栈pop(i)算法,其中,i为0或1用于指示栈号。
算法
#definmaxsize100
typedefstructnode{
datatypedata[maxsize];
inttop1,top2;
}Seqstack;
(1)双向栈的初始化
viodInitstack(Seqstack*S)
{
S->top1=-1;S->top2=maxsize;
}
(2)双向栈入栈算法
viodpush(Seqstack*S,datatypex,inti)
{if(S->top1+1==S->top2)
erroe(overflow);
else
if(i==0)
{S->top1++;
S->data[S->top1]=x;}
else
{S->top2--;
S->data[S->top2]=x;}
}
(3)双向栈出栈算法
datatypepop(Seqstack*S,inti)
{if(i==0)
if(S->top1==-1)
error(downflow);
else
{returnS->data[S->top1]}
else
if(S->top2==maxsize)
error(downflow);
else
returnS->data[S->top2];
}
3.Ackerman函数的定义如下:
n+1当m=0时
AKM(m,n)=AKM(m-1,1)当m≠0,n=0时
AKM(m-1,AKM(m,n-1)) 当m≠0,n≠0时
请写出递归算法。
算法如下:
intakm(intn,intm)
{if(m==0)
returnn+1;
elseif(n==0&&m!
=0)
returnakm(m-1,1);
else
returnakm(m-1,akm(m,n-1));
}
3.2队列
3.2.1队列的定义及其基本运算
1.队列的概念
队列:
是一种操作受限的线性表。
它只允许在表的一端进行插入,在表的另一端进行删除。
允许删除的一端称为的队头(front),允许插入的一端称为队尾(rear)。
当队列中没有元素时称为空队列。
队列中包含的元素数称为队列的长度。
空队列的长度为0。
2.队列的特点:
从定义不难看出队列具有先进先出(firstinfirstout)的特点,简称为FIFO表。
3.队列的基本运算:
Initqueue(Q):
置空队。
构造一个供空队列;
Queueempty(Q):
判定队列Q是否为空,为空返回真值,否则返回价假值;
Queuefull(Q):
判定队列Q是否已满,若已满返回真值,否则返回价假值;
Enqueue(Q,x):
入对操作。
如果队列不满,则将元素x插入队列Q;
Dequeue(Q):
出队操作。
若队列非空,则删除队头元素并将其返回;
Queuefront(Q):
读取队头元素。
若队列非空,则返回队头元素。
3.2.2顺序队列
1.顺序队列与循环队列
队列的顺序存储结构称为顺序队列,顺序队列实际上是运算受限的顺序表。
由于队列的操作总是在表的两端进行,所以设置两个指针分别指向对头和队尾位置。
顺序队列存在的“假溢出”现象,使得被删除元素的存储空间永远无法被重新利用,所以顺序队列不能充分利用存储空间。
为解决假溢出现象,我们可以将向量空间想象为一个首尾相接的环形结构,并称这种向量为循环向量,存储在其中的队列称为循环队列。
通常,我们总是在循环队列上完成队列的操作。
2.循环队列的类型定义:
#defineQueuesize100
typedefchardatatype;
typedefstruct{
datatypedata[Queuesize];
intfront,rear;
intcount;
}Cirqueue;
这里我们将循环队列的存储结构定义为结构类型Cirqueue。
应用时,可根据具体需要将队列定义为结构体变量或指向结构的指针变量。
例如:
Cirqueue*Q,Q1;其中,Q为指针变量,Q1为结构体变量注意二者访问成员的方法不同。
3.循环队列应注意的几个问题
①队头指针和队尾指针在循环意义下加1操作的实现:
(向量下标的有效范围下界是0,上界是Queuesize-1)
Q->front=(Q->front+1)%Queuesize;
Q->rear=(Q->rear+1)%Queuesize;
②循环队列队满、队空的判定:
为了区别队满和队空,有三种方法可供采用,分别为:
方法1:
引入一个布尔变量以区别队列的空和满两种状态;
方法2:
采用少用一个元素的空间的策略,例如:
队头指针指向队头元素,队尾指针指向队尾元素下一个位置,则
队空的判定条件为:
Q->front==Q->rear
队满的判定条件为:
Q->front==(Q->rear+1)%Queuesize1;
但方法3:
引入一个计数器记录队列元素的总数。
在众多的参考书中更多地采用的方法2,应对方法2给予足够的重视。
4.基本运算在循环队列上的实现(队满、队空的判定采用方法2)
(1)入队操作
voidEnqueue(Cirqueue*Q,datatypex){
if(Q->front==(Q->rear+1)%Queuesize)
error("Queueoverflow");
else
{Q->data[Q->rear]=x;
Q->rear=(Q->rear+1)%Queuesize;}
}
(2)出队操作
datatypeDequeue(Cirqueue*Q){
if(Q->front==Q->rear)
error("Queuedownflow");
else
{x=Q->data[Q->front];
Q->front=(Q->front+1)%Queuesize;
return(x);
}
}
【分析】入队、出队操作是队列的两种重要操作。
算法采用方法2区别队满和队空,应注意队满和队空的判定条件,以及入队和出队后队尾指针和队头指针在循环队列中的修改(即加1后进行取模运算)。
两算
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第三 队列
![提示](https://static.bdocx.com/images/bang_tan.gif)