数据结构第三章文档格式.docx
- 文档编号:18474380
- 上传时间:2022-12-17
- 格式:DOCX
- 页数:17
- 大小:28.99KB
数据结构第三章文档格式.docx
《数据结构第三章文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构第三章文档格式.docx(17页珍藏版)》请在冰豆网上搜索。
top]=x;
}
returns;
退栈
datatypePOP(seqstack*s)
{if(EMPTY(s))
{print(underflow);
}//下溢
top--;
returns->
top+1];
取栈顶
datatypeTOP(seqstack*s)
{print(stackisempty);
}//空栈
{returns->
top];
共享空间:
若有多个顺序栈,为防止上溢则空间开销较大,可多个栈共享空间,调节余缺,节省空间,又防止上溢发生的概率。
当n>
2时效率较低。
两个栈共享空间的上溢、下溢和栈满问题。
|-----------栈s1-----------||------------栈s2---------|
01t1t2n-2n-1
a1
a2
……
ai
bj
b2
b1
栈底1栈顶1栈顶2栈底2
3.链栈
链栈:
栈的链式存储结构称为链栈。
其操作仅限制在表头位置上进行,不需设置头结点。
typedefstructnode
{datatypedata;
structnode*next;
}linkstack*top;
top为栈顶指针,唯确定一个链栈。
当top==NULL时,链栈为空栈。
链栈是动态产生的,无需考虑上溢问题。
linkstack*PUSHLSTACK(linkstack*top,datatypex)
{linkstack*p;
p=malloc(sizeof(linkstack);
p->
data=x;
next=top;
returnp;
出栈
linkstack*POPLSTACK(linkstack*top,datatype*datap)
if(top==NULL)
{*datap=top->
data;
p=top;
top=top->
next;
free(p);
3.2栈的应用举例
1.数制转换问题
十进制数N和其它d进制的转换是计算机实现计算的基本问题,其解决方法很多,其中一个简单算法基于下列原理:
N=(N/d)*d+N%d
例如:
(1348)10=(2504)8,其运算过程如下:
NN/8N%8
13481684
168210
2125
202
算法思想:
首先按照上述计算过程得到的八进制数的各位依次进栈,然后将栈中的八进制数依次出栈输出,就是该十进制数转换得到的八进制数。
算法描述:
voidconversion()
{
initstack(S);
cin>
>
N;
while(N)
{push(S,N%8);
N=N/8;
while(!
stackempty(S))
{pop(S,e);
cout<
<
e;
2.括号匹配问题
表达式中括号是否匹配。
算法实现:
#include<
stdio.h>
voidmain()
{charstr[20],*ps=str;
chars[20],inttop=0;
printf("
pleaseinputastring\n"
);
scanf("
%s"
str);
while(*ps)
{if(*ps=='
('
)s[++top]='
;
if(*ps=='
)'
)top--;
ps++;
if(top==0)printf("
OKOKOKOK\n"
elseprintf("
NONONONO\n"
getchar();
3.表达式求值:
#(A+B)*(C-D)#
根据算符优先关系,设置运算符栈OPTR和操作数栈OPND,……
operandtypeevaluateexpression()
{initstack(OPTR);
push(OPTR,#);
initstack(OPND);
cin>
ch;
while(ch!
=#||gettop(OPTR)!
=#)
{if(!
in(ch,op))
{push(OPND,ch);
else
switch(precede(gettop(OPTR),ch))
{case<
:
push(OPTR,ch);
break;
case>
pop(OPTR,theta);
pop(OPND,b);
pop(OPND,a);
push(OPND,operate(a,theta,b));
case=:
pop(OPTR,x);
}//switch
}//while
returngettop(OPND);
}//evaluateexpression
算符间的优先关系
+
-
*
/
(
)
#
—
=
3.3栈与递归的实现
1.计算n的阶乘
longfact(longn)
{if(n==0)return1;
elsereturnn*fact(n-1);
2.依次输出链表中的结点的值
voidprint(linklist*p)
{if(p)
{cout<
p-data<
endl;
print(p-next);
3.n阶Hanoi塔问题
算法求解:
将A柱上的n-1个盘借助于C柱移到B柱上;
将A柱上的最后一个盘子直接移到C柱上;
将B柱上的n-1个盘借助于A柱移到C柱上;
voidhanoi(intn,charA,charB,charC)
{
if(n==1)
move(1,A,C);
{hanoi(n-1,A,C,B);
move(n,A,C);
hanoi(n-1,B,A,C);
注意:
程序流程
参数入栈
结束条件
返回地址
3.4队列
1.队列(queue):
是一种运算受限的线性表,只允许在表的一端进行插入称为队尾(rear),另一端进行删除称为队头(front)。
队列也称为先进先出(firstinfirstout)的线性表。
队列也称为后进后出(lastinlastout)的线性表。
a1,a2,……an==>
a1,a2,……an
排队上车,排队购物,打印队列
置空队列SETNULL(Q)
判队列空EMPTY(Q)
取队头FRONT(Q)
入队列ENQUEUE(Q,X)
出队列DEQUEUE(Q)
2.顺序队列
顺序队列:
队列的顺序存储结构称为顺序队列。
队列的队头队尾均是变化的,可设置两个指针分别指示队头,队尾的位置front,rear。
intfront,rear;
}sequeue;
sequeue*sq;
图示:
P49
讨论:
为方便设front指向队头前一位置,rear指向队尾,开始时front,rear指向向量下标的前一位置-1。
入队:
sq->
rear++;
sq->
data[sq->
rear]=x;
出队:
front++;
长度:
(sq->
rear)-(sq->
front)
空队:
长度为0
队满:
front)=maxsize
假上溢:
但是当sq->
rear=maxsize-1时,即使队列不满也会上溢,我们称这种现象为假上溢。
原因:
出队时队列中的元素并没有向前移动,被删除的空间在以后永远使用不到。
解决:
可在出队时将队列向前移一个位置,也可在发生上溢时,将整个队列向前移至front=-1的位置上,但缺点是显而易见的,实际中很少使用。
循环队列:
通常,设想sq->
data[maxsize]首尾相接成圆环称循环向量、循环队列,因此当发生假上溢时的入队操作可描述为:
if(sq->
rear+1>
=maxsize)
rear=0;
elsesq->
或:
rear=(sq->
rear+1)%maxsize
front=(sq->
front+1)%maxsize
但是:
若front从前面追上rear即sq->
front=sq->
rear----队空
若rear从后面追上front即sq->
rear=sq->
front----队满
因此:
仅凭上述等式无法判定是队空还是队满
(1)引入一标志量以区别队空,队满。
(2)入队前测试rear+1是否等于front即:
(sq->
rear+1)%maxsize==sq->
front则为队满。
从而保证sq->
rear==sq->
front是队空的判别条件。
这里满的条件是始终有一个元素的空间是空的(data[sq->
front]),即有maxsize个分量的向量只能表示maxsize-1内的队列,避免判别另设标志而造成的耗费。
置空队
voidSETNULL(sequeue*sq)
{sq->
front=maxsize-1;
rear=maxsize-1;
判队空
intEMPTY(sequeue*sq)
{if(sq->
front==sq->
rear)
returnTRUE;
elsereturnFALSE;
取队头
datatypeFRONT(sequeue*sq)
{if(EMPTY(sq))
{print(queueisempty);
}//队空
elsereturnsq->
data[(sq->
front+1)%maxsize];
入队
intENQUEUE(sequeue*sq,datatypex)
front==(sq->
rear+1)%maxsize)
{print(queueisfull);
}//队满
else{sq->
rear+1)%maxsize;
出队
datatypeDEQUEUE(sequeue*sq)
front+1)%maxsize;
return(sq->
front]);
3.链队列
链队列:
队列的链式存储结构称为链队列。
限制仅在表头删除表尾插入的单链表,方便的做法是再增加一个尾指针以便插入操作。
{
linklist*front,*rear;
}linkqueue;
linkqueue*q;
例图:
为方便运算增加一个头结点
当q->
front==q->
rear----空链队列P52
voidSETNULL(linkqueue*q)
{q->
front=malloc(sizeof(linkqueue));
q->
front->
next=NULL;
rear=q-front;
intEMPTY(linkqueue*q)
{if(q->
datatypeFRONT(linkqueue*q)
{if(EMPTY(q))
{print(queuqisempty);
elsereturn(q->
next->
data);
voidENQUEUE(linkqueue*q,datatypex)
rear->
next=malloc(sizeof(linkqueue));
rear=q->
出队
(1)队列长度大于1
next=q->
next
(2)队列长度等于1
if(q->
next==NULL)
front(指向头结点)
(3)改进算法,即出队时只修改头指针,删除头结点,即使长度为1,也不修改尾指针。
datatypeDEQUEUE(linkqueue*q)
if(EMPTY(q))
}//队空
else{s=q->
front;
front=q->
free(s);
return(q->
}
队列应用举例:
求迷宫的最短路径
迷宫示意:
入口(1,1),出口(m,n)。
0123456789
1
迷宫表示:
maze[m+2][n+2]
设maze[1][1]=0,maze[m,n]=00--通,1--不通
开始从点(1,1)出发向四周搜索,记下所有一步所能到达的坐标点P11-P1K1(1<
=K1<
=3),两步能到达的坐标点P21-P2K2(1<
=K2<
=5),依次进行,直至(m,n)。
从(m,n)回溯至入口即找到一条最短路径。
问题:
如何搜索(x,y)邻点(i,j)?
为方便为迷宫周围镶上一条取值为1的边,搜索方位8个方向,move[8]存放坐标增量,则邻点(i,j):
i=x+move[v].x;
j=y+move[v].y;
八个邻点的坐标增量:
北
(x-1,y-1)(x-1,y)(x-1,y+1)
↖↑↗
西←(x,y-1)(x,y)(x,y+1)→东
↙↓↘
(x+1,y-1)(x+1,y)(x+1,y+1)
南
八个方向的坐标增量:
Noxy
2
3
-1
4
5
6
7
如何搜索路径?
搜索过程必须记下每一个可达点,以便从这些点出发向四周搜索,需引进一队列来保存已达坐标点。
定义结构:
structsqtype
{int,x,y,pre;
}sq[r];
//r=m*n
初始设front=rear=1,从front指向的点出发,当搜索到可达点时则(i,j,front)入队,rear指向当前的可达点,完毕front++,即出队,继续……
Noxypre
1
2
f->
3
4
5
r->
6
…
r
如何防止重复搜索?
(1)一旦到达(x,y),则maze[x][y]=1,这样破坏原迷宫。
(2)令maze[x][y]=-1,则结束时将所有-1置为0,恢复迷宫。
保证:
回溯过程保证了路径最短,即哪条路线最先到达出口。
//迷宫最短路径
#definer64//定义r
#definem210//定义m+2为m2
#definen210//定义n+2为n2
intm=m2-2,n=n2-2;
//m,n赋初值
{intx,y;
//行列坐标
intpre;
//静态链域
}sqtype;
sqtypesq[r];
//顺序队列
structmoved
//坐标增量,取值-1,0,1
}move[8];
intmaze[m2][n2];
//迷宫数组
intSHORTPATH(intmaze[][n2])//找迷宫maze的最短路径
{inti,j,v,front,rear,x,y;
sq[1].x=1;
sq[1].y=1;
sq[1].pre=0;
//队列初值
front=1;
rear=1;
maze[1][1]=-1;
//标记入口点已到达过
while(front<
=rear)//队列非空
{x=sq[front].x;
y=sq[front].y;
//(x,y)为出发点
for(v=0;
v<
8;
v++)//搜索(x,y)的8个相邻点(i,j)是否可到达
{i=x+move[v].x;
if(maze[i][j]==0)//(i,j)为可到达点,将其入队列
{rear++;
sq[rear].x=isq[rear].y=j;
sq[rear].pre=front;
maze[i][j]=-1;
//标记(i,j)已到达过
if((i==m)&
&
(j==n))//到达出口
{PRINTPATH(sq,rear);
//打印路径
RESTORE(maze);
//恢复迷宫
return
(1);
//成功返回
front++;
//出队,front指向新的出发点
}//队空循环结束
return(0)//迷宫无路径返回
}//SHOTRPATH
voidPRINTPATH(sqtypesq[],intrear)//打印输出最短路径
{inti=rear;
do{
print(“\n(%d,%d)”,sq[i].x,sq[i].y);
i=sq[i].pre;
//找前一点
}while(i!
=0);
//i=0时已到达入口点
}//PRINTPATH
3.5离散事件模拟
教材
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 第三