1、数据结构实例精讲栈数据结构实例精讲:栈栈和队列是两种特殊的线性表,它们的逻辑结构和线性表相同,只是其运算规则较线性表有更多的限制,故又称它们为运算受限的线性表。3.1 栈的定义和基本运算实现栈是一种特殊的线性表,是一种只允许在表的一端进行插入或删除操作的线性表。表中允许进行插入、删除操作的一端称为栈顶。表的另一端称为栈底。栈顶的当前位置是动态的,对栈顶当前位置的标记称为栈顶指针。当栈中没有数据元素时,称之为空栈。栈的插入操作通常称为进栈或入栈,栈的删除操作通常称为退栈或出栈。在生活中我们常见到这样的例子:假设餐厅里有一叠盘子,如果我们要从中拿取盘子,只能从最上面一个开始拿,当我们要再放上一个盘
2、子时也只能放在最上面。栈的结构正是如此。根据栈的定义,每次进栈的数据元素都放在原当前栈顶元素之前而成为新的栈顶元素,每次出栈的数据元素都是原当前栈顶元素。这样,最后进栈的数据元素总是最先出栈,因此,栈具有“后进先出”(LIFO:First In Last Out)的特性。栈的基本操作有:(1)InitStack(S): 构造一个空栈,即初始化一个栈。(2)StackEmpty(S):判栈空。若S为空栈,则返回True,否则返回false。(3)Push(S,X):进栈。若栈S不满,则将元素X插入S的栈顶。(4)Pop(S): 出栈。若栈S非空,则将S的栈顶元素删去。出栈时,可以返回栈顶元素,也
3、可以不返回栈顶元素。(5)GetTop(S):取栈顶元素。若栈S非空,则返回栈顶元素,但不改变栈的状态。图3-1是一个栈的动态示意图,图中箭头代表当前栈顶指针位置。(a)表示一个空栈;(b)表示插入一个数据元素 A以后的状态;(c)表示插入数据元素 B、C以后的状态;(d)表示删除数据元素 C以后的状态;(e)表示删除数据元素 B、A以后的状态。简言之,若进栈顺序为A、B、C,则退栈顺序为C、B、A。图3-1显示的是一个顺序存储结构的栈,栈也可以用链式存储结构存储。图3-1 栈的动态示意图栈的顺序存储结构简称为顺序栈,它是运算受限的顺序表。栈的链式存储结构称为链栈,它是运算受限的单链表,其插入
4、和删除操作仅限制在表头位置上进行。1顺序栈顺序栈是利用一组地址连续的存储单元依次存放从栈底到栈顶的若干数据元素。可以用一维数组来定义: #define MAXNUM; / 栈能存放的最大元素数 typedef struct ElemType dataMAXNUM;int top; SqStack ;其中,ElemType为栈的数据元素类型,top用来指示栈顶元素的当前位置。top = -1,表示栈空;top = MAXNUM-1,表示栈满。【实例3-1】顺序栈的基本操作实现。定义一个顺序栈,并实现其5个基本操作:初始化栈、判栈空、进栈、出栈、取栈顶元素。(1)问题分析。因为top指示栈顶元素的
5、当前位置,因此栈空时,top=-1。初始化空栈时,令top=-1即可。进栈(插入元素x为新的栈顶元素)的步骤为: 检查栈是否已满,若栈满,则进行“上溢”错误处理。 将栈顶指针上移一个位置(即加1),使之指向一个空闲单元。 将新元素赋值给栈顶单元。出栈(若栈不空,则删除S的栈顶元素)的步骤为: 检查栈是否为空,若栈空,则进行“下溢”错误处理。 将栈顶指针下移一个位置(即减1)。(2)源程序。#include using namespace std;#define MAXNUM 100 / 假定预分配的栈空间最多为100个元素 typedef int ElemType; / 假定栈元素的数据类型为
6、整型 typedef struct ElemType dataMAXNUM; int top;SqStack; void InitStack(SqStack &S) / 置栈空 S.top=-1; bool StackEmpty(SqStack S) / 判栈空 return S.top=-1;void Push(SqStack &S,ElemType x) / 入栈 if (S.top =MAXNUM-1) cout栈上溢endl; return; S.data+S.top=x; / 栈顶指针加1后将x入栈void Pop(SqStack &S) / 出栈,不返回栈顶元素 if(StackE
7、mpty(S) cout栈为空endl; / 下溢,退出 return; S.top-; / 将栈顶指针减1ElemType GetTop(SqStack S) / 取栈顶元素 if (StackEmpty(S) cout栈为空endl; / 下溢,退出运行 exit(1); return S.dataS.top;int main() SqStack s; InitStack(s); for(int i=1; i =10; i+ ) Push(s,i); while( !StackEmpty(s) cout GetTop(s) ; / 10 9 8 7 6 5 4 3 2 1 Pop(s);
8、coutendl; return 0; 当然,栈采用顺序存储时,也可以用动态数组来实现。请读者参看顺序表的基本操作实现。与顺序表不同的是,栈的操作受限。2链栈链栈是栈的链式存储实现,可以用单链表来定义:struct SNode ElemType data; struct SNode *next;typedef SNode *LinkStack;【实例3-2】链栈的基本操作实现。定义一个链栈,并实现其5个基本操作:初始化栈、判栈空、进栈、出栈、取栈顶元素。#include using namespace std;typedef int ElemType; / 假定栈元素的数据类型为整型 stru
9、ct SNode ElemType data; struct SNode *next;typedef SNode *LinkStack;void InitStack(LinkStack &S) / 置栈空 S=NULL; bool StackEmpty(LinkStack S) / 判栈空 return S=NULL;void Push(LinkStack &S,ElemType x) / 入栈 SNode *newnode; newnode=new SNode; if (newnode=NULL) cout存储分配失败!data=x; newnode-next=S; S=newnode; v
10、oid Pop(LinkStack &S) / 出栈,不返回栈顶元素 SNode *top; if(S!=NULL) top=S; S=S-next; delete top; else cout栈为空endl; / 下溢ElemType GetTop(LinkStack S) / 取栈顶元素 if (StackEmpty(S) cout栈为空data;int main() LinkStack s; InitStack(s); for(int i=1; i =10; i+ ) Push(s,i); while( !StackEmpty(s) cout GetTop(s) ; / 10 9 8 7
11、 6 5 4 3 2 1 Pop(s); coutendl; return 0;3.2 栈的应用栈的应用非常广泛,表达式求值、递归过程实现都是栈应用的典型例子。【实例3-3】数制转换。编写一个函数利用栈把一个十进制整数转换为二至十六之间的任一进制数。(1)问题分析。将十进制整数转换成R进制整数的规则是:将十进制整数不断除以R,记下余数,直至十进制整数为0,将所得的余数逆序排列,即是对应的R进制数。利用栈来保存除以R过程中得到的余数,除法过程结束后,依次将余数出栈,即得对应的R进制数。由于题目要求R为216,因此采用字符串来存储得到的R进制数。(2)函数程序代码。string Multibase
12、Output(int num, int n) / num为要转换的10进制数,n是转换为多少进制 string digitchar(“0123456789ABCDEF”); / 保存每位可能的字符 string strnum; SqStack stkchar; InitStack(stkchar); / 栈初始化 while(num!=0) Push(stkchar,digitcharnum%n); / 余数入栈 num/=n; while(!StackEmpty(stkchar) strnum+=GetTop(stkchar); / 余数出栈,加入到结果字符串中 Pop(stkchar);
13、return strnum; (3)函数应用的示例源程序。#include #include using namespace std;#define MAXNUM 100 / 假定预分配的栈空间最多为100个元素 typedef char ElemType; / 假定栈元素的数据类型为字符型 typedef struct ElemType dataMAXNUM; int top;SqStack; void InitStack(SqStack &S) / 置栈空 S.top=-1; bool StackEmpty(SqStack S) / 判栈空 return S.top=-1;void Pus
14、h(SqStack &S,ElemType x) / 入栈 if (S.top =MAXNUM-1) cout栈上溢endl; return; S.data+S.top=x; / 栈顶指针加1后将x入栈void Pop(SqStack &S) / 出栈,不返回栈顶元素 if(StackEmpty(S) cout栈为空endl; / 下溢,退出 return; S.top-; / 将栈顶指针减1ElemType GetTop(SqStack S) / 取栈顶元素 if (StackEmpty(S) cout栈为空endl; / 下溢,退出运行 exit(1); return S.dataS.to
15、p;string MultibaseOutput(int num, int n) /num为要转换的10进制数,n是转换为多少进制 string digitchar(0123456789ABCDEF); / 保存每位可能的字符 string strnum; SqStack stkchar; InitStack(stkchar); / 栈初始化 while(num!=0) Push(stkchar,digitcharnum%n); / 余数入栈 num/=n; while(!StackEmpty(stkchar) strnum+=GetTop(stkchar); / 余数出栈,加入到结果字符串中
16、 Pop(stkchar); return strnum; int main() int number,base; string m; coutnumber; coutbase; if (number0) m=MultibaseOutput(number, base); else m=-+MultibaseOutput(-number, base); cout转换结果为:mendl; return 0; 【实例3-4】括号是否匹配。表达式中的括号有以下两对:“(”和“)”、“”和“”,编写一个函数判别表达式中的括号是否配对出现。(1)问题分析。判断表达式中括号是否匹配,可通过栈。简单说就是对表
17、达式进行扫描,当遇到左括号时进栈。当遇到右括号时,若栈不为空且栈顶元素是其对应的左括号,则出栈;若栈空或栈顶元素不是其对应的左括号,则结论是括号不配对,返回false。如此下去,扫描表达式结束时,栈为空则正确,否则括号不匹配。(2)函数程序代码。bool BracketMatch(char a) int i=0; SqStack s; InitStack(s); ElemType x; while(ai!=0) switch(ai) case (: Push(s,ai); break; case : Push(s,ai); break; case ): if (StackEmpty(s) re
18、turn false; x=GetTop(s); if(x=() Pop(s); else return false; break; case : if (StackEmpty(s) return false; x=GetTop(s); if(x=) Pop(s); else return false; break; default: break; i+; if( ! StackEmpty(s) return false; return true;(3)函数应用的示例源程序。#include #include using namespace std;#define MAXNUM 100 / 假
19、定预分配的栈空间最多为100个元素 typedef char ElemType; / 假定栈元素的数据类型为字符型 typedef struct ElemType dataMAXNUM; int top;SqStack; void InitStack(SqStack &S) / 置栈空 S.top=-1; bool StackEmpty(SqStack S) / 判栈空 return S.top=-1;void Push(SqStack &S,ElemType x) / 入栈 if (S.top =MAXNUM-1) cout栈上溢endl; return; S.data+S.top=x; /
20、 栈顶指针加1后将x入栈void Pop(SqStack &S) / 出栈,不返回栈顶元素 if(StackEmpty(S) cout栈为空endl; / 下溢,退出 return; S.top-; / 将栈顶指针减1ElemType GetTop(SqStack S) / 取栈顶元素 if (StackEmpty(S) cout栈为空endl; / 下溢,退出运行 exit(1); return S.dataS.top;bool BracketMatch(char a) int i=0; SqStack s; InitStack(s); ElemType x; while(ai!=0) sw
21、itch(ai) case (: Push(s,ai); break; case : Push(s,ai); break; case ): if (StackEmpty(s) return false; x=GetTop(s); if(x=() Pop(s); else return false; break; case : if (StackEmpty(s) return false; x=GetTop(s); if(x=) Pop(s); else return false; break; default: break; i+; if( ! StackEmpty(s) return fal
22、se; return true;int main() char express80; int result; coutexpress; if (BracketMatch(express) cout括号正确匹配!endl; else cout括号不能正确匹配!=j) return true; else return false;void InversePolandExpression(char Buffer) SqStack s; InitStack(s); int i=0,j=0; ElemType e; Push(s,#); while(Bufferi!=0) if(IsOperator(B
23、ufferi) / 是操作符 e=GetTop(s); if(Prior(e,Bufferi) / 当栈顶优先权高于当前序列时,退栈 Bufferj=GetTop(s); Pop(s); j+; else Push(s,Bufferi); i+; else if (Bufferi=() / 是左括号 Push(s,Bufferi); i+; else if (Bufferi=) / 是右括号 while(GetTop(s)!=() Bufferj=GetTop(s); Pop(s); j+; Pop(s); / 丢掉左括号 i+; else / 是操作数 Bufferj=Bufferi; i+; j+; while(!StackEmpty(s) e=GetTop(
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1