c++实现真值表
首先感謝下面兩位博主的帖子!
我直接搬過來用了,根據這個我改寫了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出棧,棧變為空。
- 果然,后綴表達法可以很順利解決計算的問題。但是我有個疑問,就是這個后綴表達式“9 3 1-3*+ 10 2/+”是如何通過算式“9+(3-1)*3+10/2”變化而來呢?
#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("請輸入合法的表達式\n");
? ? ? ? ? ? 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\n",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\n",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\n",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\n",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("------------------------------------------------\n");
? ? printf(" ? ? ? ? 歡迎使用真值表計算程序!!!\n");
? ? printf("------------------------------------------------\n");
? ? while(1)
? ? {
? ? ? ? printf("請您輸入變量名(溫馨提示:變量名均為大寫字母,變量名之間不能有空格,可輸入Esc退出本程序)\n");
? ? ? ? scanf("%s",variablename);//輸入變量名
? ? ? ? if(strcmp(variablename,"Esc")==0)break;
? ? ? ? n=strlen(variablename);
? ? ? ? if(!judge(variablename))//判斷變量名輸入是否合法
? ? ? ? {
? ? ? ? ? ? printf("表達式不合法或者變元超過四個,請重新輸入\n");
? ? ? ? ? ? continue;
? ? ? ? }
? ? ? ? string postfixtmp;
? ? ? ? printf("請您輸入合法表達式(*表示合取,+表示析取,!表示非,>表示條件,<表示雙條件)\n");
? ? ? ? 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;
}
總結
- 上一篇: 通过Wireshark抓包疯狂聊天程序聊
- 下一篇: 如何VisualSVN备份到不同Wind