数据结构 栈的应用 --表达式求值
Posted 佩喻幻的Blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 栈的应用 --表达式求值相关的知识,希望对你有一定的参考价值。
一: 中缀表达式求值
思想:
需要2个栈,运算对象栈OPND,运算符栈OPTR,
1:将栈OPND初始化为空,栈OPTR初始化为表达式的定界符#
2:扫描表达式,直到遇到结束符#
2.1:当前字符是运算对象,入栈OPND
2.2:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级高,入栈OPTR,处理下一个字符
2.3:当前字符是运算符且优先级比栈OPTR的栈顶运算符优先级低,则从栈OPND出栈2个运算对象,从栈OPTR出栈一个运算符进行运算,并将运算结果入栈OPND,处理当前字符
2.4:当期字符是运算符且优先级与栈OPTR的栈顶运算符的优先级相同,将栈OPTR的栈顶运算符出栈,出理下一个字符。
3:输出栈OPND中的栈顶元素,即运算结果
//expseqstack.h
//10只是示例性的数据,可以根据实际问题具体定义
const int StackSize=10; typedef struct { char op; int inputprecedence; int stackprecedence; }DataType1; template <class T> //定义模板类SeqStack class SeqStack { public: SeqStack(); //构造函数,栈的初始化 ~SeqStack(); //析构函数 void init(); void Push(T x); //将元素x入栈 T Pop(); //将栈顶元素弹出 T GetTop(); //取栈顶元素(并不删除) bool Empty(); //判断栈是否为空 public: T data[StackSize]; //存放栈元素的数组 int top; //栈顶指针,指示栈顶元素在数组中的下标 }; /* * 前置条件:栈不存在 * 输 入:无 * 功 能:栈的初始化 * 输 出:无 * 后置条件:构造一个空栈 */ template <class T> SeqStack<T>::SeqStack() { top=-1; } /* * 前置条件:栈已存在 * 输 入:无 * 功 能:销毁栈 * 输 出:无 * 后置条件:释放栈所占用的存储空间 */ template <class T> SeqStack<T>::~SeqStack() { } template <class T> void SeqStack<T>::init() { top=0; } /* * 前置条件:栈已存在 * 输 入:元素值x * 功 能:在栈顶插入一个元素x * 输 出:如果插入不成功,抛出异常 * 后置条件:如果插入成功,栈顶增加了一个元素 */ template <class T> void SeqStack<T>::Push(T x) { if (top== StackSize-1) throw "上溢"; top++; data[top]=x; } /* * 前置条件:栈已存在 * 输 入:无 * 功 能:删除栈顶元素 * 输 出:如果删除成功,返回被删元素值,否则,抛出异常 * 后置条件:如果删除成功,栈顶减少了一个元素 */ template <class T> T SeqStack<T>::Pop() { T x; if (top==-1) throw "下溢"; x=data[top--]; return x; } /* * 前置条件:栈已存在 * 输 入:无 * 功 能:读取当前的栈顶元素 * 输 出:若栈不空,返回当前的栈顶元素值 * 后置条件:栈不变 */ template <class T> T SeqStack<T>::GetTop() { if (top!=-1) return data[top]; } /* * 前置条件:栈已存在 * 输 入:无 * 功 能:判断栈是否为空 * 输 出:如果栈为空,返回1,否则,返回0 * 后置条件:栈不变 */ template <class T> bool SeqStack<T>::Empty() { if(top==-1) return 1; else return 0; }
//main.cpp #include"expseqstack.h" #include<iostream> #include<string> using namespace std; //检查符号之间的优先级,1表示>,0表示=,-1表示<,c1栈内的运算,c2栈外的运算 int check(char c1, char c2) { int a1, a2; if (c1 == ‘+‘ || c1 == ‘-‘) a1 = 3; if (c1 == ‘*‘ || c1 == ‘/‘) a1 = 5; if (c1 == ‘(‘) a1 = 1; if (c1 == ‘)‘) a1 = 7; if (c1 == ‘#‘) a1 = 0; if (c2 == ‘+‘ || c2 == ‘-‘) a2 = 2; if (c2 == ‘*‘ || c2 == ‘/‘) a2 = 4; if (c2 == ‘(‘) a2 = 6; if (c2 == ‘)‘) a2 = 1; if (c2 == ‘#‘) a2 = 0; if (a1 > a2) return 1; if (a1 == a2) return 0; if (a1 < a2) return -1; } //符号运算函数 double sum(char c, double d1, double d2) { switch (c) { case ‘+‘: return d1 + d2; break; case ‘-‘: return d1 - d2; break; case ‘*‘: return d1 * d2; break; case ‘/‘: return d1 / d2; break; default: break; } } int main() { char *op = "+-*/()#"; string str; cout<<"请输入表达式:"<<endl; cin>>str; //给表达式字符串str添加‘#’结束标志符 str.append(1, ‘#‘); SeqStack<char> OPTR;//运算符栈 SeqStack<double> OPND;//操作数栈 int a = -1; //先将‘#‘入栈 OPTR.Push(‘#‘); while (true) { int b = a + 1; a = str.find_first_of(op, a + 1); if (a == string::npos) break; if (a != b) { string ss(str, b, a - b); double d = atof(ss.c_str()); //数据先入栈 OPND.Push(d); } //运算符优先级比较 char val; val=OPTR.GetTop(); int che = check(val, str[a]); if (-1 == che)//栈外优先级大直接入栈 { OPTR.Push(str[a]); } if (0 == che)//栈内外优先级相等则出栈 { OPTR.Pop(); } if (1 == che)//栈内优先级大,出栈进行运算 { char val; double d1; double d2; val=OPTR.GetTop(); d1=OPND.GetTop(); d1=OPND.Pop(); d2=OPND.GetTop(); d2=OPND.Pop(); d1 = sum(val, d2, d1); //运算结果入栈 OPND.Push(d1); OPTR.Pop(); a--; } } double s; s=OPND.GetTop(); cout <<s<<endl; return 0; }
二:中缀表达式转后缀表达式并求值
中缀表达式转后缀表达式思想:
1:栈S初始化为空栈
2:扫描表达式的每个字符,
2.1:当前字符是运算对象,输出此字符,处理下一个字符
2.2:当前字符是运算符且优先级比栈S的栈顶的运算符优先级高,此字符入栈S,处理下一个字符
2.3:当前字符是运算符且优先级比栈S的栈顶的运算符优先级低,则将栈S的栈顶元素弹出并输出
2.4:当前字符是运算符且优先级比栈S的栈顶的运算符优先级相同,则将栈S的栈顶元素弹出,处理下一个字符
注:只有遇到 ) 的情况下,才弹出 ( ,但不输出。
例子:中缀表达式 3*(4+2)/2-5 ====>>后缀表达式3 4 2 + * 2 / 5 -
3 后缀表达式求值:
1:初始化栈S
2:扫描当前表达式
2.1当前字符是运算对象,则入栈S,处理下一个字符
2.2当前字符是运算符,则从栈S出栈2个运算对象,执行运算并将结果入栈S,处理下一个字符
3:输出栈S的栈顶元素,就是表达式结果。
//头文件 PrefixToPostfix.h #include <vector> using namespace std; bool isoperator(char op); // 判断是否为运算符 int priority(char op); // 求运算符优先级 void postfix(char pre[] , char post[],int &n); // 把中缀表达式转换为后缀表达式 double read_number(char str[],int *i); // 将数字字符串转变成相应的数字 double postfix_value(char post[]); // 由后缀表达式字符串计算相应的中值表达式的值
//PrefixToPostfix.cpp #include "PrefixToPostfix.h" #include"expseqstack.h" #include <iostream> using namespace std; bool isoperator(char op) { switch(op) { case ‘+‘: case ‘-‘: case ‘*‘: case ‘/‘: return 1; default : return 0; } } int priority(char op) { switch(op) { case ‘#‘: return -1; case ‘(‘: return 0; case ‘+‘: case ‘-‘: return 1; case ‘*‘: case ‘/‘: return 2; default : return -1; } } // 把中缀表达式转换为后缀表达式,返回后缀表达式的长度(包括空格) void postfix(char pre[] ,char post[],int &n) { int i = 0 ,j=0; SeqStack<char> stack; stack.init(); // 初始化存储操作符的栈 stack.Push(‘#‘); // 首先把结束标志‘#’放入栈底 while(pre[i]!=‘#‘) { if((pre[i]>=‘0‘ && pre[i] <=‘9‘)||pre[i] ==‘.‘) // 遇到数字和小数点直接写入后缀表达式 { post[j++] = pre[i]; n++; } else if (pre[i]==‘(‘) // 遇到“(”不用比较直接入栈 stack.Push(pre[i]); else if(pre[i] ==‘)‘) // 遇到右括号将其对应左括号后的操作符(操作符栈中的)全部写入后缀表达式 { while(stack.GetTop()!=‘(‘) { post[j++] = stack.Pop(); n++; } stack.Pop(); // 将“(”出栈,后缀表达式中不含小括号 } else if (isoperator(pre[i])) { post[j++] = ‘ ‘; // 用空格分开操作数( n++; while(priority(pre[i]) <= priority(stack.GetTop())) { // 当前的操作符小于等于栈顶操作符的优先级时,将栈顶操作符写入到后缀表达式,重复此过程 post[j++] = stack.Pop(); n++; } stack.Push(pre[i]); // 当前操作符优先级大于栈顶操作符的优先级,将该操作符入栈 } i++; } while(stack.top) // 将所有的操作符加入后缀表达式 { post[j++] = stack.Pop(); n++; } } double read_number(char str[],int *i) { double x=0.0; int k = 0; while(str[*i] >=‘0‘ && str[*i]<=‘9‘) // 处理整数部分 { x = x*10+(str[*i]-‘0‘); (*i)++; } if(str[*i]==‘.‘) // 处理小数部分 { (*i)++; while(str[*i] >= ‘0‘&&str[*i] <=‘9‘) { x = x * 10 + (str[*i]-‘0‘); (*i)++; k++; } } while(k!=0) { x /= 10.0; k--; } return x; } double postfix_value(char post[]) { SeqStack<double> stack; // 操作数栈 stack.init(); int i=0 ; double x1,x2; while(post[i] !=‘#‘) { if(post[i] >=‘0‘ && post[i] <=‘9‘) stack.Push(read_number(post,&i)); else if(post[i] == ‘ ‘) i++; else if (post[i] ==‘+‘) { x2 = stack.Pop(); x1 = stack.Pop(); stack.Push(x1+x2); i++; } else if (post[i] ==‘-‘) { x2 = stack.Pop(); x1 = stack.Pop(); stack.Push(x1-x2); i++; } else if (post[i] ==‘*‘) { x2 = stack.Pop(); x1 = stack.Pop(); stack.Push(x1*x2); i++; } else if (post[i] ==‘/‘) { x2 = stack.Pop(); x1 = stack.Pop(); stack.Push(x1/x2); i++; } } return stack.GetTop(); }
//main.cpp #include "PrefixToPostfix.h" #include"expseqstack.h" #include <iostream> using namespace std; void main() { SeqStack<int> stack ; stack.init(); //char pre[] ="22/(5*2+1)#"; char exp[100]; cout << "输入表达式(中缀,以#结束):"; cin >> exp; char post[100] ; //cout <<"中缀表达式为:"<< pre << endl; int n =0; // 返回后缀表达式的长度 postfix(exp,post,n); cout <<"后缀表达式为:"; for( int i =0 ;i < n ;i++) cout << post[i] ; cout << "\n由后缀表达式计算出的数值结果: "; cout << postfix_value(post) << endl; system("pause"); }
以上是关于数据结构 栈的应用 --表达式求值的主要内容,如果未能解决你的问题,请参考以下文章