数据结构第三章.docx
- 文档编号:5486890
- 上传时间:2022-12-17
- 格式:DOCX
- 页数:17
- 大小:28.99KB
数据结构第三章.docx
《数据结构第三章.docx》由会员分享,可在线阅读,更多相关《数据结构第三章.docx(17页珍藏版)》请在冰豆网上搜索。
数据结构第三章
第三章栈和队列
3.1栈
1.栈的概念及运算:
栈(stack):
栈是运算受限的线性表,只限制在表的一端进行运算,称为栈顶(top),另一端称栈底(bottom),当表中无元素时称为空栈。
栈又称为后进先出(lastinfirstout)的线性表。
栈又称为先进后出(firstinlastout)的线性表。
例如:
a1,a2……an==>an,an-1,……a1
一叠书,一叠重物
运算:
置空栈SETNULL(S)
判空栈EMPTY(S)
进栈PUSH(S,X)
退栈POP(S)
取栈顶TOP(S)//不改变栈的状态
2.顺序栈
顺序栈:
栈的顺序存储结构称为顺序栈。
栈底位置不变,栈顶指针top用来指示栈顶位置
定义:
typedefstruct
{datatypedata[maxsize];
inttop;
}seqstack;
seqstack*s;
上溢,下溢,设初始情况下s->top=-1;
运算:
图示
置空栈
voidSETNULL(seqstack*s)
{s->top=-1;
}
判栈空
intEMPTY(seqstack*s)
{if(s->top>=0)
returnFLASE;
elsereturnTRUE;
}
进栈
seqstack*sPUSH(seqstack*s,datatypex)
{if(s->top==maxsize-1)
{print(overflow);returnNULL;}//上溢
else
{s->top++;s->data[s->top]=x;}
returns;
}
退栈
datatypePOP(seqstack*s)
{if(EMPTY(s))
{print(underflow);returnNULL;}//下溢
else
{s->top--;
returns->data[s->top+1];
}
}
取栈顶
datatypeTOP(seqstack*s)
{if(EMPTY(s))
{print(stackisempty);returnNULL;}//空栈
else
{returns->data[s->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;
p->next=top;
returnp;
}
出栈
linkstack*POPLSTACK(linkstack*top,datatype*datap)
{linkstack*p;
if(top==NULL)
{print(underflow);returnNULL;}//下溢
else
{*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< } } 2.括号匹配问题 表达式中括号是否匹配。 算法实现: #include 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);cin>>ch; } else switch(precede(gettop(OPTR),ch)) {case<: push(OPTR,ch);cin>>ch; break; case>: pop(OPTR,theta); pop(OPND,b);pop(OPND,a); push(OPND,operate(a,theta,b)); break; case=: pop(OPTR,x);cin>>ch; break; }//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< 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); else {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。 定义: typedefstruct {datatypedata[maxsize]; intfront,rear; }sequeue; sequeue*sq; 图示: P49 讨论: 为方便设front指向队头前一位置,rear指向队尾,开始时front,rear指向向量下标的前一位置-1。 入队: sq->rear++; sq->data[sq->rear]=x; 出队: sq->front++; 长度: (sq->rear)-(sq->front) 空队: 长度为0 队满: (sq->rear)-(sq->front)=maxsize 假上溢: 但是当sq->rear=maxsize-1时,即使队列不满也会上溢,我们称这种现象为假上溢。 原因: 出队时队列中的元素并没有向前移动,被删除的空间在以后永远使用不到。 解决: 可在出队时将队列向前移一个位置,也可在发生上溢时,将整个队列向前移至front=-1的位置上,但缺点是显而易见的,实际中很少使用。 循环队列: 通常,设想sq->data[maxsize]首尾相接成圆环称循环向量、循环队列,因此当发生假上溢时的入队操作可描述为: 入队: if(sq->rear+1>=maxsize) sq->rear=0; elsesq->rear++; 或: sq->rear=(sq->rear+1)%maxsize 出队: sq->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; sq->rear=maxsize-1; } 判队空 intEMPTY(sequeue*sq) {if(sq->front==sq->rear) returnTRUE; elsereturnFALSE; } 取队头 datatypeFRONT(sequeue*sq) {if(EMPTY(sq)) {print(queueisempty);returnNULL;}//队空 elsereturnsq->data[(sq->front+1)%maxsize]; } 入队 intENQUEUE(sequeue*sq,datatypex) {if(sq->front==(sq->rear+1)%maxsize) {print(queueisfull);returnNULL;}//队满 else{sq->rear=(sq->rear+1)%maxsize; sq->data[sq->rear]=x; returnTRUE; } } 出队 datatypeDEQUEUE(sequeue*sq) {if(EMPTY(sq)) {print(queueisempty);returnNULL;}//队空 else{sq->front=(sq->front+1)%maxsize; return(sq->data[sq->front]); } } 3.链队列 链队列: 队列的链式存储结构称为链队列。 限制仅在表头删除表尾插入的单链表,方便的做法是再增加一个尾指针以便插入操作。 定义: typedefstruct { linklist*front,*rear; }linkqueue; linkqueue*q; 例图: 为方便运算增加一个头结点 当q->front==q->rear----空链队列P52 运算: 置空队 voidSETNULL(linkqueue*q) {q->front=malloc(sizeof(linkqueue)); q->front->next=NULL; q->rear=q-front; } 判队空 intEMPTY(linkqueue*q) {if(q->front==q->rear) returnTRUE; elsereturnFALSE; } 取队头 datatypeFRONT(linkqueue*q) {if(EMPTY(q)) {print(queuqisempty);returnNULL;}//队空 elsereturn(q->front->next->data); } 入队 voidENQUEUE(linkqueue*q,datatypex) {q->rear->next=malloc(sizeof(linkqueue)); q->rear=q->rear->next; q->rear->data=x; q->rear->next=NULL; } 出队 (1)队列长度大于1 q->front->next=q->front->next->next (2)队列长度等于1 if(q->front->next->next==NULL) q->rear=q->front(指向头结点) (3)改进算法,即出队时只修改头指针,删除头结点,即使长度为1,也不修改尾指针。 datatypeDEQUEUE(linkqueue*q) { if(EMPTY(q)) {print(queueisempty);returnNULL;}//队空 else{s=q->front; q->front=q->front->next; free(s); return(q->front->data); } } 队列应用举例: 求迷宫的最短路径 迷宫示意: 入口(1,1),出口(m,n)。 0123456789 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 0 1 0 0 1 1 1 1 1 1 0 1 1 1 0 0 1 1 1 1 1 0 0 1 1 0 0 0 1 1 0 1 1 0 0 1 1 0 1 1 1 1 1 1 1 1 1 1 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 0 0 1 1 1 1 2 1 0 3 1 -1 4 0 -1 5 -1 -1 6 -1 0 7 -1 1 如何搜索路径? 搜索过程必须记下每一个可达点,以便从这些点出发向四周搜索,需引进一队列来保存已达坐标点。 定义结构: structsqtype {int,x,y,pre; }sq[r];//r=m*n 初始设front=rear=1,从front指向的点出发,当搜索到可达点时则(i,j,front)入队,rear指向当前的可达点,完毕front++,即出队,继续…… Noxypre 1 1 1 0 2 2 2 1 f->3 3 3 2 4 3 1 2 5 3 4 3 r->6 2 4 3 … … … … 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赋初值 typedefstruct {intx,y;//行列坐标 intpre;//静态链域 }sqtype; sqtypesq[r];//顺序队列 structmoved {intx,y;//坐标增量,取值-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; j=y+move[v].y; 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文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 第三