版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第3章章 栈和队列栈和队列3.1 栈栈3.2 栈的应用举例栈的应用举例3.3 栈与递归的实现栈与递归的实现3.4 队列队列3.1 栈栈3.1.1 抽象数据类型栈的定义抽象数据类型栈的定义 栈的定义栈的定义l栈栈(stack),又称堆栈,是限制线性表中元素的插入和删除只,又称堆栈,是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为除的一端,为变化的一端,称为栈顶栈顶(Top),另一端为固定,另一端为固定的一端,称为的一端,称为栈底栈底(Bottom)。l根据栈的定义可知,最先根据栈
2、的定义可知,最先放入栈中元素在栈底,最放入栈中元素在栈底,最后放入的元素在栈顶,而后放入的元素在栈顶,而删除元素刚好相反,最后删除元素刚好相反,最后放入的元素最先删除,最放入的元素最先删除,最先放入的元素最后删除。先放入的元素最后删除。l也就是说,栈是一种后进也就是说,栈是一种后进先出先出(Last In First Out)的线性表,简称为的线性表,简称为LIFO表。表。l栈的插入操作被形象地称栈的插入操作被形象地称为为进栈进栈或入栈,删除操作或入栈,删除操作称为称为出栈出栈或或退栈退栈。例:例:l入栈顺序:入栈顺序:123l可能出栈顺序:可能出栈顺序:123,132,213,231,321
3、l不可能出栈顺序:不可能出栈顺序:312 栈的抽象数据类型栈的抽象数据类型lADT Stack lData:含有:含有n个元素个元素a1,a2,a3,an,按,按LIFO规则存放,每个元素的类型规则存放,每个元素的类型都为都为ElemType。lOperation: lvoid InitStack(Stack &s); /初始化栈初始化栈slvoid DestroyStack(Stack &s) /销毁栈销毁栈s lvoid ClearStack(Stack &s); /清除栈清除栈s的所有元素,使之成为空栈的所有元素,使之成为空栈lbool StackEmpty (S
4、tack s); /判断栈判断栈s是否为空,若是则返回是否为空,若是则返回true,否,否则返回则返回false lint StackLength(Stack s) /获取栈获取栈s中元素的个数中元素的个数lSElemType Peek(Stack s); /返回栈顶元素,但不移动栈顶指针返回栈顶元素,但不移动栈顶指针lvoid Push(Stack& s,const SElemType& e); /元素元素e进栈,插入到栈顶进栈,插入到栈顶lSElemType Pop(Stack& s); /删除栈顶元素并返回之删除栈顶元素并返回之lvoid StackTravers
5、e(SqStack s,void (*visit)(SElemType) /遍历栈遍历栈slend Stack3.1.2 栈的表示和实现栈的表示和实现3.1.2.1 顺序栈顺序栈-栈的顺序存储结构栈的顺序存储结构l和线性表类似,栈也有两种存储表示,其顺和线性表类似,栈也有两种存储表示,其顺序存储结构简称为序存储结构简称为。顺序栈的定义:顺序栈的定义:sqstack.h (泛型编程)(泛型编程)lconst int STACK_INIT_SIZE=100; /初始存储空间大小初始存储空间大小lconst int STACKINCREMENT=50; /存储空间分配增量存储空间分配增量ltempl
6、atelstruct SqStackll SElemType *base; /栈底指针栈底指针l SElemType *top; /栈顶指针栈顶指针l int stacksize; /栈存储空间的大小栈存储空间的大小l;ls.base 始终指向栈底始终指向栈底ls.base=NULL 表示栈结构不存在表示栈结构不存在ls.top=s.base 表示栈空表示栈空ls.top 始终指向栈顶元素的下一个位置始终指向栈顶元素的下一个位置顺序栈基本操作的实现:顺序栈基本操作的实现:sqstack.htemplatevoid InitStack(SqStack &s) /构造一个空栈构造一个空栈s
7、 s.base=new SElemTypeSTACK_INIT_SIZE; if(!s.base) exit(-1); /存储分配失败存储分配失败 s.top=s.base; /栈为空栈为空 s.stacksize=STACK_INIT_SIZE;templatevoid DestroyStack(SqStack &s) /销毁栈销毁栈s delete s.base; s.base=s.top=NULL; s.stacksize=0;templatevoid ClearStack(SqStack &s) /清空栈清空栈s s.top=s.base;templatebool St
8、ackEmpty(SqStack s) return s.top=s.base;templateint StackLength(SqStack s) /返回返回s中元素个数中元素个数 return s.top-s.base;templateSElemType Peek(SqStack s) /读取栈顶元素读取栈顶元素 if (s.top=s.base) cerrStack is empty!endl; exit(-1); /栈为空,获取失败栈为空,获取失败 return *(s.top-1);templatevoid Push(SqStack &s,SElemType e) if (s
9、.top-s.base=s.stacksize) SElemType *p=new SElemTypes.stacksize+STACKINCREMENT; if(!p) exit(1); /存储分配失败存储分配失败 for(int i=0;is.stacksize;i+) pi=s.basei; delete s.base; /释放原空间释放原空间 s.base=p; s.top=s.base+s.stacksize; s.stacksize+=STACKINCREMENT; *s.top+=e;templateSElemType Pop(SqStack &s) if (s.top=
10、s.base) cerrStack is empty!endl; exit(-1); /栈为空,获取失败栈为空,获取失败 return *-s.top; /返回栈顶元素返回栈顶元素templatevoid StackTraverse(SqStack s, void (*visit)(SElemType) for(SElemType *p=s.base; ps.top; p+) visit(*p);3.1.2.2 栈的链接存储结构栈的链接存储结构-链栈链栈 (Linked-stack)l栈的链式存贮结构,也称为链栈,它是一种限制运栈的链式存贮结构,也称为链栈,它是一种限制运算的链表,即规定链表中
11、的插入和删除运算只能在算的链表,即规定链表中的插入和删除运算只能在链表链表进行。链栈结构见下图进行。链栈结构见下图注: 只能在链表头部进行操作 表示同线性表 头指针-栈顶指针链栈的结构可用链栈的结构可用C+语言定义如下:语言定义如下:lstruct LNodel SElemType data;l Lnode * next; l;lLNode *top;3.2 栈的应用举例栈的应用举例l由于栈的操作具有后进先出的固有特性,致由于栈的操作具有后进先出的固有特性,致使栈成为程序设计中的有用工具。凡应用问使栈成为程序设计中的有用工具。凡应用问题求解的过程具有题求解的过程具有后进先出后进先出的天然特性的
12、的天然特性的话,则求解的算法中也必然需要利用话,则求解的算法中也必然需要利用栈栈。3.2.1 数制转换数制转换l假设要将十进制数假设要将十进制数n转换为转换为d进制数:(如进制数:(如8进制)进制)转换结果:2504 问题很明确,就是要输出计算过程中所得到的各个八进制数位。然而这八进制的各个数位产生的顺序是从低位到高位的,而打印输出的顺序,一般来说应从高位到低位,这恰好和计算过程相反。因此,需要先保存在计算过程中得到的八进制数的各位,然后逆序输出,因为它是按后进先出的规律进行的,所以用栈最合适。/将将10进制数进制数n转成转成r进制数进制数void Conversion(int n, int
13、r) SqStack s; /定义栈定义栈s InitStack(s); /初始化栈初始化栈s while (n) /只要只要n不为不为0,n除基数除基数 Push(s, n%r); /余数入栈余数入栈 n=n/r; /n取整数部分取整数部分 while (!StackEmpty(s) /栈不为空,出栈栈不为空,出栈 coutPop(s); coutendl;3.2.2 括号匹配问题括号匹配问题l假设表达式中允许包含两种括号:圆括号和假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,如方括号,其嵌套的顺序随意,如( ( ) )或或 ( ) 等为正确的匹配,等为正确的匹配, ( )
14、或或( ( )或或 ( ( ) ) )均为错误的匹配。均为错误的匹配。l现在的问题是,要求检验一个给定表达式中现在的问题是,要求检验一个给定表达式中的括弧是否正确匹配?的括弧是否正确匹配?l检验括号是否匹配的方法可用检验括号是否匹配的方法可用期待的急迫程期待的急迫程度度这个概念来描述。即后出现的这个概念来描述。即后出现的左括弧左括弧,它等待与其匹配的它等待与其匹配的右括弧右括弧出现的出现的急迫急迫心心情要比先出现的左括弧高。情要比先出现的左括弧高。l在检验算法中可设置一个栈,每读入一个括号:在检验算法中可设置一个栈,每读入一个括号:l若是左括号,则直接入栈,等待相匹配的同类右若是左括号,则直接
15、入栈,等待相匹配的同类右括号;括号;l若读入的是右括号,且与当前栈顶的左括号同类若读入的是右括号,且与当前栈顶的左括号同类型,如二者匹配,则将栈顶的左括号出栈;否则属型,如二者匹配,则将栈顶的左括号出栈;否则属于不合法的情况;于不合法的情况;l如果输入序列已读尽,而栈中仍有等待匹配的左如果输入序列已读尽,而栈中仍有等待匹配的左括号,不合法;括号,不合法;l读入了一个右括号,而栈中已无等待匹配的左括读入了一个右括号,而栈中已无等待匹配的左括号,不合法。号,不合法。bool BracketsCheck(char* c) ; InitStack(s); for (int i=0; ci!=0; i+
16、) switch (ci) case : case (: Push(s,ci); break; case : if (Peek(s)=) Pop(s); else return false; break; case ): if (Peek(s)=() Pop(s); else return false; break; if (StackEmpty(s) return true; else return false;3.2.3 迷宫(迷宫(Maze)求解)求解l一个迷宫包含有一个迷宫包含有m行行n列个小方格,每个方格用列个小方格,每个方格用1表示可通行,用表示可通行,用0表示墙壁,即不可通行,迷
17、宫中通表示墙壁,即不可通行,迷宫中通常有一个入口和一个出口。求解迷宫问题是从入口常有一个入口和一个出口。求解迷宫问题是从入口点出发寻找一条通向出口点的路径,并输出这条路点出发寻找一条通向出口点的路径,并输出这条路径。径。12345110010211101301011411010501110l计算机解迷宫问题时,通常用的是计算机解迷宫问题时,通常用的是穷举求解穷举求解法:法: 从入口出发,顺某一方向向前搜索,若能走通,从入口出发,顺某一方向向前搜索,若能走通,则继续往前走,否则则继续往前走,否则,换一个方向再,换一个方向再继续搜索,直至所有可能的通路都探索到为止。继续搜索,直至所有可能的通路都探
18、索到为止。l在一个迷宫中,中间的每个方格位置都有四个可选择的移动在一个迷宫中,中间的每个方格位置都有四个可选择的移动方向,而在四个顶点只有两个方向,并且每个顶点的两个方方向,而在四个顶点只有两个方向,并且每个顶点的两个方向均有差别,每条边线上除顶点外的每个位置只有三个方向,向均有差别,每条边线上除顶点外的每个位置只有三个方向,并且也有差别。并且也有差别。,如图(,如图(b)所示。)所示。012345600000000101001002011101030010110401101005001110060000000l当从迷宫中的一个位置(称之为当前位置)当从迷宫中的一个位置(称之为当前位置)前进到
19、下一个位置时,下一个位置相对于当前进到下一个位置时,下一个位置相对于当前位置的位移量(包括行位移量和列位移量)前位置的位移量(包括行位移量和列位移量)随着前进的方向的不同而不同,东、南、西、随着前进的方向的不同而不同,东、南、西、北(即右、下、左、上)各方向的位移量依北(即右、下、左、上)各方向的位移量依次为(次为(0,1)、()、(1,0)、()、(0,-1)和()和(-1,0)。)。l为了寻找从入口点到出口点的一条通路,首先从入为了寻找从入口点到出口点的一条通路,首先从入口点出发,按照口点出发,按照东南西北东南西北各方向的次序试探前进,各方向的次序试探前进,若向东可通行,若向东可通行,则向
20、东前进一,则向东前进一个方格;否则表明向东没有通向出口的路径,接着个方格;否则表明向东没有通向出口的路径,接着向南方向试着前进,若向南可通行同时没有被访问向南方向试着前进,若向南可通行同时没有被访问过,应向南前进一步;否则依次向西和向北试探。过,应向南前进一步;否则依次向西和向北试探。若试探完当前位置上的所有方向后都没有通路,则若试探完当前位置上的所有方向后都没有通路,则应退回一步,从到达当前位置的下一个方向试探着应退回一步,从到达当前位置的下一个方向试探着前进。因此每前进一步都前进。因此每前进一步都要记录其上一步的坐标位要记录其上一步的坐标位置以及前进到此步的方向置以及前进到此步的方向,以便
21、退回之用。这正好,以便退回之用。这正好需要用栈来解决。需要用栈来解决。l算法见教材算法见教材P51。main.cpp#include #include #include sqstack.hconst int MAXLENGTH=25; / 设迷宫的最大行列为设迷宫的最大行列为25typedef int MazeTypeMAXLENGTHMAXLENGTH; / 迷宫迷宫数组数组行行列列struct PosType / 迷宫坐标位置类型迷宫坐标位置类型 int x; / 行值行值 int y; / 列值列值;struct Elem / 栈的元素类型栈的元素类型 int ord; / 通道块在路径
22、上的序号通道块在路径上的序号PosType seat; / 通道块在迷宫中的坐标位置通道块在迷宫中的坐标位置int di; / 从此通道块走向下一通道块的方向从此通道块走向下一通道块的方向(03表示东北表示东北);MazeType m; / 迷宫数组迷宫数组int curstep=1; / 当前足迹当前足迹,初值为初值为1/ 定义墙元素值为定义墙元素值为0,可通过路径为可通过路径为1,不能通过路径为不能通过路径为-1,通过路通过路径为足迹径为足迹bool Pass(PosType b) / 当迷宫当迷宫m的的b点的序号为点的序号为1(可通过路径可通过路径),返回,返回 true /否则,返回否
23、则,返回false if(mb.xb.y=1)return true;elsereturn false;void FootPrint(PosType a) / 使迷宫使迷宫m的的a点的序号变为足迹点的序号变为足迹(curstep)ma.xa.y=curstep; / 根据当前位置及移动方向,返回下一位置根据当前位置及移动方向,返回下一位置PosType NextPos(PosType c, int di)PosType direc4=0,1,1,0,0,-1,-1,0; / 行增量行增量,列增量列增量/ 移动方向移动方向,依次为东南西北依次为东南西北c.x+=direcdi.x;c.y+=di
24、recdi.y;return c;/ 使迷宫使迷宫m的的b点的序号变为点的序号变为-1(不能通过的路径不能通过的路径)void MarkPrint(PosType b) mb.xb.y=-1;bool MazePath(PosType start,PosType end) /若迷宫若迷宫maze中存在从入口中存在从入口start到出口到出口end的通道,则求得一条的通道,则求得一条 /存放在栈中存放在栈中(从栈底到栈顶从栈底到栈顶),并返回,并返回TRUE;否则返回;否则返回FALSE SqStack s; InitStack(s); PosType curpos; /当前位置变量当前位置变量
25、 Elem e; curpos=start; /当前位置为开始点当前位置为开始点doif(Pass(curpos) / 当前位置可以通过,即是未曾走到过的通道块当前位置可以通过,即是未曾走到过的通道块 FootPrint(curpos); / 留下足迹留下足迹/构建表示当前位置的入栈元素构建表示当前位置的入栈元素Push(s,e); / 入栈当前位置及状态入栈当前位置及状态curstep+; / 足迹加足迹加1if(curpos.x=end.x&curpos.y=end.y) / 到达终点到达终点 return true;curpos=NextPos(curpos, e.di); /向
26、前走一步向前走一步else / 当前位置不能通过当前位置不能通过 if (!StackEmpty(s)e=Pop(s); / 退栈到前一位置退栈到前一位置curstep-;while(e.di=3&!StackEmpty(s) / 前一位置处于最后一个方向前一位置处于最后一个方向 MarkPrint(e.seat); / 留下不能通过的标记留下不能通过的标记(-1)e=Pop(s); / 退回一步退回一步curstep-;if(e.di3) / 没到最后一个方向没到最后一个方向(北北)e.di+; / 换下一个方向探索换下一个方向探索Push(s,e);curstep+;curpos=
27、NextPos(e.seat, e.di); while(!StackEmpty(s);return false;void Print(int x,int y) / 输出迷宫的解输出迷宫的解 for(int i=0;ix;i+)for(int j=0;jy;j+)coutsetw(3)mij;coutendl;int main()PosType begin,end;begin.x=1;begin.y=1;end.x=6;end.y=8;ifstream infile; /定义文件输入流对象定义文件输入流对象infile.open(data.txt); /打开文件打开文件for(int i=0;
28、i8;i+) /读入迷宫数组读入迷宫数组for(int j=0;jmij;infile.close(); /关闭文件关闭文件cout迷宫结构如下迷宫结构如下:n;Print(m); if(MazePath(begin,end) / 求得一条通路求得一条通路 cout此迷宫从入口到出口的一条路径如下此迷宫从入口到出口的一条路径如下:n;Print(m); / 输出此通路输出此通路elsecout此迷宫没有从入口到出口的路径此迷宫没有从入口到出口的路径n;3.2.4 表达式求值表达式求值l程序设计语言中都有计算表达式的问题,这程序设计语言中都有计算表达式的问题,这是语言编译中的典型问题,是栈的典型
29、应用是语言编译中的典型问题,是栈的典型应用实例。实例。3.2.4.1 算术表达式的两种表示算术表达式的两种表示l通常书写的算术表达式是由操作数(又叫运通常书写的算术表达式是由操作数(又叫运算对象或运算量)和运算符以及改变运算次算对象或运算量)和运算符以及改变运算次序的圆括号连接而成。如序的圆括号连接而成。如l16-9*(4+3)l这种算术表达式称为这种算术表达式称为。在中缀表。在中缀表达式的计算过程中,即要考虑括号的作用,达式的计算过程中,即要考虑括号的作用,又要考虑运算符的优先级,还要考虑运算符又要考虑运算符的优先级,还要考虑运算符出现的先后次序,用计算机来处理非常困难。出现的先后次序,用计
30、算机来处理非常困难。l波兰科学家谢维奇提出了算术表达式的另一种表示,波兰科学家谢维奇提出了算术表达式的另一种表示,即后缀表示,又称逆波兰式,其定义是把运算符放即后缀表示,又称逆波兰式,其定义是把运算符放在两个运算对象的后面。采用后缀表示的算术表达在两个运算对象的后面。采用后缀表示的算术表达式称为式称为后缀表达式后缀表达式。如。如l16 9 4 3 + * -l在后缀表达式中,不存在括号,也不存在优先级的在后缀表达式中,不存在括号,也不存在优先级的差别,计算过程完全差别,计算过程完全进进行,整个计算过程仅需一遍便可完成,显然比中缀行,整个计算过程仅需一遍便可完成,显然比中缀表达式的计算要简单得多
31、。表达式的计算要简单得多。3.2.4.2 把中缀表达式转换为后缀表达式把中缀表达式转换为后缀表达式l设以设以字符作为结束的中缀表达式保存在字符作为结束的中缀表达式保存在s1字符串中,转换后得到的后缀表达式拟存于字符串中,转换后得到的后缀表达式拟存于s2字符串中。字符串中。l由中缀表达式转换为后缀表达式的规则可知:由中缀表达式转换为后缀表达式的规则可知:转换前后,转换前后,表达式中的数值项的次序不变表达式中的数值项的次序不变,而而运算符的次序发生了变化运算符的次序发生了变化,由处在两个运,由处在两个运算对象的中间变为处在两个运算对象的后面,算对象的中间变为处在两个运算对象的后面,同时去掉了所有的
32、括号。同时去掉了所有的括号。l为了使转换正确,必须设定一个运算符栈,为了使转换正确,必须设定一个运算符栈,并在栈底放入一个特殊运算符,假定为并在栈底放入一个特殊运算符,假定为字字符,让它具有符,让它具有最低的运算符优先级最低的运算符优先级,假定数,假定数值为值为0。此栈用来保存扫描中中缀表达式得到。此栈用来保存扫描中中缀表达式得到的暂不能放入后缀表达式中的运算符,待它的暂不能放入后缀表达式中的运算符,待它的两个运算符对象都放入到后缀表达式以后,的两个运算符对象都放入到后缀表达式以后,再令其出栈并写入到后缀表达式中。再令其出栈并写入到后缀表达式中。算法的基本思路:算法的基本思路:l从头到尾地扫描
33、中缀表达式中的每个字符,不同的从头到尾地扫描中缀表达式中的每个字符,不同的类型的字符按不同的情况处理。类型的字符按不同的情况处理。若遇到的是空格,则认为是分隔符,不需要进行若遇到的是空格,则认为是分隔符,不需要进行处理;处理;若遇到的是数字或小数点,则直接写入若遇到的是数字或小数点,则直接写入s2中,并中,并在每个数值最后写入一个空格;在每个数值最后写入一个空格; 若遇到的是左括号,则应把它压入到运算符栈中,若遇到的是左括号,则应把它压入到运算符栈中,待以它开始的括号内的表达式转换完毕后再出栈;待以它开始的括号内的表达式转换完毕后再出栈;若遇到的是右括号,则表明括号内的中缀表达式若遇到的是右括
34、号,则表明括号内的中缀表达式已经扫描完毕,把从栈顶直到保存着的对应左括号已经扫描完毕,把从栈顶直到保存着的对应左括号之间的运算符依次退栈并写入之间的运算符依次退栈并写入s2串中;串中;若遇到的是运算符:若遇到的是运算符: a. 当该运算符的优先级大于栈顶运算符的优先级时,表明当该运算符的优先级大于栈顶运算符的优先级时,表明该运算符的后一个运算对象还没有被放入到该运算符的后一个运算对象还没有被放入到s2串中,应把它串中,应把它暂存于运算栈中;暂存于运算栈中; b. 当该运算符的优先级小于栈顶运算符的优先级时,表明当该运算符的优先级小于栈顶运算符的优先级时,表明栈顶运算符的两个运算对象已经被保存到
35、栈顶运算符的两个运算对象已经被保存到s2串中,应将栈顶串中,应将栈顶运算符退栈并写入到运算符退栈并写入到s2串中,对于新的栈顶运算符仍继续进串中,对于新的栈顶运算符仍继续进行比较和处理,直到被处理的运算符的优先级大于栈顶运算行比较和处理,直到被处理的运算符的优先级大于栈顶运算符的优先级为止,然后令该运算符进栈即可。符的优先级为止,然后令该运算符进栈即可。l按照以上过程扫描到中缀表达式结束符按照以上过程扫描到中缀表达式结束符时,把栈中剩余时,把栈中剩余的运算符依次退栈并写入到后缀表达式中,再向的运算符依次退栈并写入到后缀表达式中,再向s2写入表达写入表达式结束符式结束符和字符串结束符和字符串结束
36、符0,整个转换过程就处理完毕,整个转换过程就处理完毕,在在s2中就得到了转换成的后缀表达式。中就得到了转换成的后缀表达式。change.cpp#include sqstack.hint Precede(char op) /获取运算符的优先级获取运算符的优先级 switch (op) case +: case -: return 1; case *: case /: return 2; case (: case : default: return 0; void Change(char* s1,char* s2) /将字符串将字符串s1中的中缀表达式转换为存于中的中缀表达式转换为存于s2中的后缀
37、表达式中的后缀表达式 SqStack r; InitStack(r); /初始化栈初始化栈 Push(r,); /给栈底放入给栈底放入字符,它具有最低优先级字符,它具有最低优先级 int i, j; i=0; j=0; char ch=s1i; while (ch!=) if (ch= ) ch=s1+i; else if (ch=() Push(r,ch); ch=s1+i; else if (ch=) while (Peek(r)!=() s2j+=Pop(r); Pop(r); ch=s1+i; else if (ch=+|ch=-|ch=*|ch=/) char w=Peek(r);
38、while (Precede(w)=Precede(ch) s2j+=w; Pop(r); w=Peek(r); Push(r,ch); ch=s1+i; else while (isdigit(ch)|ch=.) s2j+=ch; ch=s1+i; s2j+= ; ch=Pop(r); while (ch!=) if (ch=() cerrexpression error!endl; exit(-1); else s2j+=ch; ch=Pop(r); s2j+=; s2j+=0;3.2.4.3 后缀表达式求值后缀表达式求值l后缀表达式的求值比较简单,扫描一遍即可后缀表达式的求值比较简单,扫
39、描一遍即可完成。它需要使用一个栈,用以存储后缀表完成。它需要使用一个栈,用以存储后缀表达式中的操作数、计算的中间结果以及最后达式中的操作数、计算的中间结果以及最后结果。结果。l假定一个后缀表达式以字符假定一个后缀表达式以字符作为结束符,作为结束符,并且以字符串方式提供。并且以字符串方式提供。后缀表达式求值算法的基本思路:后缀表达式求值算法的基本思路:l把包含后缀表达式的字符串定义为一个输入字符把包含后缀表达式的字符串定义为一个输入字符串流对象,每次从中读入一个字符时,若它是串流对象,每次从中读入一个字符时,若它是运算运算符符,则表明它的两个操作数已经在栈中,把它们弹,则表明它的两个操作数已经在
40、栈中,把它们弹出后进行运算即可,然后把运算结果再压入栈中;出后进行运算即可,然后把运算结果再压入栈中;l否则,读入的字符必为否则,读入的字符必为操作数操作数的最高位数字,应的最高位数字,应把它重新送回输入流中,然后把下一个数据作为浮把它重新送回输入流中,然后把下一个数据作为浮点数输入,并把它压入到栈中;点数输入,并把它压入到栈中;l依次扫描每一个字符并进行上述处理,直到遇到依次扫描每一个字符并进行上述处理,直到遇到结束符结束符为止,表明后缀表达式计算完毕,最终结为止,表明后缀表达式计算完毕,最终结果保存在栈中,并且栈中仅存一个值,把它弹出返果保存在栈中,并且栈中仅存一个值,把它弹出返回即可。回
41、即可。compute.cpp#include sqstack.h#include double Compute(char* str) SqStack s; InitStack(s); istringstream ins(str); /把把str定义为定义为string流对象流对象ins,P82 char ch; /用于输入字符用于输入字符 double x; /用于输入浮点数用于输入浮点数 insch; while (ch!=) switch (ch) case +: x=Pop(s)+Pop(s); break; case -: x=Pop(s); /Pop(s)弹出减数弹出减数 x=Pop
42、(s)-x; /Pop(s)弹出被减数弹出被减数 break; case *: x=Pop(s)*Pop(s); break; case /: x=Pop(s); if (x!=0.0) x=Pop(s)/x; cerrDivide by 0!x; /从字符串输入流中读入一个浮点数从字符串输入流中读入一个浮点数 Push(s,x); /把读入的数或进行相应运算的结果压入到把读入的数或进行相应运算的结果压入到s栈中栈中 insch; if (!StackEmpty(s) x=Pop(s); if (StackEmpty(s) return x; else cerrexpression error
43、!endl; exit(-1); else cerrStack is emppty!endl; exit(-1); main.cpp#include #include sqstack.husing namespace std;int Precede(char op);void Change(char* s1,char* s2);double Compute(char* str);int main() char s1=34*(2+5)+3; char s230; Change(s1,s2); couts2endl; double r=Compute(s2); coutr0实现递归调用,由实现递归
44、调用,由n的值乘以的值乘以f(n-1)的返的返回值求出回值求出f(n)。10( )(1)0nf nn f nnl用用C+语言编写出求解语言编写出求解n!的递归函数为:的递归函数为:long Fun(int n)if(n=0)return 1;elsereturn n*Fun(n-1);l在计算机系统内,执行递归函数是通过在计算机系统内,执行递归函数是通过栈栈来实现的,来实现的,栈中的每个元素包含有递归函数的每个栈中的每个元素包含有递归函数的每个参数域参数域、每、每个个局部变量域局部变量域和调用后的和调用后的返回地址域返回地址域。每次进行函。每次进行函数调用时,都把相应的值压入栈。每次调用结束时
45、,数调用时,都把相应的值压入栈。每次调用结束时,都按照本次返回地址返回到指定位置执行,并且自都按照本次返回地址返回到指定位置执行,并且自动作一次退栈操作,使得上一次调用所使用的参数动作一次退栈操作,使得上一次调用所使用的参数成为新的栈顶,继续被使用。成为新的栈顶,继续被使用。l栈和递归是可以相互转换的,当编写递归算法时,栈和递归是可以相互转换的,当编写递归算法时,虽然表面上没有使用栈,但系统执行时会虽然表面上没有使用栈,但系统执行时会自动自动建立建立和使用栈。和使用栈。l求解迷宫问题也是一个递归问题,适合采用递归算求解迷宫问题也是一个递归问题,适合采用递归算法来解决。法来解决。若迷宫中的当前位
46、置(初始上入口点)就是出口位若迷宫中的当前位置(初始上入口点)就是出口位置,则表示找到了通向出口的一条路径,应返回置,则表示找到了通向出口的一条路径,应返回true;若从当前位置按东、南、西、北方向的次序前进到若从当前位置按东、南、西、北方向的次序前进到下一个位置,该位置可通行且没有被访问过,则以该下一个位置,该位置可通行且没有被访问过,则以该位置为参数进行递归调用,若返回位置为参数进行递归调用,若返回true的话,表明从的话,表明从该位置到出口点有通路,标记该位置后向上一个位置该位置到出口点有通路,标记该位置后向上一个位置返回返回true,结束递归。,结束递归。若当前位置上的所有方向都试探完
47、毕,表明从当前若当前位置上的所有方向都试探完毕,表明从当前位置出发没有寻找到通向出口点的路径,返回位置出发没有寻找到通向出口点的路径,返回false结结束递归。束递归。#include #include #include using namespace std;const int MAXLENGTH=25; / 设迷宫的最大行列为设迷宫的最大行列为25typedef int MazeTypeMAXLENGTHMAXLENGTH; / 迷宫数组迷宫数组行行列列struct PosType / 迷宫坐标位置类型迷宫坐标位置类型 int x; / 行值行值int y; / 列值列值;struct E
48、lem / 元素类型元素类型 int ord; / 通道块在路径上的序号通道块在路径上的序号PosType seat; / 通道块在迷宫中的坐标位置通道块在迷宫中的坐标位置int di; / 从此通道块走向下一通道块的方向从此通道块走向下一通道块的方向(03表示东北表示东北);MazeType m; / 迷宫数组迷宫数组int curstep=0; / 当前足迹当前足迹,初值为初值为1 / 定义墙元素值为定义墙元素值为0,可通过路径为可通过路径为1,不能通过路径为不能通过路径为-1,通过路径为足迹通过路径为足迹bool Pass(PosType b) / 当迷宫当迷宫m的的b点的序号为点的序号
49、为1(可通过路径可通过路径),返回,返回 true; 否则,返回否则,返回 false。if(mb.xb.y=1)return true;elsereturn false;void FootPrint(PosType a) / 使迷宫使迷宫m的的a点的序号变为足迹点的序号变为足迹(curstep)ma.xa.y=curstep; / 根据当前位置及移动方向,返回下一位置根据当前位置及移动方向,返回下一位置PosType NextPos(PosType c,int di)PosType direc4=0,1,1,0,0,-1,-1,0; / 行增量行增量,列增量列增量/ 移动方向移动方向,依次为
50、东南西北依次为东南西北c.x+=direcdi.x;c.y+=direcdi.y;return c;/ 使迷宫使迷宫m的的b点的序号变为点的序号变为-1(不能通过的路径不能通过的路径)void MarkPrint(PosType b)mb.xb.y=-1;void Print(int x,int y) / 输出迷宫的解输出迷宫的解 for(int i=0;ix;i+)for(int j=0;jy;j+)coutsetw(3)mij;coutendl;lbool MazePath(PosType curpos,PosType end) l/若存在从当前位置到出口若存在从当前位置到出口end的通道
51、,则返回的通道,则返回true;否则返回;否则返回falselif(curpos.x=end.x&curpos.y=end.y) / 到达终点到达终点(出口出口)lreturn true;lPosType nextpos;lfor(int i=0;i4;+i)lnextpos=NextPos(curpos,i);lif(Pass(nextpos)lMarkPrint(nextpos); /标记不通(标记不通(-1)lif(MazePath(nextpos,end)lcurstep+; / 足迹加足迹加1lFootPrint(nextpos); /标记足迹标记足迹lreturn true
52、;llllreturn false;lint main()PosType begin,end;int x=8,y=10;begin.x=1;begin.y=1;end.x=6;end.y=8;ifstream infile;infile.open(data.txt); /打开文件打开文件for(int i=0;i8;i+)for(int j=0;jmij;infile.close(); /关闭文件关闭文件if(MazePath(begin,end) / 求得一条通路求得一条通路 cout此迷宫从入口到出口的一条路径如下此迷宫从入口到出口的一条路径如下:n;Print(x,y); / 输出此通路
53、输出此通路elsecout此迷宫没有从入口到出口的路径此迷宫没有从入口到出口的路径n;3.4 队列队列3.4.1 抽象数据类型队列的定义抽象数据类型队列的定义l仅允许在一端进行插入,另一端进行删除的线性表,仅允许在一端进行插入,另一端进行删除的线性表,称为队列称为队列(queue)。允许插入的一端称为。允许插入的一端称为队尾队尾(rear),允许删除的一端称为允许删除的一端称为队头队头(front)。)。队列是一种先进先出(First In First Out)的特殊线性表,或称FIFO表。若队列中没有任何元素,则称为空队列,否则称为非空队列。l例:购物排队例:购物排队 -新来的成员总是加入队
54、尾(不允新来的成员总是加入队尾(不允许许加塞加塞),每次离开的成员总是队列头上的(不),每次离开的成员总是队列头上的(不允许中途离队)。允许中途离队)。l例:解决主机与外部设备之间速度不匹配问题。例:解决主机与外部设备之间速度不匹配问题。l例:操作系统中资源竞争。例:操作系统中资源竞争。队列的抽象数据类型定义如下:队列的抽象数据类型定义如下:lADT Queue islData: 采用顺序或链接方式存储的队列,假定其存储类型用采用顺序或链接方式存储的队列,假定其存储类型用QueueType表示。表示。lOperation:lvoid InitQueue(QueueType &q); /
55、初始化队列初始化队列q,置为空,置为空lvoid DestroyQueue(QueueType &q);/销毁队列销毁队列q,不再存在,不再存在lvoid ClearQueue(QueueType &q); /清空队列清空队列lbool QueueEmpty (QueueType q); /若若q为空返回为空返回true,否则返回,否则返回falselint QueueLength (QueueType q); /返回队列返回队列q的长度的长度lElemType GetHead(QueueType q); /返回返回q的队头元素的队头元素lvoid EnQueue (Queue
56、Type &q,ElemType e); /在在q的队尾插入元素的队尾插入元素elElemType DeQueue (QueueType &q); /删除队头元素,并将之返回删除队头元素,并将之返回lvoid QueueTraverse (QueueType q,void (*visit)(ElemType);/从队头到队尾,依次对每个元素调用函数从队头到队尾,依次对每个元素调用函数visit()3.4.2 链队列队列的链式表示和实现链队列队列的链式表示和实现l用链表表示的队列称为用链表表示的队列称为链队列链队列,一个链队列,一个链队列需要两个分别指示需要两个分别指示队头队头和
57、和队尾队尾的的指针指针才能唯才能唯一确定。为操作方便,可给链队列添加一个一确定。为操作方便,可给链队列添加一个头结点头结点并令并令头指针指向头结点头指针指向头结点。由此,。由此,空的空的链队列的判决条件为头指针和尾指针均指向链队列的判决条件为头指针和尾指针均指向头结点。头结点。插入元素删除元素删除最后一个元素链队列的实现如下:链队列的实现如下:linkqueue.hl#include l#include lusing namespace std;lstruct QElemTypell int d;l;lstruct QNodell QElemType data;l QNode *next;l;
58、ltypedef QNode *QNodePtr;lstruct LinkQueuell QNodePtr front;l QNodePtr rear;l;void InitQueue(LinkQueue &q);void DestroyQueue(LinkQueue &q);void ClearQueue(LinkQueue &q);bool QueueEmpty(LinkQueue q);int QueueLength(LinkQueue q);QElemType GetHead(LinkQueue q);void EnQueue(LinkQueue &q,
59、 QElemType e);QElemType DeQueue(LinkQueue &q);void QueueTraverse(LinkQueue q,void (*visit)(QElemType);linkqueue.cppl#include linkqueue.hlvoid InitQueue(LinkQueue &q)ll q.front=q.rear=new QNode;l if (!q.front)l exit(1);l q.front-next=NULL;llvoid DestroyQueue(LinkQueue &q)ll while (q.front
60、)l l q.rear=q.front-next;l delete q.front;l q.front=q.rear;l llvoid ClearQueue(LinkQueue &q)ll QNodePtr p=q.front-next;l while (p)l l q.rear=p-next;l delete p;l p=q.rear;l llbool QueueEmpty(LinkQueue q)ll return q.front=q.rear;llint QueueLength(LinkQueue q)ll int n=0;l QNodePtr p=q.front-next;l while (p)l l +n;l p=p-next;l l return n;llQElemType GetHead(LinkQueue q)ll if (q.front=q.rear)l l cerrQueue is empty!next-data;llv
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 节前安全生产会议工作简报
- 四年级语文现代诗教学全案
- 节日主题儿童手工制作活动方案
- 护士站日常管理工作流程及岗位职责
- 物业管理自查检查标准模板
- 中医基础气血调理知识普及
- 小学五年级英语阶段性考试试题解析
- 2025中国新材料产业发展趋势分析及市场潜力与投资策略研究报告
- 2025中国教育神经科学行业市场技术突破及投资战略规划报告
- 2025中国教育机器人行业市场现状及未来发展趋势报告
- 建设工程企业资质管理规定2025
- 2025年全国消防安全知识竞赛题库及答案(完整版)
- 慢性肾脏病高磷血症临床管理中国专家共识(2025版)解读
- 2025年高速公路收费站车辆通行费收费员岗位职业技能资格知识考试笔试试题(含答案)
- 人才培养方案答辩汇报
- 2024年9月电工三级试题与答案
- 光大信用卡逾期协议书
- 2025及未来5年中国花卉肥市场调查、数据监测研究报告
- 2025福建漳州市龙海区嘉达出行服务有限公司劳务外包人员招聘10人考试参考题库及答案解析
- 2025年供水知识竞赛题库含答案
- SF-36健康调查简表标准化操作手册(2025年更新版)
评论
0/150
提交评论