首先感谢下面两位博主的帖子!
我直接搬过来用了,根据这个我改写了c++输出真值表的代码,再次感谢!
后缀表达式求值点击打开链接
参考资料1:
1 后缀表达式的求值
将中缀表达式转换成等价的后缀表达式后,求值时,不需要再考虑运算符的优先级,只需从左到右扫描一遍后缀表达式即可。具体求值步骤为:从左到右扫描后缀表 达式,遇到运算符就把表达式中该运算符前面两个操作数取出并运算,然后把结果带回后缀表达式;继续扫描直到后缀表达式最后一个表达式。
例如,后缀表达式(abc*+def*/-) 的求值
2 后缀表达式的求值的算法
设置一个栈,开始时,栈为空,然后从左到右扫描后缀表达式,若遇操作数,则进栈;若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的 放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。此时,栈中仅有一个元素,即为运算的结果。
例,求后缀表达式:1 2 + 8 2 - 7 4 - / * 的值,
栈的变化情如下:
步骤 |
栈中元素 |
说明 |
1 |
1 |
1 进栈 |
2 |
12 |
2 进栈 |
3 |
|
遇+ 号退栈2 和1 |
4 |
3 |
1+2=3 的结果3 进栈 |
5 |
38 |
8 进栈 |
6 |
382 |
2 进栈 |
7 |
3 |
遇- 号退栈2 和8 |
8 |
36 |
8-2=6 的结果6 进栈 |
9 |
367 |
7 进栈 |
10 |
3674 |
4 进栈 |
11 |
36 |
遇- 号退栈4 和7 |
12 |
36 |
7-4=3 的结果3 进栈 |
13 |
3 |
遇/ 号退栈3 和6 |
14 |
32 |
6/3=2 的结果2 进栈 |
15 |
|
遇* 号退栈2 和3 |
16 |
6 |
3*2=6 进栈 |
17 |
6 |
扫描完毕,运算结束 |
从上可知,最后求得的后缀表达式之值为6 ,与用中缀表达式求得的结果一致,但后缀式求值要简单得多。
五、中缀表达式变成等价的后缀表达式的算法
将中缀表达式变成等价的后缀表达式,表达式中操作数次序不变,运算符次序发生变化,同时去掉了圆括号。转换规则是:设立一个栈,存放运算符,首先栈为空, 编译程序从左到右扫描中缀表达式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;若遇到运算符,则必须与栈顶比较,运算符级别比栈顶级 别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。当栈变成空时, 输出的结果即为后缀表达式。将中缀表达式(1+2)*((8-2)/(7-4)) 变成等价的后缀表达式。
现在用栈来实现该运算,栈的变化及输出结果如下:
步骤 |
栈中元素 |
输出结果 |
说明 |
1 |
( |
|
( 进栈 |
2 |
( |
1 |
输出1 |
3 |
(+ |
1 |
+ 进栈 |
4 |
(+ |
1 2 |
输出2 |
5 |
|
1 2 + |
+ 退栈输出,退栈到( 止 |
6 |
* |
1 2 + |
* 进栈 |
7 |
*( |
1 2 + |
( 进栈 |
8 |
*(( |
1 2 + |
( 进栈 |
9 |
*(( |
1 2 + 8 |
输出8 |
10 |
*((- |
1 2 + 8 |
输出2 |
11 |
*((- |
1 2 + 8 2 |
- 进栈 |
12 |
*( |
1 2 + 8 2 - |
- 退栈输出,退栈到( 止 |
13 |
*(/ |
1 2 + 8 2 - |
/ 进栈 |
14 |
*(/( |
1 2 + 8 2 - |
( 进栈 |
15 |
*(/( |
1 2 + 8 2 - 7 |
输出7 |
16 |
*(/(- |
1 2 + 8 2 - 7 |
- 进栈 |
17 |
*(/(- |
1 2 + 8 2 - 7 4 |
输出4 |
18 |
*(- |
1 2 + 8 2 - 7 4 - |
- 退栈输出,退栈到( 止 |
19 |
* |
1 2 + 8 2 - 7 4 - / |
/ 退栈输出,退栈到( 止 |
20 |
|
1 2 + 8 2 - 7 4 - / * |
* 退栈并输出 |
图解后缀表达式的计算过程
参考资料2:
为了解释后缀表达式的好处,我们先来看看,计算机如何应用后缀表达式计算出最终的结果20的。
后缀表达式:9 3 1-3*+ 10 2/+
下面是详细的步骤:
1. 初始化一个空栈。此桟用来对要运算的数字进出使用。
2. 后缀表达式中前三个都是数字,所以9、3、1进栈。
3. 接下来是减号“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再将2进栈。
4. 接着是数字3进栈。
5. 后面是乘法“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。
6. 下面是加法“+”,所以找中6和9出找,9与6相加,得到15,将15进栈。
7. 接着是10与2两数字进栈。
8. 接下来是符号因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈。
9. 最后一个是符号“+”,所以15与5出找并相加,得到20,将20进栈。
10. 结果是20出栈,栈变为空。
#include <iostream>
#include <string>
#include<string.h>
#include <stack>
#include<cstdio>
using namespace std;
//用二维数组为真值表赋值
int table2[4][2]= {{0,0},{0,1},{1,0},{1,1}};
int table3[8][3]= {{0,0,0},{0,0,1},{0,1,0},{1,0,0},
{0,1,1},{1,0,1},{1,1,0},{1,1,1}
};
int table4[16][4]= {{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,1,0,0},
{1,0,0,0},{0,0,1,1},{0,1,0,1},{1,0,0,1},
{0,1,1,0},{1,0,1,0},{1,1,0,0},{0,1,1,1},
{1,1,0,1},{1,0,1,1},{1,1,1,0},{1,1,1,1}
};
//*"合取",+"析取",!"",>"条件",<"双条件"
int prior(char ch)//确定优先级
{
switch(ch)
{
case '!':
return 5;
case '+':
return 3;
case '*':
return 4;
case '>':
return 2;
case '<':
return 1;
default:
return 0;
}
}
bool isOperator(char ch)//判断是否为运算操作符
{
switch(ch)
{
case '!':
case '+':
case '*':
case '>':
case '<':
return true;
default :
return false;
}
}
stack<char>s1;
stack<int>s2;
string getPostfix(string &infix)//中缀表达式转后缀表达式
{
string postfix;
while(!s1.empty())s1.pop();
int i,j,k;
char tmp;
for(i=0; i<infix.size(); i++)
{
tmp=infix[i];
if(isOperator(tmp))
{
while(!s1.empty()&&isOperator(s1.top())&&prior(s1.top())>=prior(tmp))
{
postfix.push_back(s1.top());
s1.pop();
}
s1.push(tmp);
}
else if(tmp=='(')
{
s1.push(tmp);
}
else if(tmp==')')
{
while(s1.top()!='(')
{
postfix.push_back(s1.top());
s1.pop();
}
s1.pop();
}
else if(tmp>='A'&&tmp<='Z')postfix.push_back(tmp);
else
{
printf("请输入合法的表达式
");
break;
}
}
while (!s1.empty())
{
postfix.push_back(s1.top());
s1.pop();
}
return postfix;
}
int Calculate(const string& postfix)//计算后缀表达式
{
int left,right;
int flag;
while(!s2.empty())s2.pop();
for(int i=0; i<postfix.size(); ++i)
{
char c = postfix[i];
switch (c)
{
case '+':
right=s2.top();
s2.pop();
left=s2.top();
s2.pop();
if(left==0&&right==0)flag=0;
else flag=1;
s2.push(flag);
break;
case '*':
right=s2.top();
s2.pop();
left=s2.top();
s2.pop();
if(left==1&&right==1)flag=1;
else flag=0;
s2.push(flag);
break;
case '>':
right=s2.top();
s2.pop();
left=s2.top();
s2.pop();
if(left==1&&right==0)flag=0;
else flag=1;
s2.push(flag);
break;
case '<':
right=s2.top();
s2.pop();
left=s2.top();
s2.pop();
if(left==right)flag=1;
else flag=0;
s2.push(flag);
break;
case '!':
flag=s2.top();
s2.pop();
if(flag==0)flag=1;
else flag=0;
s2.push(flag);
break;
default:
s2.push(c-'0');
break;
}
}
int result = s2.top();
s2.pop();
return result;
}
int Print(string &tmp,char name[],int n)//真值表输出
{
//tmp是中缀式,tmp2是后缀式,n是变量的个数
string tmp2;
tmp2=getPostfix(tmp);
int i,j,k,m;
m=tmp2.size();//m保存后缀式的长度
if(n==1)
{
printf("%5c",name[0]);
printf(" ");
cout<<tmp<<endl;//输出中缀式
for(j=0; j<2; j++)
{
string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
printf("%5d",j);
i=0;
while(i<m)
{
if(tmp1[i]==name[0])tmp1[i]=j+'0';
i++;
}
printf("%5d
",Calculate(tmp1));
}
}
else if(n==2)
{
for(i=0; i<2; i++)printf("%5c",name[i]);
printf(" ");
cout<<tmp<<endl;//输出中缀式
for(j=0; j<4; j++)
{
string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
for(k=0; k<2; k++)printf("%5d",table2[j][k]);
i=0;
while(i<m)
{
if(tmp1[i]==name[0])tmp1[i]=table2[j][0]+'0';
else if(tmp1[i]==name[1])tmp1[i]=table2[j][1]+'0';
i++;
}
printf("%5d
",Calculate(tmp1));
}
}
else if(n==3)
{
for(i=0; i<3; i++)printf("%5c",name[i]);
printf(" ");
cout<<tmp<<endl;//输出中缀式
for(j=0; j<8; j++)
{
string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
for(k=0; k<3; k++)printf("%5d",table3[j][k]);
i=0;
while(i<m)
{
if(tmp1[i]==name[0])tmp1[i]=table3[j][0]+'0';
else if(tmp1[i]==name[1])tmp1[i]=table3[j][1]+'0';
else if(tmp1[i]==name[2])tmp1[i]=table3[j][2]+'0';
i++;
}
printf("%5d
",Calculate(tmp1));
}
}
else if(n==4)
{
for(i=0; i<4; i++)printf("%5c",name[i]);
printf(" ");
cout<<tmp<<endl;//输出中缀式
for(j=0; j<16; j++)
{
string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
for(k=0; k<4; k++)printf("%5d",table4[j][k]);
i=0;
while(i<m)
{
if(tmp1[i]==name[0])tmp1[i]=table4[j][0]+'0';
else if(tmp1[i]==name[1])tmp1[i]=table4[j][1]+'0';
else if(tmp1[i]==name[2])tmp1[i]=table4[j][2]+'0';
else if(tmp1[i]==name[3])tmp1[i]=table4[j][3]+'0';
i++;
}
printf("%5d
",Calculate(tmp1));
}
}
}
bool judge(char name[])//判断变量名是否合法
{
int i,n=strlen(name);
if(n>=5)return false;
for(i=0; i<n; i++)if(name[i]<'A'||name[i]>'Z')return false;
return true;
}
int main()
{
int i,n;
char variablename[10];
printf("------------------------------------------------
");
printf(" 欢迎使用真值表计算程序!!!
");
printf("------------------------------------------------
");
while(1)
{
printf("请您输入变量名(温馨提示:变量名均为大写字母,变量名之间不能有空格,可输入Esc退出本程序)
");
scanf("%s",variablename);//输入变量名
if(strcmp(variablename,"Esc")==0)break;
n=strlen(variablename);
if(!judge(variablename))//判断变量名输入是否合法
{
printf("表达式不合法或者变元超过四个,请重新输入
");
continue;
}
string postfixtmp;
printf("请您输入合法表达式(*表示合取,+表示析取,!表示非,>表示条件,<表示双条件)
");
cin>>postfixtmp;
Print(postfixtmp,variablename,n);//输出真值表
}
return 0;
}
参考代码:
#include <iostream>
#include <string>
#include <stack>
using namespace std;
int prior(char c)
{
switch (c)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
bool isOperator(char c)
{
switch (c)
{
case '+':
case '-':
case '*':
case '/':
return true;
default:
return false;
}
}
string getPostfix(const string& expr)
{
string output; // 输出
stack<char> s; // 操作符栈
for(int i=0; i<expr.size(); ++i)
{
char c = expr[i];
if(isOperator(c))
{
while(!s.empty() && isOperator(s.top()) && prior(s.top())>=prior(c))
{
output.push_back(s.top());
s.pop();
}
s.push(c);
}
else if(c == '(')
{
s.push(c);
}
else if(c == ')')
{
while(s.top() != '(')
{
output.push_back(s.top());
s.pop();
}
s.pop();
}
else
{
output.push_back(c);
}
}
while (!s.empty())
{
output.push_back(s.top());
s.pop();
}
return output;
}
// 从栈中连续弹出两个操作数
void popTwoNumbers(stack<int>& s, int& first, int& second)
{
first = s.top();
s.pop();
second = s.top();
s.pop();
}
// 计算后缀表达式的值
int Calculate(string& postfix)
{
int first,second;
stack<int>s;
for(int i=0; i<postfix.size(); ++i)
{
char c = postfix[i];
switch (c)
{
case '+':
popTwoNumbers(s, first, second);
s.push(second+first);
break;
case '-':
popTwoNumbers(s, first, second);
s.push(second-first);
break;
case '*':
popTwoNumbers(s, first, second);
s.push(second*first);
break;
case '/':
popTwoNumbers(s, first, second);
s.push(second/first);
break;
default:
s.push(c-'0');
break;
}
}
int result = s.top();
s.pop();
return result;
}
int main()
{
string expr = "5+2*(6-3)-4/2";
string postfix =getPostfix(expr);
int result = Calculate(postfix);
cout << "The result is: " << result << endl;
return 0;
}