栈应用后缀表达式计算
- 格式:docx
- 大小:39.59 KB
- 文档页数:5
浙江大学城市学院实验报告课程名称数据结构与算法实验项目名称实验二栈的应用---算术表达式的计算实验成绩指导老师(签名)日期一.实验目的和要求1.进一步掌握栈的基本操作的实现。
2.掌握栈在算术表达式的计算方面的应用。
二. 实验内容1. 编写程序利用栈将中缀表达式转换成后缀表达式,即从键盘输入任一个中缀表达式(字符串形式),转换成后缀表达式后,将后缀表达式输出。
假设:中缀表达式包含圆括号( ) 及双目运算符+、-、*、/、^(乘方)。
要求:把栈的基本操作的实现函数存放在头文件stack1.h中(栈元素的类型为char),在主文件test6_2.cpp中包含将中缀表达式S1转换成后缀表达式S2的转换函数void Change( char *S1, char *S2 )及主函数,在主函数中进行输入输出及转换函数的调用。
2. 选做:编写利用栈对后缀表达式进行求值的函数double Compute(char *str),以计算从前述程序得到的后缀表达式的值。
要求:把栈的基本操作的实现函数存放在头文件stack2.h中(栈元素的类型为double),在主文件test6_2.cpp中添加后缀表达式求值函数,并在主函数中增加调用求值函数及输出结果值的语句。
3. 填写实验报告,实验报告文件取名为report2.doc。
4. 上传实验报告文件report2.doc与源程序文件stack1.h、stack2.h(若有)及test6_2.cpp到Ftp服务器上你自己的文件夹下。
二.函数的功能说明及算法思路(算法思路见源程序的注释部分)//栈的顺序存储结构定义struct Stack{ElemType *stack;int top;int MaxSize;};//初始化栈S为空void InitStack(Stack &S)//元素item进栈,即插入到栈顶void Push(Stack &S,ElemType item)//删除栈顶元素并返回ElemType Pop(Stack &S)//读取栈顶元素的值ElemType Peek(Stack &S)//判断S是否为空,若是则返回true,否则返回false bool EmptyStack(Stack &S)//清除栈S中的所有元素,释放动态存储空间void ClearStack(Stack &S)//将中缀算术表达式转换为后缀算术表达式void Change(char *S1,char *&S2)//返回运算符op所对应的优先级数值int Precedence(char op)//计算由str所指字符串的后缀表达式的值double Compute(char *str)四. 实验结果与分析五. 心得体会【附录----源程序】test6_2.cpp#include<iostream.h>#include<stdlib.h>#include<math.h>#include"stack1.h"#include"stack2.h"void main(){char x[30],y[30];double r;while(1){cout<<"请输入一个中缀算术表达式:";cin.getline(x,sizeof(x));Change(x,y);cout<<"对应的后缀算术表达式为:";cout<<y<<endl;r=Compute(y);cout<<"后缀算术表达式值为:"<<r<<endl<<endl;}}stack1.htypedef char ElemType1;struct Stack1{ElemType1 *stack;int top;int MaxSize;};void InitStack(Stack1 &S){S.MaxSize=10;S.stack=new ElemType1[S.MaxSize];if(!S.stack){cerr<<"动态储存分配失败"<<endl;exit(1);}S.top=-1;}void Push(Stack1 &S,ElemType1 item)if(S.top==S.MaxSize-1){int k=sizeof(ElemType1);S.stack=(ElemType1*)realloc(S.stack,2*S.MaxSize*k);S.MaxSize=2*S.MaxSize;}S.top++;S.stack[S.top]=item;}ElemType1 Pop(Stack1 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}S.top--;return S.stack[S.top+1];}ElemType1 Peek(Stack1 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}return S.stack[S.top];}bool EmptyStack(Stack1 &S){return S.top==-1;}void ClearStack(Stack1 &S){if(S.stack){delete []S.stack;S.stack=0;}S.top=-1;S.MaxSize=0;}//返回运算符op所对应的优先级数值int Precedence(char op){switch(op){case'+':case'-':return 1;case'*':case'/':return 2;case'^':return 3;case'(':case'@':default:return 0;}}//将中缀算术表达式转换为后缀算术表达式void Change(char *S1,char *S2){Stack1 R;InitStack(R);Push(R,'@');int i=0,j=0;char ch=S1[i];while(ch!='\0'){//对于空格字符不做任何处理,顺序读取下一个字符if(ch==' ')ch=S1[++i];//对于左括号,直接进栈else if(ch=='('){Push(R,ch);ch=S1[++i];}//对于右括号,使括号内的仍停留在栈中的运算符依次出栈并写入S2else if(ch==')'){while(Peek(R)!='(')S2[j++]=Pop(R);Pop(R);//删除栈顶的左括号ch=S1[++i];}//对于运算符,使暂存于栈顶且不低于ch优先级的运算符依次出栈并写入S2else if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='^'){char w=Peek(R);while(Precedence(w)>=Precedence(ch)){S2[j++]=w;Pop(R);w=Peek(R);}Push(R,ch);//把ch运算符写入栈中ch=S1[++i];}else{if((ch<'0'||ch>'9')&&ch!='.'){cout<<"中缀表达式表示错误!"<<endl;exit(1);}while((ch>='0'&&ch<='9')||ch=='.'){S2[j++]=ch;ch=S1[++i];}S2[j++]=' ';}}//把暂存在栈中的运算符依次退栈并写入到S2中ch=Pop(R);while(ch!='@'){if(ch=='('){cerr<<"expression error!"<<endl;exit(1);}else{S2[j++]=ch;ch=Pop(R);}}S2[j++]='\0';}stack2.htypedef double ElemType2;struct Stack2{ElemType2 *stack;int top;int MaxSize;};void InitStack(Stack2 &S){S.MaxSize=10;S.stack=new ElemType2[S.MaxSize];if(!S.stack){cerr<<"动态储存分配失败"<<endl;exit(1);}S.top=-1;}void Push(Stack2 &S,ElemType2 item){if(S.top==S.MaxSize-1){int k=sizeof(ElemType2);S.stack=(ElemType2*)realloc(S.stack,2*S.MaxSize*k);S.MaxSize=2*S.MaxSize;}S.top++;S.stack[S.top]=item;}ElemType2 Pop(Stack2 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}S.top--;return S.stack[S.top+1];}ElemType2 Peek(Stack2 &S){if(S.top==-1){cerr<<"Stack is empty! "<<endl;exit(1);}return S.stack[S.top];}bool EmptyStack(Stack2 &S){return S.top==-1;}void ClearStack(Stack2 &S){if(S.stack){delete []S.stack;S.stack=0;}S.top=-1;S.MaxSize=0;}//计算由str所指字符串的后缀表达式的值double Compute(char *str){Stack2 S;InitStack(S);double x,y;int i=0;while(str[i]){if(str[i]==' '){i++;continue;}switch(str[i]){case '+':x=Pop(S)+Pop(S);i++;break;case'-':x=Pop(S);x=Pop(S)-x;i++;break;case'*':x=Pop(S)*Pop(S);i++;break;case'/':x=Pop(S);if(x!=0)x=Pop(S)/x;else{cerr<<"Divide by 0!"<<endl;exit(1);}i++;break;case'^':x=Pop(S);x=pow(Pop(S),x);i++;break;default:x=0;while(str[i]>=48&&str[i]<=57){x=x*10+str[i]-48;i++;}if(str[i]=='.'){i++;y=0;double j=10.0;while(str[i]>=48&&str[i]<=57){y=y+(str[i]-48)/j;i++;j*=10;}x+=y;}}Push(S,x);}if(EmptyStack(S)){cerr<<"expression error!"<<endl;exit(1);}x=Pop(S);if(EmptyStack(S))return x;else{cerr<<"expression error!"<<endl;exit(1);}ClearStack(S);}(注:可编辑下载,若有不当之处,请指正,谢谢!)。
基于栈的后缀算术表达式求值c语言1. 引言1.1 概述本文将讨论基于栈的后缀算术表达式求值的实现过程。
后缀算术表达式(也称为逆波兰表达式)是一种无需括号即可进行运算的表达式表示方法,它将操作符置于操作数之后。
相较于传统的中缀表达式,在计算机程序中处理后缀表达式更为高效和简洁。
1.2 文章结构文章分为五个主要部分:引言、栈的概念及原理、后缀算术表达式的定义和转换、基于栈的后缀算术表达式求值算法实现以及结论与总结。
在引言部分,我们将首先介绍本文的概述和目标,对后续内容进行简要说明。
1.3 目的通过本文,我们旨在让读者了解栈数据结构的基本概念和原理,并且掌握如何利用栈来实现对后缀算术表达式进行求值的算法。
同时,我们将介绍后缀算术表达式的定义和转换方法,并给出基于栈实现该计算方式的详细步骤与示例代码。
通过深入研究并学习这些内容,读者可以加深对栈数据结构和后缀算术表达式的理解,并且能够应用所学知识解决实际问题。
本文不仅适用于计算机科学或相关专业的学生,也适合对数据结构和算法感兴趣的读者阅读和学习。
2. 栈的概念及原理2.1 栈的定义栈是一种具有特定限制条件的线性数据结构,它具备“先进后出”(Last-In-First-Out,LIFO)的特性。
栈可以看作是一个容器,其中可以存储各种类型的数据。
与实际生活中的堆栈类似,栈只允许在其末尾进行插入和删除操作。
在栈中,最后加入的元素首先被访问和处理。
这是由于栈内元素之间的相对位置关系决定的。
插入操作称为“压栈”(Push),删除操作称为“弹栈”(Pop),而从栈顶读取元素或获取栈顶元素但不删除它称为“查看”(Peek)。
2.2 栈的基本操作推入元素:将一个元素添加到栈顶。
如果已经存在满员条件,则无法执行此操作。
弹出元素:从栈顶移除一个元素,并返回移除的值。
如果没有任何元素存在,则无法执行此操作。
查看栈顶元素:获取位于栈顶处的元素值,但不对其进行删除。
判断是否为空:检查栈是否为空。
利用栈来实现算术表达式求值的算法利用栈来实现算术表达式求值的算法算术表达式是指按照一定规则组成的运算式,包含数字、运算符和括号。
在计算机中,求解算术表达式是一项基本的数学运算任务。
根据算术表达式的性质,我们可以考虑利用栈这一数据结构来实现求值算法。
一、算法思路首先,我们需要明确一个重要概念——逆波兰表达式(ReversePolish notation)。
逆波兰表达式是一种没有括号的算术表达式,其运算规则是先计算后面的数字和运算符,再计算前面的数字和运算符。
例如,对于算术表达式“3+4*5-6”,其对应的逆波兰表达式为“3 45 * +6 -”。
那么,我们可以利用栈来实现将中缀表达式转化为逆波兰表达式的过程,具体步骤如下:1. 创建两个栈——操作数栈和操作符栈。
2. 从左到右扫描中缀表达式的每一个数字和运算符,遇到数字则压入操作数栈中,遇到运算符则进行如下操作:(1)如果操作符栈为空或当前运算符的优先级大于栈顶运算符的优先级,则将当前运算符压入操作符栈中。
(2)如果当前运算符的优先级小于或等于栈顶运算符的优先级,则将栈顶运算符弹出并加入操作数栈中,重复此过程直到遇到优先级较低的运算符或操作符栈为空为止,然后将当前运算符压入操作符栈中。
3. 扫描完中缀表达式后,若操作符栈不为空,则将其中所有运算符弹出并加入操作数栈中。
4. 最终,操作数栈中存放的就是逆波兰表达式,我们可以按照逆波兰表达式的计算规则来计算其结果。
二、算法优点利用栈来实现算术表达式求值的算法具有以下优点:1. 代码简洁易懂,易于实现和维护。
2. 由于将中缀表达式转化为逆波兰表达式后,可以减少运算符的优先级关系而消除括号,从而减少求值的复杂度,提高程序的执行效率。
三、代码实现下面是利用栈来实现算术表达式求值的算法的Python代码实现:```pythonclass Stack:def __init__(self):self.items = []def push(self, item):self.items.append(item)def pop(self):return self.items.pop()def peek(self):return self.items[-1]def is_empty(self):return len(self.items) == 0def size(self):return len(self.items)def calculate(op_num1, op_num2, operator):if operator == "+":return op_num1 + op_num2elif operator == "-":return op_num1 - op_num2elif operator == "*":return op_num1 * op_num2elif operator == "/":return op_num1 / op_num2def infix_to_postfix(infix_expr):opstack = Stack()postfix_expr = []prec = {"+": 1, "-": 1, "*": 2, "/": 2, "(": 0} token_list = infix_expr.split()for token in token_list:if token.isdigit():postfix_expr.append(token)elif token == '(':opstack.push(token)elif token == ')':top_token = opstack.pop()while top_token != '(':postfix_expr.append(top_token)top_token = opstack.pop()else:while (not opstack.is_empty()) and(prec[opstack.peek()] >= prec[token]):postfix_expr.append(opstack.pop())opstack.push(token)while not opstack.is_empty():postfix_expr.append(opstack.pop())return " ".join(postfix_expr)def postfix_eval(postfix_expr):opstack = Stack()token_list = postfix_expr.split()for token in token_list:if token.isdigit():opstack.push(int(token))else:op_num2 = opstack.pop()op_num1 = opstack.pop()result = calculate(op_num1, op_num2, token) opstack.push(result)return opstack.pop()infix_expr = "3 + 4 * 5 - 6"postfix_expr = infix_to_postfix(infix_expr)print(postfix_expr)print(postfix_eval(postfix_expr))```四、总结算术表达式求值是一项常见的数学运算任务,利用栈这一数据结构来实现求值算法是一种简单有效的方法,它将中缀表达式转化为逆波兰表达式后,可以消除括号并减少运算符的优先级关系,从而提高程序的执行效率。
后缀表达式求值实验报告书课程名:数据结构题⽬:后缀表达式求值1、实验题⽬(1)掌握栈“后进先出”的特点。
(2)掌握栈的典型应⽤——后缀表达式求值。
2、实验内容(1)⽤键盘输⼊⼀个整数后缀表达式(操作数的范围是0~9,运算符只含+、—、*、/、,⽽且中间不可以有空格),使⽤循环程序从左向右读⼊表达式。
(2)如果读⼊的是操作数,直接进⼊操作数栈。
(3)如果读⼊的是运算符,⽴即从操作数栈取出所需的操作数,计算操作数运算的值,并将计算结果存回操作数栈。
(4)检验程序运⾏结果。
3、实验要求(1)分析后缀表达式求值的算法思想,⽤C(或C++)语⾳设计程序。
(2)上机调试通过实验程序。
(3)给出具体的算法分析,包括时间复杂度和空间复杂度等。
(4)撰写实验报告(把输⼊实验数据及运⾏结果⽤抓图的形式粘贴到实验报告上)。
(5)本程序运⾏结果通过以后,添加到原教材验证性实验3的菜单中去。
4、实验步骤与源程序错误!未找到引⽤源。
实验步骤使⽤循环从左到右输⼊后缀表达式。
如输⼊的是运算符,⽴即从操作数栈取出两个操作数,计算上述操作数和运算符的值,然后存回操作数栈。
如输⼊的是操作数则直接存⼊操作数栈。
整个过程只需要⼀个操作数栈。
由⼀个链栈结点定义node、push()、pop()、empty()运算函数⼀个main()主函数(完成数据输⼊和函数调⽤)、两个个功能函数:isoperator()//判运算符getvalue()//计算表达式值错误!未找到引⽤源。
源代码#include#includestruct node // 栈结构声明{int data; // 数据域struct node *next; // 指针域typedef struct node stacklist; // 链表新类型typedef stacklist *link; // 链表指新针类型link operand=NULL; // 操作数栈指针void push( int value) // 进栈,存⼊数据{link newnode; // 新结点指针newnode=new stacklist; // 分配新结点if (!newnode){printf("分配失败!"); // 存⼊失败return ;}newnode->data=value; // 创建结点的内容newnode->next=operand;operand=newnode; // 新结点成为栈的开始return ;}void pop(int *value) // 出栈,取出数据{link top; // 指向栈顶if (operand !=NULL){top=operand; // 指向栈顶operand=operand->next; // 移动栈顶指针,指向下⼀个结点*value=top->data; // 取数据delete top; // 吸收结点}else*value=-1;}int empty() // 判栈空{if (operand!=NULL) return 1;else return 0;int isoperator(char op) // 判运算符{switch (op){case'+':case'-':case'*':case'/': return 1; // 是运算符,返回default: return 0; // 不是运算符,返回}}int getvalue(int op,int operand1,int operand2) // 计算表达式值{switch((char)op){case'*': return(operand1*operand2);case'/': return(operand1/operand2);case'+': return(operand1+operand2);case'-': return(operand1-operand2);}}void main() // 主函数{char exp[100];int operand1=0; // 定义操作数int operand2=0; // 定义操作数int result=0; // 定义操作结果变量int pos=0; // ⽬前表达式位置printf("\t\n 请输⼊后缀表达式:");gets(exp); //cin.getline(exp,81) // 读取后缀表达式 printf("\t\n\n 后缀表达式[%s]的结果是:",exp); while (exp[pos] !='\0' && exp[pos] !='\n') // 分析表达式字符串{if (isoperator(exp[pos])) // 是运算符,取两个操作数{pop(&operand2);pop(&operand1);push(getvalue(exp[pos],operand1,operand2)); }elsepush(exp[pos]-48); // 是操作数,压⼊操作数栈 pos++; // 移到下⼀个字符串位置}pop(&result); // 弹出结果printf("%d\n",result); // 输出}5、测试数据与实验结果(可以抓图粘贴)图1:程序运⾏结果6、结果分析与实验体会结果分析:本次实验结果准确。
一、设计思想第一种算法:将中缀表达式转为后缀表达式,然后通过后缀表达式计算出算术表达式的结果。
核心思想:第一步:中缀变后缀。
首先,我们做出一个统一的Node结构体,结构体内部包含四个属性,分别是操作符的字符‘op’,char类型;操作符的优先级‘level’,int 类型;数字的浮点数数值‘od’,float类型;Node的标识符,int类型。
然后,定义一个Node结构体类型的数组*listNode,这里的*listNode用的是全局变量,为了方便在得到后缀表达式后,不需再传递给计算的方法。
定义一个存放操作符的栈,遍历用户输入的算术表达式(不考虑错误情况),在遍历的过程中如果遇到数字,直接将数字存放在*listNode里面;如果遇到了操作符,则判断操作符栈目前是不是为空,如果为空,直接将遇到的操作符放入操作符栈中,如果操作符栈不为空,那么观察操作符栈中栈顶的操作符,然后再次判断当前遇到的操作符的优先级是不是比栈顶的操作符的优先级高,如果是,那么将当前的操作符入操作符栈;如果不是,那么将操作符栈的栈顶操作符取出,追加到*listNode中,然后继续观察栈顶操作符,直到当前的操作符的优先级比栈顶操作符的优先级高或者操作符栈为空时,将当前操作符入操作符栈。
如果遇到了左括号,那么定义其优先级为最低,然后直接将左括号入操作符栈。
如果遇到了右括号,那么开始从操作符栈中取出操作符追加到*listNode中,直到遇到了与之对应的左括号,然后将左括号和右括号一起销毁。
当遍历完成了算术表达式之后,这时判断操作符栈是否为空,如果不为空,那么从操作符栈中依次取出栈顶操作符追加到*listNode中,直到操作符栈为空,那么就代表我们将中缀表达式转变成为了后缀表达式。
第二步:通过得到的后缀表达式,计算算术表达式。
首先,定义一个数字栈用来存放数值。
然后,遍历*listNode中的每一个Node,如果Node是一个数字,那么就将数字入数字栈,如果Node是一个操作符,那么就从数字栈中依次取出栈顶的两个数字,然后根据操作符计算这两个数字,将得到的结果再次入数字栈,直到遍历*listNode完成,最终数字栈中会只剩下一个Node,那就是我们计算出算术表达式的结果,将结果返回给main 函数用来输出。
中缀表达式转后缀表达式中缀表达式转后缀表达式的规则。
1.遇到操作数:直接输入到后缀表达式栈2.遇到运算符,直接入操作符栈3.遇到左括号:直接将其入栈4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈6.最终将操作符栈中的元素依次出栈,输出到后缀表达式栈。
以下是自己写的代码。
亲测没有问题。
(模拟一个计算器,可以带括号,中间可以空格,只支持整数输入,但是输出结果精确到小数后6位)#include "stdio.h"#define MAX_LEN 100typedef struct cal{unsigned char isOper;//是否是操作数1,操作符0.操作数double Num; //值。
或者是操作符的ASCII值}STRUCT_CAL;#define IS_NUM 0x00#define IS_OPER 0x01STRUCT_CAL stackCal[MAX_LEN];STRUCT_CAL stackCalBack[MAX_LEN];unsigned char topCal;char stackOper[MAX_LEN];unsigned char topOper;/****************************************************************** 堆栈初始化*****************************************************************/void stackInit(void){int i;for(i=0;i<MAX_LEN;i++){stackCal[i].isOper = 0;stackCal[i].Num = 0;stackOper[i] = 0;}topCal = topOper = 0;}/***************************************************************** * 返回堆栈的栈顶,返回后栈顶减一*****************************************************************/ STRUCT_CAL * stackCalPop(void){if(topCal == 0)return (STRUCT_CAL *)0;return stackCal+(--topCal);}/***************************************************************** * 计算表达式入栈*****************************************************************/void stackCalPush(double num, unsigned char isOper){if(topCal>=MAX_LEN)return;stackCal[topCal].Num = num;stackCal[topCal].isOper= isOper;topCal++;}/***************************************************************** * 操作符出栈*****************************************************************/char stackOperPop(void){if(topOper == 0)return 0;return stackOper[--topOper];}/****************************************************************** 操作符入栈*****************************************************************/void stackOperPush(char oper){if(topOper >=MAX_LEN)return;stackOper[topOper++] = oper;}/****************************************************************** 比较两个sour sour1 的优先级* 1 sour >= sour1 直接入操作符栈* 0 sour < sour1 直接入计算表达式栈*****************************************************************/ unsigned char comparPrior(char sour, char sour1){if(sour =='\0' ||sour1 == '\0') return 1;switch(sour){case '+':case '-':if(sour1 == '*' ||sour1 == '/'||sour1 == '+' ||sour1 == '-' ){return 0;}else{return 1;}break;case '*':case '/':if(sour1 == '*' ||sour1 == '/'||sour1 == '+' ||sour1 == '-'||sour1 == '('){return 1;}else{return 0;}break;default:return 1;break;}}/****************************************************************** 将输入的字符串转换为栈*****************************************************************/void StrToCal(char *pStr){int tmpNum = 0;char tmpOper;char islastNum = 0;//判断上一个字符是什么。
栈的应⽤——表达式求值 表达式求值是程序设计语⾔编译中的⼀个基本问题,它的实现就是对“栈”的典型应⽤。
本⽂针对表达式求值使⽤的是最简单直观的算法“算符优先法”。
本⽂给出两种⽅式来实现表达式求值,⽅式⼀直接利⽤中缀表达式求值,需要⽤到两个栈,操作数栈和操作符栈。
⾸先置操作数栈为空栈,操作符栈仅有“#”⼀个元素。
依次读⼊表达式中的每个字符,若是操作数则进操作数栈,若是操作符则和操作符栈的栈顶运算符⽐较优先权作相应操作,直⾄整个表达式求值完毕。
⽅式⼆⾸先把中缀表达式转换为后缀表达式并存储起来,然后利⽤读出的后缀表达式完成求值,其本质上是⽅式⼀的分解过程。
表达式求值的代码如下:#include <iostream>#include "stack"#include "map"using namespace std;/* 只能求⼀位整数的加减乘除混合运算 */map<char, pair<int, int>> priority; // 存放各个操作符的栈内栈外优先级,first是栈内,second是栈外char infix[50]; // 存放初始的中缀表达式char postfix[50]; // 存放转化的后缀表达式int result;void MakePriority() // 构造运算符优先级表{priority.insert(make_pair('#', make_pair(0, 0))); // isp(#)=0, icp(#)=0priority.insert(make_pair('\n', make_pair(0, 0))); // isp(\n)=0, icp(\n)=0 表达式结尾的'#'⽤'\n'代替,这样可以省略表达式末尾的结束符'#'priority.insert(make_pair('(', make_pair(1, 6))); // isp(()=1, icp(()=6priority.insert(make_pair('*', make_pair(5, 4))); // isp(*)=5, icp(*)=4priority.insert(make_pair('/', make_pair(5, 4))); // isp(/)=5, icp(/)=4priority.insert(make_pair('%', make_pair(5, 4))); // isp(%)=5, icp(%)=4priority.insert(make_pair('+', make_pair(3, 2))); // isp(+)=3, icp(+)=2priority.insert(make_pair('-', make_pair(3, 2))); // isp(-)=3, icp(-)=2priority.insert(make_pair(')', make_pair(6, 1))); // isp())=6, icp())=1}void InfixToPostfix() // 把中缀表达式转换为后缀表达式{int i = 0;stack<char> optrStack; // 操作符栈char optr; // optr为栈顶的操作符optrStack.push('#');while (!optrStack.empty()){if (isdigit(infix[i])) // 是操作数则直接输出(追加到postfix结尾){postfix[strlen(postfix)] = infix[i];postfix[strlen(postfix) + 1] = '\0';i++; // 读⼊中缀表达式的下⼀个字符}else// 是操作符, ⽐较优先级{optr = optrStack.top(); // 取出栈顶操作符if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]⼊栈{optrStack.push(infix[i]);i++;}else if (priority[infix[i]].second < priority[optr].first)// icp(infix[i]) < isp(optr),optr退栈并输出{postfix[strlen(postfix)] = optr;postfix[strlen(postfix) + 1] = '\0';optrStack.pop();}else// icp(infix[i]) = isp(optr),退栈但不输出,若退出的是'(',则继续读⼊下⼀个字符{optrStack.pop();if (optr == '(')i++;}}}}void CalculateByPostfix() // 通过后缀表达式求值{int i = 0;stack<int> opndStack; // 操作数栈int left, right; // 左右操作数int value; // 中间结果int newOpnd;while (postfix[i] != '#' && i < strlen(postfix)){switch (postfix[i]){case'+':right = opndStack.top(); // 从操作数栈中取出两个操作数opndStack.pop();left = opndStack.top();opndStack.pop();value = left + right;opndStack.push(value); // 中间结果⼊栈break;case'-':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();value = left - right;opndStack.push(value);break;case'*':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();value = left * right;opndStack.push(value);break;case'/':right = opndStack.top();opndStack.pop();left = opndStack.top();opndStack.pop();if (right == 0){cerr << "Divide by 0!" << endl;}else{value = left / right;opndStack.push(value);}break;default:newOpnd = (int)(postfix[i] - 48); // 操作数直接⼊栈opndStack.push(newOpnd);break;}i++;}result = opndStack.top();}void CalculateByInfix() // 直接利⽤中缀表达式求值{int i = 0;stack<char> optrStack; // 操作符栈stack<int> opndStack; // 操作数栈char optr; // optr为操作符栈顶的操作符int left, right, value; // 左右操作数以及中间结果optrStack.push('#');optr = optrStack.top();while (!optrStack.empty()) // 直到操作符栈为空{if (isdigit(infix[i])) // 是操作数, 进操作数栈{value = (int)(infix[i] - 48);opndStack.push(value);i++;}else// 是操作符, ⽐较优先级{optr = optrStack.top(); // 取出操作符栈顶的操作符if (priority[infix[i]].second > priority[optr].first) // icp(infix[i]) > isp(optr),infix[i]⼊栈 {optrStack.push(infix[i]);i++;}else if (priority[infix[i]].second < priority[optr].first) // icp(infix[i]) < isp(optr),optr退栈并输出{optrStack.pop();right = opndStack.top(); // 从操作数栈中取出两个操作数opndStack.pop();left = opndStack.top();opndStack.pop();switch (optr){case'+':value = left + right;opndStack.push(value); // 中间结果⼊栈break;case'-':value = left - right;opndStack.push(value); // 中间结果⼊栈break;case'*':value = left * right;opndStack.push(value); // 中间结果⼊栈break;case'/':if (right == 0){cerr << "Divide by 0!" << endl;}else{value = left / right;opndStack.push(value);}break;default:break;}}else{optrStack.pop();if (optr == '(')i++;}}}result = opndStack.top();}int main(){MakePriority(); // 构造运算符优先级表cout << "请输⼊中缀表达式:";cin >> infix;cout << "直接利⽤中缀表达式求值为:";CalculateByInfix();cout << result << endl;cout << "转化为后缀表达式:";InfixToPostfix();for (int i = 0;i < strlen(postfix);i++){cout << postfix[i];}cout << endl;cout << "利⽤后缀表达式求值为:";CalculateByPostfix();cout << result << endl;return0;} 为了⽅便起见,本⽂只是简单的设计了⼀个针对⼀位整数的四则运算进⾏求值的算法,对于处理多位整数的四则运算,需要对本⽂接受输⼊的数据类型进⾏“升阶”,把字符数组换成字符串数组,将⼀个整数的多位数字存⼊⼀个字符串进⾏处理。
栈和队列的应用场景栈和队列是数据结构中常见的两种基本数据结构,它们在实际生活和计算机领域中有着广泛的应用场景。
本文将从实际应用的角度出发,介绍栈和队列在不同场景下的具体应用。
### 一、栈的应用场景#### 1.1 浏览器的后退和前进功能在浏览器中,当我们访问一个网页时,浏览器会将该网页的 URL 存储在一个栈中。
当我们点击后退按钮时,浏览器会从栈顶取出上一个网页的 URL,实现后退功能;当我们点击前进按钮时,浏览器会从栈中取出下一个网页的 URL,实现前进功能。
#### 1.2 括号匹配在编程中,栈常用于检查表达式中的括号是否匹配。
当遇到左括号时,将其入栈;当遇到右括号时,将栈顶元素出栈并与右括号进行匹配。
如果匹配成功,则继续;如果匹配失败,则表达式中存在不匹配的括号。
#### 1.3 撤销操作在文本编辑器或图像处理软件中,撤销操作通常使用栈来实现。
每次编辑操作都会将编辑内容存储在栈中,当用户点击撤销按钮时,软件会从栈中取出上一个编辑操作,实现撤销功能。
### 二、队列的应用场景#### 2.1 系统任务调度在操作系统中,队列常用于实现任务调度。
操作系统会将需要执行的任务按照先来先服务的原则排入队列,然后逐个执行。
这种方式可以保证任务的顺序性和公平性。
#### 2.2 打印队列在打印机中,打印任务通常按照先后顺序排入打印队列中,然后依次执行。
这样可以避免多个打印任务同时请求打印,导致打印机发生冲突。
#### 2.3 消息队列在分布式系统中,消息队列被广泛应用于解耦和异步处理。
生产者将消息发送到队列中,消费者从队列中取出消息并进行处理,实现了生产者和消费者之间的解耦。
### 三、栈和队列的综合应用场景#### 3.1 模拟计算器在计算器的设计中,可以使用栈来实现表达式的计算。
将中缀表达式转换为后缀表达式,然后利用栈来计算后缀表达式的值,实现计算器的功能。
#### 3.2 资源分配在操作系统中,可以使用队列来实现资源的分配。
后缀表达式计算结果(栈的应用)
后缀表达式为:9 3 1 - 3 * + 10 2 / +
规则为:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。
a.初始化一个空栈。
此栈用来对要运算的数字进行进出使用。
b.后缀表达式中前三个是、都是数字,所以9 3 1 进栈。
c.接下来是“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再讲2进栈。
d.接着是数字3进栈。
e.后面是“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。
f.下面是“+”,所以栈中6和9出栈,9和6相加,得到15,将15进栈。
g.接着是10和2两数字进栈。
h.接下来是符号“/”,因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈。
i.最后一个是符号“+”,所以15与5出栈并相加,得到20,讲20进栈。
j.结果是20出栈,栈变为空。
一、设计思想两种算法首先都要建立两个栈,一个是存放操作数的数栈OdStack,一个是存放运算符的符栈OpStack。
数栈采用double型的用来存放浮点数,符栈采用char型的用来存放运算符,由于考虑到运算符有优先级的问题,所以事先做了一个Type用来存储运算符的优先级。
栈建立好了之后做栈的相关操作,初始化栈,入栈,出栈,看栈顶。
其中入栈要判满,出栈和看栈顶要判空。
中缀转后缀再计算的算法。
此算法的基本思路是先将中缀表达式转换成后缀表达式,之后再利用后缀表达式的算法对表达式进行计算。
首先,用一个char数组将中缀表达式读入,对数组中的每一个元素进行处理,区分哪些是数,哪些是运算符。
如果是数元素(或小数点元素),则依次存入用来存储后缀表达式的char数组,直到一个整合数存完之后用空格将其与后面的元素分开。
如果是运算符元素,则根据当前运算符的优先级和栈里面的运算符的优先级进行处理。
如果栈内元素的优先级小于当前元素的优先级或者栈内为空,则将当前运算符入栈;如果栈内元素的优先级大于等于当前元素的,则依次将出栈元素存入后缀表达式,并用空格将其与后面的元素分开,直到栈内元素的优先级小或者栈内为空。
对于左括号来说,无条件进栈,并只在有右括号出现的时候才有可能出栈。
对于右括号来说,无条件让栈内元素出栈,直到左括号出栈。
依次将每个元素进行处理直到中缀表达式索引完毕。
至此,已经实现了将中缀表达式转换成了后缀表达式,在数组的最后加上结束符以便下一步的调用。
第二步,读出后缀表达式并进行计算。
如果索引到空格则将索引标志后推1位。
之后要先对char型的数字元素进行整合,从后缀表达式中依次取出数字元素(连同小数点)存入一个新的char型数组,直到一整个数取完后通过atof函数将char型转换成浮点型存入数栈,并将新数组初始化用来存储下一个数。
如果是索引到运算符,则在数栈中出栈两个数字与当前运算符进行运算,先出栈的数字放在运算符后面,后出栈的数字放在运算符的前面,将运算以后的结果再次存入数栈。
第4章栈和队列一、复习要点本章主要讨论3种线性结构:栈、队列与优先级队列。
这3种结构都是顺序存取的表,而且都是限制存取点的表。
栈限定只能在表的一端(栈顶)插入与删除,其特点是先进后出。
队列和优先级队列限定只能在表的一端(队尾)插入在另一端(队头)删除,不过优先级队列在插入和删除时需要根据数据对象的优先级做适当的调整,令优先级最高的对象调整到队头,其特点是优先级高的先出。
而队列不调整,其特点是先进先出。
这几种结构在开发各种软件时非常有用。
本章复习的要点:1、基本知识点要求理解栈的定义和特点,栈的抽象数据类型和在递归和表达式计算中的使用,在栈式铁路调车线上当进栈序列为1, 2, 3, , n时,可能的出栈序列计数,栈的顺序存储表示和链接存储表示,特别要注意,链式栈的栈顶应在链头,插入与删除都在链头进行。
另外,需要理解队列的定义和特点,队列的抽象数据类型和在分层处理中的使用,队列的顺序存储表示(循环队列)和链接存储表示,需要注意的是,链式队列的队头应在链头,队尾应在链尾。
还需要理解优先级队列的定义和特点。
优先级队列的最佳存储表示是堆(heap),本章介绍的表示看懂即可。
2、算法设计➢栈的5种操作(进栈、退栈、取栈顶元素、判栈空、置空栈)的在顺序存储表示下的实现,以及在链接存储表示下的实现。
➢使用栈的后缀表达式计算算法➢循环队列的进队列、出队列、取队头元素、判队列空、置空队列操作的实现➢链式队列的进队列、出队列、取队头元素、判队列空、置空队列操作的实现二、难点和重点1、栈:栈的特性、栈的基本运算➢栈的数组实现、栈的链表实现➢栈满及栈空条件、抽象数据类型中的先决条件与后置条件2、栈的应用:用后缀表示计算表达式,中缀表示改后缀表示3、队列:队列的特性、队列的基本运算➢队列的数组实现:循环队列中队头与队尾指针的表示,队满及队空条件➢队列的链表实现:链式队列中的队头与队尾指针的表示、三、习题的解析4-2 铁路进行列车调度时, 常把站台设计成栈式结构的站台,如右图所示。
中缀、前缀、后缀表达式的运算 中缀表达式,就是在表达式中,操作符在操作数的中间,⽐如 (1+2)*3,+和*在1, 2, 3的中间。
前缀表达式,就是操作符在操作数的前⾯,⽐如 +12,+在1, 2的前⾯。
后缀表达式,就是操作符在操作数的后⾯,⽐如 12+,+在1, 2的后⾯。
为什么会有这么多表达式呢?它们⽬的不同。
中缀表达式,便于我们书写,也符合我们的阅读习惯,在计算机程序中,都是写中缀表达式,但它却不利于计算机进⾏算术计算,因为涉及到优先级和括号。
前缀表达式和后缀表达式中没有括号,并且运算符的优先级也通过它们在表达式中的顺序体现出来了,有利于计算机进⾏算术运算。
前缀表达式也叫波兰表达式,因为它是由⼀个波兰⼈发明的,相应的,后缀表达式也称为逆波兰表达式。
举个例⼦来说明⼀下三者的运算过程,假设计算(3+4)*5-6 使⽤中缀表达式进⾏计算 1,创建两个栈,⼀个是数字栈,⽤来存放操作数,⼀个是字符栈,⽤来存放操作符。
2,算术表达式是⼀个字符串,从左到右循环遍历表达式,依次取出每⼀个字符。
当取出的字符是操作数时,⼊数字栈。
当取出的字符是操作符时,这时还要看操作符的优先级和字符栈是否为空 如果字符栈为空,直接把取出的字符放⼊到字符栈中。
如果字符栈不为空,则要⽐较字符的优先级 如果取出的字符的优先级⼤于等于字符栈中栈顶的字符的优先级,直接把取出的字符放⼊到字符栈中。
如果取出的字符的优先级⽐字符栈中栈顶的字符的优先级低,则要循环进⾏如下操作,直到取出的字符的优先级⼤于等于字符栈中栈顶字符的优先级或者栈为空,此时,把取出的字符放⼊到字 符栈中。
如下操作就是: 1,从字符栈中弹出操作符 2,从数字栈中弹出两个操作数。
3,操作数结合操作符进⾏计算,要注意操作数顺序,后⾯pop出的数在求值的表达式中是前⾯的操作数,尤其是在做减法的时候 4,计算出的值放⼊到数字栈。
为什么要⽐较操作符的优先级呢?因为要确定操作数属于哪个操作符,相邻两个操作符之间的数字是共享的。
一、设计思想计算算数表达式并求值,采取的共有两种方法:1.先将算数表达式转化为后缀表达式,然后对后缀表达式进行计算。
2.对算数表达式进行直接的计算。
第一种算法这种解决方案又分为两步:1.将表达式先转化为后缀表达式的字符串数组2.利用后缀表达式进行计算在转化过程中,第一,建立一个存符号的栈,和一个字符串数组,用来存放转化以后的表达式然后,对于得到的用户输入的字符串进行逐个的扫描,如果是数组或者小数点,则直接存放到数组中,并且在后面加入一个分隔符,如果是操作符,则和栈中的已存的进行比较,如果比栈中的操作符的优先级高,则直接入栈,如果优先级低或相等,则栈中元素出栈,存到字符串中,然后再次检查栈顶,直到栈中元素的优先级低于扫描操作符,则此操作符入栈,然后扫描下一个字符,直到遇到字符串的结束符号\0,扫描结束。
数组中存的就是后缀表达式。
得到后缀表达式后,进行计算,要用到数值栈。
首先要将字符表示的数字转化为浮点小数,然后进行扫描,遇到数值,放入栈中,遇到操作符,就从栈中取出两个数,进行计算后再放入栈中,扫描下一个,最后的计算结果就存到了栈中,直接取出栈内元素,就是计算的最后结果。
第二种算发首先要建立两个栈,一个用来存放操作符,一个用来存放数值。
开始对用户输入的字符串进行扫描,如果是数字字符或者小数点,则将字符转化为浮点数存到数栈里,如果是操作符,则观察符号栈,如果栈顶元素的优先级低于观察的操作符,则操作符入栈,如果栈顶元素的优先级高于或者等于观察的操作符,则从数值栈中取出两个浮点数,从符号栈中取出栈顶的操作符,然后进行相应的数值计算,所得的结果再存到数值栈中,重复这样的操作,直到符号栈中栈顶元素的优先级低于观察的操作符,则此操作符入栈,然后对下一个字符进行扫描。
如果是左括号,则不进行优先级的比较,直接入栈,入栈后优先级为-1。
如果是右括号,则从数值栈中取两个操作数,符号栈中取出一个符号,然后进行计算后得数放入数栈中,不断进行此类操作,直到从栈中取出的是左括号为止,左括号去掉,扫描下一个。
逆波兰利用栈实现简单的四则运算一.逆波兰表达式引自/blog/472070逆波兰表达式解决四则运算逆波兰表达式又叫做后缀表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式,解决了四则运算中括号改变运算符优先级的问题。
四则运算的表达式一般都是中缀表达式如1+2*(3-4)+5,即操作符在两个操作数之间。
四则运算需要两个步骤,一是把中缀表达式转为后缀表达式,二是由后缀表达生成结果中缀表达式转为后缀表达式算法描述:(1)首先有个包含中缀表达式元素列表sourceList,然后创建一个符号列表destList保存最终后缀表达式,创建一个操作符堆栈opStack(2)从sourceList取出一个元素A(3a)如是数字则加入到destList中(3b)如果元素A是运算符,将操作符A与操作符堆栈opStack栈顶的运算符的优先关系相比较。
如果,优先关系高于opStack栈顶的运算符,则将该运算符压入操作符堆栈opStack。
倘若不是(低于或等于)的话,则将运算符栈opStack栈顶的运算符从栈中弹出保存到destList,重复此步骤,直到作符A压入操作符堆栈opStack。
(3c)若元素A是左括号"(",则压入操作符堆栈opStack(3d)若元素B是右括号")",则操作符堆栈opStack弹出操作符并加入到destList中,直到弹出左括号"("。
(5)从步骤2重复上述操作,所有元素处理完毕后将操作符堆栈opStack弹出操作符并加入到destList中,这样中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
示例:中缀表达式如1+2*(3-4)+5,构造元素列表1,+,2,*,(,3,-,4,),5,构造一个空最终后缀表达式destList,一个操作符堆栈opStack1、取出“1”,destList【1】,opStack【】2、取出“+”,destList【1】,opStack【+】3、取出“2”,destList【1,2】,opStack【+】4、取出“*”,destList【1,2】,opStack【+,*】5、取出“(”,destList【1,2】,opStack【+,*,(】6、取出“3”,destList【1,2,3】,opStack【+,*,(】7、取出“-”,destList【1,2,3】,opStack【+,*,(,-】8、取出“4”,destList【1,2,3,4】,opStack【+,*,(,-】9、取出“)”,destList【1,2,3,4,-】,opStack【+,*】//操作符堆栈opStack弹出操作符并加入到destList中,直到弹出左括号"("10、取出“+”,destList【1,2,3,4,-,*,+】,opStack【+】//加号优先级不大于【+,*】11、取出“5”,destList【1,2,3,4,-,*,+,5】,opStack【+】12、处理完毕,destList【1,2,3,4,-,*,+,5,+】,opStack【】后缀表达式到计算结果算法描述:遍历储存后缀表达式的列表,将元素依次进栈,当遇到操作符时,连续出栈两个元素,进行运算,再将结果进栈,最后栈内留下的元素就是计算结果示例:后缀表达式destList【1,2,3,4,-,*,+,5,+】,结果堆栈resultStatck【】格式输入-->:结果[1,2,3,4]-->:resultStatck【1,2,3,4】[-]-->:resultStatck【1,2,3-4】[ * ]-->:resultStatck【1,2*(3-4)】[+]-->:resultStatck【1+2*(3-4)】[5]-->:resultStatck【1+2*(3-4),5】[+]-->:resultStatck【1+2*(3-4)+5】举例:正常的表达式逆波兰表达式a+b ---> a,b,+a+(b-c) ---> a,b,c,-,+a+(b-c)*d ---> a,b,c,-,d,*,+a+d*(b-c) ---> a,d,b,c,-,*,+a=1+3 ---> a=1,3 +二.自己写的简单四则运算的程序。
关于栈的实验报告引言栈(Stack)是一种常用的数据结构,它基于后进先出(Last In First Out,LIFO)的原则,元素的插入和删除操作只能在栈顶进行。
栈具有快速插入和删除元素的特点,因此在很多应用中广泛使用。
本实验旨在通过编写一个栈的实现,探究栈的基本操作以及应用,并对栈的性能进行评估。
一、栈的实现1. 栈的定义使用数组来实现一个基本的栈结构,可以定义一个栈类`Stack`,其中包含以下属性和方法:- 属性:- `max_size`:栈的最大容量- `top`:栈顶指针- `data`:存储栈元素的数组- 方法:- `__init__(self, size)`:构造函数,初始化栈对象,参数为栈的最大容量- `is_empty(self)`:判断栈是否为空- `is_full(self)`:判断栈是否已满- `push(self, item)`:将元素压入栈顶- `pop(self)`:从栈顶弹出一个元素- `peek(self)`:返回栈顶元素- `size(self)`:返回栈的当前大小- `clear(self)`:清空栈中所有元素2. 栈的实现pythonclass Stack:def __init__(self, size):self.max_size = sizeself.top = -1self.data = [None] * sizedef is_empty(self):return self.top == -1def is_full(self):return self.top == self.max_size - 1 def push(self, item):if self.is_full():print("Stack is full.")returnself.top += 1self.data[self.top] = itemdef pop(self):if self.is_empty():print("Stack is empty.")return Noneitem = self.data[self.top]self.top -= 1return itemdef peek(self):if self.is_empty():print("Stack is empty.")return Nonereturn self.data[self.top]def size(self):return self.top + 1def clear(self):self.top = -1上述代码实现了一个基本的栈,其中使用一个列表`data` 来存储栈的元素,`top` 表示栈顶指针,初始值为-1。
数据结构实验报告报告名称栈的应用专业网络工程班级1001学号************姓名张剑指导教师陈淑红李珍辉黄哲2012 年5 月4日一、实验目的:熟练掌握栈的基本操作,进一步理解栈的应用。
二、实验内容与基本要求:实验内容:设计一个程序,用算符优先法对算术表达式求值基本要求:以字符序列的形式从终端输入语法正确的、不含变量的算术表达式,利用算符优先关系,实现对算术四则混合运算表达式求值。
三、实现提示:1.利用栈辅助分析算符优先关系;2.在读入表达式字符序列的同时,完成运算符和操作数的识别处理,以及相应的运算;3.在识别出操作数的同时,要将其字符序列形式转换成相应的浮点数形式。
四.概要设计:1.顺序栈的定义:typedef struct{SElemType *base;SElemType *top;int stacksize;} SqStack;2.栈的基本操作:InitStack(&S)操作结果:构造一个空栈S。
DestoryStack(&S)初始条件:栈S存在。
、操作结果:栈S被销毁。
ClearStack(&S)初始条件:栈S存在。
、操作结果:将S清为空栈。
StackEmpty(&S)初始条件:栈S存在。
、操作结果:若S为空栈,则返回TUUE,否则FALSE.StackLength(&S)初始条件:栈S存在。
、操作结果:返回S的元素个数,即栈的长度。
GetTop(S,&e)初始条件:栈S存在且非空。
操作结果:用e 返回S的栈顶元素。
Push(&S,e)初始条件:栈S存在。
、操作结果:插入元素e为新的栈顶元素。
pop (&s,&e)初始条件:栈S存在且非空。
操作结果:删除S的栈顶元素,并用e返回其值。
StackTravse(S,vist())初始条件:栈S存在且非空.操作结果:从栈底到栈顶依次对S的每个元素调用函数vist(),一旦vist()失败,择操作结束。
栈和队列的应用实例一、栈的应用实例1.计算器程序计算器程序是栈的一个经典应用,它可以通过将表达式转换成后缀表达式,再利用栈进行运算得出结果。
具体实现过程如下:(1)将中缀表达式转换为后缀表达式。
(2)利用栈进行后缀表达式的运算。
2.浏览器前进后退功能浏览器前进后退功能也是栈的一个应用。
当用户点击浏览器的前进或后退按钮时,浏览器会将当前页面的URL压入一个栈中。
当用户点击前进或后退按钮时,浏览器会从栈中弹出上一个或下一个URL并加载。
3.括号匹配问题括号匹配问题也是栈的一个常见应用。
当我们需要判断一段代码中括号是否匹配时,可以使用栈来实现。
遍历代码中每个字符,如果是左括号,则将其压入栈中;如果是右括号,则从栈顶弹出一个左括号进行匹配。
如果最终栈为空,则说明所有括号都匹配成功。
二、队列的应用实例1.打印队列打印队列是队列的一个典型应用。
在打印机资源有限且多人共享的情况下,打印队列可以帮助我们管理打印任务的顺序。
每当有一个新的打印任务到达时,就将其加入队列中。
当打印机空闲时,从队列中取出第一个任务进行打印,直到队列为空。
2.消息队列消息队列也是队列的一个重要应用。
在分布式系统中,不同节点之间需要传递消息进行通信。
为了保证消息传递的可靠性和顺序性,可以使用消息队列来实现。
每当一个节点发送一条消息时,就将其加入到消息队列中。
接收方从消息队列中取出最早的一条消息进行处理。
3.广度优先搜索广度优先搜索也是队列的一个常见应用。
在图论和网络分析中,广度优先搜索可以帮助我们寻找最短路径和连通性等问题。
具体实现过程如下:(1)将起点加入到队列中。
(2)从队首取出一个节点,并将与其相邻且未访问过的节点加入到队尾。
(3)重复步骤(2),直到找到终点或者遍历完所有节点。
以上是栈和队列的一些应用实例,在实际编程过程中需要根据具体情况选择合适的数据结构来解决问题。
后缀表达式计算
LinkStack.cpp
#include<iostream>
using namespace std;
//单链表的结点结构体:
template <class DataType>
struct Node
{ DataType data;
Node<DataType> *next;
};
//带头结点的单链表类的声明
template <class DataType>
class LinkStack
{ public:
LinkStack( ){ top=NULL; } //构造函数
~LinkStack( ); //析构函数
bool IsEmpty( ); //栈空操作
DataType GetTop ( ); //得到栈顶值操作
void Push( DataType x ); //进栈操作
DataType Pop( ); //出栈操作
private:
Node<DataType> *top;
};
//析构函数,析构函数将单链表中所有结点的存储空间释放。
template <class DataType>
LinkStack<DataType> :: ~LinkStack( )
{ Node<DataType> *q;
while (top !=NULL)
{ q = top; //暂存释放结点
top = top->next; //top指向被释放结点的下一个结点 delete q; //释放结点
}
cout<<"链表已经删除。
"<<endl;
}
//栈空返回true,否则返回false
template <class DataType>
bool LinkStack<DataType>::IsEmpty()
{ return (top==NULL)?true:false; };
//进栈操作
template <class DataType>
void LinkStack<DataType>:: Push( DataType x )
{ Node<DataType> *s;
s=new Node<DataType>; //申请一个数据成为x的结点s s->data=x;
s->next=top;
top=s;
};
//出栈操作
template <class DataType>
DataType LinkStack<DataType>::Pop( )
{ Node<DataType> *p;
DataType x;
if (IsEmpty())
{ cout<< "栈空无值弹出" <<endl; exit(1); } x=top->data;
p=top;
top=top->next;
delete p;
return x;
};
//返回栈顶值操作
template <class DataType>
DataType LinkStack<DataType>::GetTop( )
{ if (IsEmpty())
{ cout<< "栈空无值" <<endl;
exit(1);
}
return top->data;
};
PostExp.cpp
#include "LinkStack.h"
//后缀表达式计算的栈类声明
template <class DataType>
class PostExp
{ public:
PostExp( ){ } ; //构造函数
void Run( ); //执行表达式计算
void Clear( ); //清栈操作
private:
LinkStack<DataType> s; //栈对象s
void Enter( DataType num); //进栈操作
bool In(char op); //判断操作数
bool GetTwoOperands(DataType& operand1,DataType& operand2); //从栈中推出两个操作数
void Compute(char op); //形成运算指令,进行计算
};
//进栈操作
template <class DataType>
void PostExp<DataType>::Enter( DataType num)
{ s.Push(num); } //将操作数的值num进操作数栈
//从栈中推出两个操作数
template <class DataType>
bool PostExp<DataType>::GetTwoOperands(DataType&
operand1,DataType& operand2)
{ if(s.IsEmpty()) //判断栈是否空
{ cout<< "缺少右操作数" <<endl; return false; }
operand1=s.Pop();
if(s.IsEmpty())
{ cout<< "缺少左操作数" <<endl; return false; }
operand2=s.Pop(); //去左操作数
return true;
}
//形成运算指令,进行计算
template <class DataType>
void PostExp<DataType>::Compute(char op)
{
bool retult;
DataType operand1,operand2;
retult=GetTwoOperands(operand1,operand2); //取两个操作数if(retult==true) //如果操作数取成功,计算并进栈
switch( op )
{
case '+': s.Push(operand2 + operand1); break;
case '-': s.Push(operand2 - operand1); break;
case '*': s.Push(operand2 * operand1); break;
case '/': if(operand1==0)
{ cout<< "除数为零" <<endl;
exit(1);
}
else
s.Push(operand2 / operand1);
break;
}
else s.~LinkStack();
}
//判断操作数
template <class DataType>
bool PostExp<DataType>::In(char op) //判断操作数
{
switch( op ) //是操作符进行计算
{
case '+' :
case '-' :
case '*' :
case '/' : return true;
default : return false;
}
}
//执行表达式计算
template <class DataType>
void PostExp<DataType>::Run( )
{
char ch;
DataType newOperand;
cout<< "输出后缀表达式,以#结束;" <<endl;
while( cin>>ch,ch!='#')
{
if(In(ch)) Compute(ch);
else //不是操作符,不进行计算
{ cin.putback(ch); //把字符放回操作流
cin>>newOperand; //从新读操作数
Enter(newOperand); //将操作数放入栈中
}
}
if(! s.IsEmpty())cout<< "后缀表达式是:" <<s.GetTop()<<endl; }
//清栈操作
template <class DataType>
void PostExp<DataType>:: Clear( )
{ s.~LinkStack(); }
test.cpp
#include "PostExp.h"
void main(void)
{
PostExp<int> exp;
exp.Run();
}。