命题逻辑之真值表
①C語言版
亮點:
1.qsort(b, j, sizeof(char), cmp);
C語言標準庫函數
2.while(處理括號 || 處理否定 || 處理合取 ... );
可以消除運算符優先級的問題,但是還是解決不了同級運算符的先后問題。
如:p+q*r會變成p+(q*r)
3.模擬輾轉相除法給變元賦值
代碼簡單明了,但是效率比不上位運算
#include "string.h" #include "stdio.h" #include "ctype.h" #include "stdlib.h"int cmp(const void* a, const void* b) {return (*((char*) a) - *((char*) b)); }int getalpha(char a[],char b[]) {char tmpc=' ';int n=strlen(a),i=0,j=0,k=0;for(i=0; i<n; i++){if(isalpha(a[i])) //改進1:使用isalpha()函數判斷大小寫,簡潔明了// if(((a[i]>='a')&&(a[i]<='z'))||((a[i]>='A')&&(a[i]<='Z'))){for(k=0; k<j; k++){if(b[k]==a[i]){break;}}if(k>=j){b[j]=a[i];j++;}}}qsort(b,j,sizeof(char),cmp); //改進2:用快排代替冒泡排序,提高效率/* for(i=0; i<j-1; i++){for(k=0; k<j-i-1; k++){if(b[k]>b[k+1]){tmpc=b[k];b[k]=b[k+1];b[k+1]=tmpc;}}}*/b[j]='\0';return j; }void fillValue(char a[],char varchar[],int nvar,char valchar[],char resultchar[]) {//a是原始公式,varchar是變元列表如pqrs,//valchar是變元的某次取值int nLen=strlen(a),i=0,j=0,k=0;for(i=0; i<nLen; i++)resultchar[i]=a[i];resultchar[i]='\0';for(i=0; i<nLen; i++){//原公式中的每個字符for(j=0; j<nvar; j++){//公式中的字符是第幾個變元if(resultchar[i]==varchar[j]){//是第j個變元,其值換成第j個值resultchar[i]=valchar[j];break;}}} }bool negatecal(char a[]) //改進5:將函數返回類型改為bool,若在字符串中存在!1或!0,就把第一個!1或!0改成0或1,然后返回true;如果沒找到,返回false //void negatecal(char a[]) //...下面的函數進行完全相同的修改 {int _result=0,i=0,j=0;while(i<strlen(a)){//如果當前位置起形如"!1"則換成"1"j=i;_result=0;if((j+1<strlen(a))&&(a[j]=='!')&&(a[j+1]=='1')){a[j]='0';_result=1;}else if((j+1<strlen(a))&&(a[j]=='!')&&(a[j+1]=='0')){a[j]='1';_result=1;}if(_result==1){//如果有運算則后面的往前移j++;while(a[j+1]!='\0'){//后面的字符往前移1格a[j]=a[j+1];j++;}a[j]='\0';return 1; //改進5}else{//沒有!0或!1則看下一個指針i++;}}return 0; //改進5 }bool kuanhao(char a[]) {int _result=0,i=0,j=0;while (i<strlen(a)) //如果當前位置起形如(1)則換成1{j=i;_result=0;if ((j+2<strlen(a))&&(a[j]=='(')&&(a[j+1]=='1')&&(a[j+2]==')')){a[j]='1';_result=1;}else if ((j+2<strlen(a))&&(a[j]=='(')&&(a[j+1]=='0')&&(a[j+2]==')')){a[j]='0';_result=1;}if (_result==1){j++;while (a[j+2]!='\0'){a[j]=a[j+2];j++;}a[j]='\0';return 1;}else{i++;}}return 0; }bool conYsh(char a[]) {int _result=0,i=0,j=0;while (i<strlen(a)) //如果當前位置其形如1*1則換成"1"{j=i;_result=0;if ((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='*')&&(a[j+2]=='0')){a[j]='0';_result=1;}else if ((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='*')&&(a[j+2]=='1')){a[j]='0';_result=1;}else if ((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='*')&&(a[j+2]=='0')){a[j]='0';_result=1;}else if ((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='*')&&(a[j+2]=='1')){a[j]='1';_result=1;}if (_result==1){j++;while (a[j+2]!='\0'){a[j]=a[j+2];j++;}a[j]='\0';return 1;}else{i++;}}return 0; }bool biCondYsh (char a[]) //1=1 {int _result=0,i=0,j=0;while(i<strlen(a)){j=i;_result=0;if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='=')&&(a[j+2]=='0')){a[j]='1';_result=1;}else if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='=')&&(a[j+2]=='1')){a[j]='0';_result=1;}else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='=')&&(a[j+2]=='0')){a[j]='0';_result=1;}else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='=')&&(a[j+2]=='1')){a[j]='1';_result=1;}if(_result==1){j++;while(a[j+2]!='\0'){a[j]=a[j+2];j++;}a[j]='\0';return 1;}else{i++;}}return 0; }bool condYsh(char a[]) //1-1 {int _result=0,i=0,j=0;while(i<strlen(a)){j=i;_result=0;if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='-')&&(a[j+2]=='0')){a[j]='1';_result=1;}else if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='-')&&(a[j+2]=='1')){a[j]='1';_result=1;}else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='-')&&(a[j+2]=='0')){a[j]='0';_result=1;}else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='-')&&(a[j+2]=='1')){a[j]='1';_result=1;}if(_result==1){j++;while(a[j+2]!='\0'){a[j]=a[j+2];j++;}a[j]='\0';return 1;}else{i++;}}return 0; }bool disConjYsh(char a[]) {int _result=0,i=0,j=0;while (i<strlen(a)){j = i;_result =0;if ((j+2<strlen(a)) && (a[j]=='0') && (a[j+1]=='+')&& (a[j+2]=='0')){a[j] = '0' ;_result=1;}else if ((j+2<strlen(a)) && (a[j]=='0') && (a[j+1]=='+')&& (a[j+2]=='1')){a[j] = '1';_result=1;}else if ((j+2<strlen(a)) && (a[j]=='1') && (a[j+1]=='+')&& (a[j+2]=='0')){a[j] ='1' ;_result=1;}else if ((j+2<strlen(a)) && (a[j]=='1') && (a[j+1]=='+')&& (a[j+2]=='1')){a[j] ='1' ;_result=1;}if (_result==1){j ++;while (a[j+2]!='\0'){a[j]=a[j+2];j++;}a[j]='\0';return 1;}else{i++;}}return 0; }int main(int argc,char* argv[]) {char pstate[120],pstate0[120],charList[120],charVal[120];char minItem[1024][52],truetable[1024]; //最多10個變量int i=0,nold=0,nnew=0,nvar=1,nRow=1,j=0,iMinItem=0; // int flagsum=1; printf("請輸入公式(析+,合*,條-,雙=,否定!01) \n");gets(pstate0);fflush(stdin);nold=strlen(pstate0)+1;nnew=strlen(pstate0);strcpy(pstate,pstate0); //改進3:strcpy函數拷貝字符串,簡單快捷/* for(i=0; i<nnew; i++){pstate[i]=pstate0[i];}pstate[i]='\0';*/nvar=getalpha(pstate,charList);//真值表各個變元的值nRow=1;for(i=0; i<nvar; i++){charVal[i]='0';nRow=nRow*2;}charVal[i]='\0';//真值表的首行printf("\n");for(i=0; i<nvar; i++)printf("%4c",charList[i]);printf("%15c%s\n",' ',pstate);for(i=0; i<nvar; i++)printf("%4c",'-');printf("|");for(i=0; i<60; i++)printf("%c",'-');printf("\n"); int num; //為改進4作鋪墊for(i=0; i<nRow; i++){num = i;for(j=nvar-1; j>=0; j--) //改進4:new algorithm: 模擬"輾轉相除法"給charList賦值,更簡潔明了{charVal[j] = num % 2 + '0';num /= 2;}//真值表各行for(j=0; j<nvar; j++)printf("%4c",charVal[j]);//將值填入到公式中pstate[0]='\0';fillValue(pstate0,charList,nvar,charVal,pstate);while(negatecal(pstate)||kuanhao(pstate)||conYsh(pstate)||disConjYsh(pstate)||condYsh(pstate)||biCondYsh(pstate));//改進5:利用||的短路性質,保證處理順序:否定、括號、合取析取、條件。消除了原代碼的BUG/* nold=strlen(pstate0)+1; //原來處理字符串的辦法 nnew=strlen(pstate);while(nnew<nold){nold=strlen(pstate);negatecal(pstate); //否定kuanhao(pstate); // (A)conYsh(pstate); //1*1biCondYsh(pstate); //1=1condYsh(pstate); //1-1disConjYsh(pstate); //1+1nnew=strlen(pstate);}*/if(strlen(pstate)==1){if(pstate[0]=='1'){for (j=0; j<nvar; j++)minItem[iMinItem][j]=charVal[j];minItem[iMinItem][j]='\0';iMinItem++;}truetable[i]=pstate[0];}printf("%20c%s",' ',pstate);printf("\n");/* flagsum=1; //原算法:進位法 for(j=nvar-1; j>=0; j--){if(charVal[j]=='1'){if(flagsum==1) {charVal[j]='0';flagsum=1;}else //1+0=1 不變{break;}}else if(charVal[j]=='0'){if(flagsum==1) {charVal[j]='1';flagsum=0;} //0+0結束else{break;}}}*/}for (i=0; i<iMinItem; i++){if (i==0)printf("m%s",minItem[i]);elseprintf("+m%s",minItem[i]);}printf("\n");for (i=0; i<iMinItem; i++){if(i==0){printf("(");for (j=0; j<nvar; j++){if (j==0){if (minItem[i][j]=='1')printf("%c",charList[j]);elseprintf("!%c",charList[j]);}else{if (minItem[i][j]=='1')printf("*%c",charList[j]);elseprintf("*!%c",charList[j]);}}printf(")");}else{printf("+(");for(j=0; j<nvar; j++){if (j==0){if (minItem[i][j]=='1')printf("%c",charList[j]);elseprintf("!%c",charList[j]);}else{if (minItem[i][j]=='1')printf("*%c",charList[j]);elseprintf("*!%c",charList[j]);}}printf(")");}} }運行結果展示:
②C++11版
亮點:
1.使用map容器儲存變元—>0/1的映射
2.合理使用STL中的string::find和replace函數
3.增加判斷了公式是否合法
// !否定,*合取,+析取,-條件,=雙條件 #include <iostream> #include <cstring> #include <vector> #include <cctype> #include <cmath> #include <map> using namespace std;map<char, bool> letter; //用紅黑樹結構建立 p/q/r -> 0/1 的映射 //優點:查找方便且速度快,按字典順序排序 vector<int> minum; vector<int> maxum;void setLetter( int num ) //set p/q/r with 0/1 {for (auto p = letter.rbegin(); p != letter.rend(); ++p) //new algorithm:模擬輾轉相除法給p/q/r賦值{p->second = num % 2;num /= 2;} }bool rps( string& a, string f, string r ) //replace f with r in string a {if (a.find( f ) != string::npos) //string::find {a.replace( a.find( f ), f.length(), r ); //string::replace return true;}return false; }void setString( string& a ) //replace p/q/r with 0/1 in string {for (auto &p : a)if (islower( p )){if (letter[p]) p = '1';else p = '0';} }int getResult( string& tmp ) //get the result true/false {//利用||判斷符的"短路性",按照運算符優先級給原字符串替換,消除了原版本的bug while (rps( tmp, "(0)", "0" ) || rps( tmp, "(1)", "1" ) ||rps( tmp, "!0", "1" ) || rps( tmp, "!1", "0" ) ||rps( tmp, "0+0", "0" ) || rps( tmp, "0+1", "1" ) || rps( tmp, "1+0", "1" ) || rps( tmp, "1+1", "1" ) ||rps( tmp, "0*0", "0" ) || rps( tmp, "0*1", "0" ) || rps( tmp, "1*0", "0" ) || rps( tmp, "1*1", "1" ) ||rps( tmp, "0-0", "1" ) || rps( tmp, "0-1", "1" ) || rps( tmp, "1-0", "0" ) || rps( tmp, "1-1", "1" ) ||rps( tmp, "0=0", "1" ) || rps( tmp, "0=1", "0" ) || rps( tmp, "1=0", "0" ) || rps( tmp, "1=1", "1" ));if (tmp == "1") return 1;else if (tmp == "0") return 0;else return -1; }void print( int num, bool isMax, int count ) //print the min_item or max_item {int temp = 0;setLetter( num );for (auto p = letter.begin(); p != letter.end(); ++p, ++temp){if (p->second ^ isMax) cout << p->first; //異或運算:若是小項,則輸出值為0的變元;若是大項,輸出值為1的變元 else cout << "!" << p->first;if (temp != count - 1){if (isMax) cout << "+";else cout << "*";}} }int main() {string input, tmp;cout << "說明:!否定,*合取,+析取,-條件,=雙條件" << endl;cout << "請輸入公式:";cin >> input;tmp = input;for (auto p : input)if (islower( p )) letter[p] = 0; //把字母建立到map容器中去 setString( tmp );if (getResult( tmp ) == -1) //首先判斷公式是否合法 {cout << input << " 不合法!" << endl;return 0;}cout << endl << "真值表:" << endl;for (auto p : letter)cout << p.first << ' ';cout << '|' << input << endl;int count = pow( 2, letter.size() );for (int i = 0; i < count; ++i) //for i = 0 to 2^letter_number{tmp = input;setLetter( i );setString( tmp );for (auto p : letter)cout << p.second << ' ';cout << '|';for (int j = 0; j < input.size() / 2; ++j)cout << ' ';if (getResult( tmp )) //如果結果為1 {cout << 1 << endl;minum.push_back( i ); //儲存到小項數組 }else{cout << 0 << endl;maxum.push_back( i );}}//print 主合/主析 cout << endl << "主析取范式:";if (minum.size() == 1) print( minum[0], false, letter.size() );else{for (auto p = minum.begin(); p != minum.end(); ++p){cout << "(";print( *p, false, letter.size() );cout << ")";if (p != minum.end() - 1) cout << "+";}}cout << endl << endl;cout << "主合取范式:";if (maxum.size() == 1) print( maxum[0], true, letter.size() );else{for (auto p = maxum.begin(); p != maxum.end(); ++p){cout << "(";print( *p, true, letter.size() );cout << ")";if (p != maxum.end() - 1) cout << "*";}}cout << endl << endl;system( "pause" );return 0; } 運行結果:總結
- 上一篇: 第一次网络渗透实验报告
- 下一篇: 指针和对象