离散数学上机实验,给定一个命题公式,求其主析取范式,主合取范式,能力有限,参考了我学长的一篇博客,并进行了许多优化。
本次离散数学实验,我学到了许多东西,也看了自己的不足之处
1).我深刻地体会到在比较大型的软件的开发过程中预先进行设计的重要性,就拿这个小程序来说,
如果不预先设计好程序需要的算法,各个函数,解决方法的一步步流程,那么在真正开发过程中效率将大大降低,会不断地删除修改,有时候甚至要重写,这都是事先没有进行计划的原因。
2).程序设计中算法的重要性,本程序用到了将命题公式转化为逆波兰表达式的算法,我起先一点也不会,但是看了学长的源代码理解了个大概,自己又仔细琢磨琢磨,也就写出来了,但是现在让我独立再写一遍我是真的 写不出来了
3).大型程序中函数名称的规范性,起先我嫌弃命名规范的话敲起代码来很不舒服,可是随着程序越来越大,程序变得越来越难读,最终我全部换成了能一眼看出功能函数名
4).要学会版本控制系统
各个版本原代码:各个版本代码
#include <cstdio> #include <cstring> #include <windows.h> #include <iostream> using namespace std; string Original_Formula;//用户输入的命题公式 string Simp_Formula;//将用户输入的命题公式中->和<->转化为>和~ string Suffix_Formula;//将简化后的式子转化为后缀表达式 string PCNF;//主合取范式 string PDNF;//主析取范式 char ch[15]="()PQRST!&|-><";//把用户输入的式子简化时需要该语句 int p,q,r,s,t;//for循环打印真值表时使用 int a,b,res;//逻辑运算时使用,比如a==1, b==0传到了And()(合取函数)里,这时候res为0; int v=0;//还未写注释 int var_cnt;//计算用户输入的变量的个数(各不相同的变量的个数,重复的算一个) //用一个类来模拟栈 class Stack { public: Stack(int mSize) { maxtop=mSize-1; //maxtop为st数组下标最大值,mSize为st数组元素个数 st=new char[mSize];//动态内存分配 top=-1; } ~Stack()//析构函数,释放st[]内存 { delete[]st; } bool Push(char x)//模拟入栈 { if(top==maxtop)//如果栈溢出,返回false return false; st[++top]=x; return true; } bool Pop() { if(top==-1) return false; top--;//模拟出栈 return true; } char Top() { return st[top];//模拟取栈顶元素 } private: int top; char *st; int maxtop; }; void Not();//非运算 void And();//合取运算 void Or();//析取运算 void If();//条件运算 void Iif();//双条件运算 void Menu();//打印菜单,增强用户体验 void count_varcnt();////计算用户输入的变量的个数(各不相同的变量的个数,重复的算一个) void InputANDjude_formula();// 用户输入的命题公式并进行检查,如果有异常输入,输出警告,并重新输入 bool Jude_canin(char);//判断运算符能否入栈 void Change_to_sufexp();//将处理后的命题公式转化为逆波兰表达式 void Calculate();//进行逻辑运算 void Print();//打印结果 void Not_Not(char);//忘记了,稍后补回来 void Switch_Operator(char);//运算符优先级,判断能否进栈 bool Enh_Robustness();//增强程序鲁棒性 Stack Sim_stack(200);//构造一个类对象,Sim_stack int main() { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);//Windows编程的小知识,看不懂的话可以将这样的语句全部删除不影响,这些全部用来控制窗口文字的颜色 Menu();//输出菜单 while(1) { do { InputANDjude_formula();//当检测到用户非法输入时,让用户再次输入 }while(!Enh_Robustness()); if(Original_Formula=="Over")//用户输入Over可结束程序 { SetConsoleTextAttribute(hConsole, 0xC ); cout<<"\\\\*^o^*// 谢谢使用 \\\\*^o^*//"<<endl; SetConsoleTextAttribute(hConsole, 0xF ); system("pause"); return 0; } count_varcnt();//计算出用户输入的变量的个数 Change_to_sufexp();//将处理后的命题公式转化为逆波兰表达式 Print();//打印 } return 0; } /***********************************打印菜单*********************************************/ void Menu() { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hConsole, 0xB ); cout<<"******************离散数学之数理逻辑******************"<<endl; cout<<"****************** 输入符号规定 ******************"<<endl; cout<<"****************** ┐:! ******************"<<endl; cout<<"****************** ∧:& ******************"<<endl; cout<<"****************** ∨:| ******************"<<endl; cout<<"****************** →:-> ******************"<<endl; cout<<"****************** ←→:<-> ******************"<<endl; cout<<"******************************************************"<<endl; cout<<endl; SetConsoleTextAttribute(hConsole, 0xC ); cout<<"必读:1.支持括号"<<endl; cout<<" 2.最多支持五个不同变元(P,Q,R,S,T),最少两个变元"<<endl; cout<<" 3.两个变元用P,Q;三个用P,Q,R:以此类推"<<endl; cout<<" 3.输入时请注意大小写及英文状态下输入符号"<<endl; cout<<" 4.十分感谢我校***学长的热心指导"<<endl; cout<<" 5.时间仓促,程序可能存在bug,如有发现请及时告知,十分感谢"<<endl; cout<<" 6.2016.3 12-17 By:******** ****1.8版本****"<<endl; cout<<"\n"<<endl; SetConsoleTextAttribute(hConsole, 0xF ); } /***********************************打印菜单*********************************************/ /*************************输入并且进行简化************************************************/ void InputANDjude_formula() { char str1[100]={0}, str2[100], str3[100]; //str1为输入式子,str2为处理后的式子,并将处理后的式子赋给Simp_Formula int cnt=0; cout<<"请输入命题公式:(输入Over可结束程序)"<<endl; gets(str1); //疑惑:将str1, str2改为全局变量后程序出错 要用gets(),不然鲁棒性不强 for(int i=0;i<strlen(str1);)//将用户输入的命题公式中->和<->转换成>和< { if(str1[i]=='-') { str2[cnt++]='>';i+=2; } else if(str1[i]=='<') { str2[cnt++]='~';i+=3; } else { str2[cnt++]=str1[i];i+=1; } } str2[cnt++]='\0';//重要,给字符串加上结束标记符 Original_Formula=str1; Simp_Formula=str2; } /*************************输入并且进行简化************************************************/ /*************************增强程序鲁棒性**************************************************/ bool Enh_Robustness() { bool Rob=true; if(Original_Formula=="Over") return true; for(int i=0;i<Original_Formula.length();i++) { if(strchr(ch,Original_Formula[i])==NULL) { HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hConsole, 0xC ); cout<<"输入异常,请检查是否有空格,小写抑或非法字符"<<endl<<endl; SetConsoleTextAttribute(hConsole, 0xF ); Original_Formula=""; return false; } } return Rob; } /*************************增强程序鲁棒性**************************************************/ /********************************计算出用户输入的变量的个数*******************************/ void count_varcnt() { int Count=0; bool P=true, Q=true, R=true, S=true, T=true; for(int i=0;i<Simp_Formula.length();i++) { if(Simp_Formula[i]=='P'&&P) { Count++; P=!P; } else if(Simp_Formula[i]=='Q'&&Q) { Count++; Q=!Q; } else if(Simp_Formula[i]=='R'&&R) { Count++; R=!R; } else if(Simp_Formula[i]=='S'&&S) { Count++; S=!S; } else if(Simp_Formula[i]=='T'&&T) { Count++; T=!T; } else continue; } var_cnt=Count; } /********************************计算出用户输入的变量的个数*******************************/ /********************************优先级运算***********************************************/ bool Jude_canin(char out)//具体的大家代入数据实际体验体验 { char in=Sim_stack.Top(); int i, o; switch(in) { case '#':i=0; break; case '(':i=1; break; case '~':i=3; break; case '>':i=5; break; case '|':i=7; break; case '&':i=9; break; case '!':i=11; break; case ')':i=12; break; } switch(out) { case '#':o=0; break; case '(':o=12; break; case '~':o=2; break; case '>':o=4; break; case '|':o=6; break; case '&':o=8; break; case '!':o=10; break; case ')':o=1; break; } if(i<o) return true; else return false; } /********************************优先级运算***********************************************/ /*******************************将处理后的命题公式转化为逆波兰表达式**********************/ void Change_to_sufexp() { string Tmp=""; Sim_stack.Push('#'); for(int i=0;i<Simp_Formula.length();i++) { if(Simp_Formula[i]=='P'||Simp_Formula[i]=='Q'||Simp_Formula[i]=='R'||Simp_Formula[i]=='S') { Tmp=Tmp+Simp_Formula[i]; continue; } if(Jude_canin(Simp_Formula[i])) Sim_stack.Push(Simp_Formula[i]); else if(Simp_Formula[i]==')') { while(Sim_stack.Top()!='(') { Tmp=Tmp+Sim_stack.Top(); Sim_stack.Pop(); } Sim_stack.Pop(); } else { do { Tmp=Tmp+Sim_stack.Top(); Sim_stack.Pop(); }while(!Jude_canin(Simp_Formula[i])); Sim_stack.Push(Simp_Formula[i]); } } while(Sim_stack.Top()!='#') { Tmp=Tmp+Sim_stack.Top(); Sim_stack.Pop(); } Sim_stack.Pop(); Suffix_Formula=Tmp; } /*******************************将处理后的命题公式转化为逆波兰表达式**********************/ /*******************************进行运算**************************************************/ void Calculate() { if(var_cnt==2) { for(int i=0;i<Suffix_Formula.length();i++) { if(Suffix_Formula[i]=='P'||Suffix_Formula[i]=='Q') { v= Suffix_Formula[i]=='P'?p:q; Sim_stack.Push(v); continue; } Not_Not(Suffix_Formula[i]); Switch_Operator(Suffix_Formula[i]); } } if(var_cnt==3) { for(int i=0;i<Suffix_Formula.length();i++) { if(Suffix_Formula[i]=='P'||Suffix_Formula[i]=='Q'||Suffix_Formula[i]=='R') { v= Suffix_Formula[i]=='P'?p:Suffix_Formula[i]=='Q'?q:r; Sim_stack.Push(v); continue; } Not_Not(Suffix_Formula[i]); Switch_Operator(Suffix_Formula[i]); } } if(var_cnt==4) { for(int i=0;i<Suffix_Formula.length();i++) { if(Suffix_Formula[i]=='P'||Suffix_Formula[i]=='Q'||Suffix_Formula[i]=='R'||Suffix_Formula[i]=='S') { v= Suffix_Formula[i]=='P'?p:Suffix_Formula[i]=='Q'?q:Suffix_Formula[i]=='R'?r:s; Sim_stack.Push(v); continue; } Not_Not(Suffix_Formula[i]); Switch_Operator(Suffix_Formula[i]); } } if(var_cnt==5) { for(int i=0;i<Suffix_Formula.length();i++) { if(Suffix_Formula[i]=='P'||Suffix_Formula[i]=='Q'||Suffix_Formula[i]=='R'||Suffix_Formula[i]=='S'||Suffix_Formula[i]=='T') { v= Suffix_Formula[i]=='P'?p:Suffix_Formula[i]=='Q'?q:Suffix_Formula[i]=='R'?r:Suffix_Formula[i]=='S'?s:t; Sim_stack.Push(v); continue; } Not_Not(Suffix_Formula[i]); Switch_Operator(Suffix_Formula[i]); } } } /*******************************进行运算**************************************************/ /********************************打印*****************************************************/ void Print() { if(var_cnt==2) { cout<<"真值表如下"<<endl; cout<<"P\t"<<"Q\t"<< Original_Formula<<endl; for(p=1;p>=0;p--) { for(q=1;q>=0;q--) { Calculate(); if(res==1) PDNF=PDNF+"("+(p==1?"P":"┐P")+"∧"+(q==1?"Q":"┐Q")+")"+"∨"; else PCNF=PCNF+"("+(p==0?"P":"┐P")+"∨"+(q==0?"Q":"┐Q")+")"+"∧"; cout<<p<<"\t"<<q<<"\t"<<res<<endl; } } } if(var_cnt==3) { cout<<"真值表如下"<<endl; cout<<"P\t"<<"Q\t"<<"R\t"<< Original_Formula<<endl; for(p=1;p>=0;p--) { for(q=1;q>=0;q--) { for(r=1;r>=0;r--) { Calculate(); if(res==1) PDNF=PDNF+"("+(p==1?"P":"┐P")+"∧"+(q==1?"Q":"┐Q")+"∧"+(r==1?"R":"┐R")+")"+"∨"; else PCNF=PCNF+"("+(p==0?"P":"┐P")+"∨"+(q==0?"Q":"┐Q")+"∨"+(r==0?"R":"┐R")+")"+"∧"; cout<<p<<"\t"<<q<<"\t"<<r<<"\t"<<res<<endl; } } } } if(var_cnt==4) { cout<<"真值表如下"<<endl; cout<<"P\t"<<"Q\t"<<"R\t"<<"S\t"<<Original_Formula<<endl; for(p=1;p>=0;p--) { for(q=1;q>=0;q--) { for(r=1;r>=0;r--) { for(s=1;s>=0;s--) { Calculate(); if(res==1) PDNF=PDNF+"("+(p==1?"P":"┐P")+"∧"+(q==1?"Q":"┐Q")+"∧"+(r==1?"R":"┐R")+"∧"+(s==1?"R":"┐R")+")"+"∨"; else PCNF=PCNF+"("+(p==0?"P":"┐P")+"∨"+(q==0?"Q":"┐Q")+"∨"+(r==0?"R":"┐R")+"∨"+(s==0?"R":"┐R")+")"+"∧"; cout<<p<<"\t"<<q<<"\t"<<r<<"\t"<<s<<"\t"<<res<<endl; } } } } } if(var_cnt==5) { cout<<"真值表如下"<<endl; cout<<"P\t"<<"Q\t"<<"R\t"<<"S\t"<<"T\t"<<Original_Formula<<endl; for(p=1;p>=0;p--) { for(q=1;q>=0;q--) { for(r=1;r>=0;r--) { for(s=1;s>=0;s--) { for(t=1;t>=0;t--) { Calculate(); if(res==1) PDNF=PDNF+"("+(p==1?"P":"┐P")+"∧"+(q==1?"Q":"┐Q")+"∧"+(r==1?"R":"┐R")+"∧"+(s==1?"R":"┐R")+")"+"∨"; else PCNF=PCNF+"("+(p==0?"P":"┐P")+"∨"+(q==0?"Q":"┐Q")+"∨"+(r==0?"R":"┐R")+"∨"+(s==0?"R":"┐R")+")"+"∧"; cout<<p<<"\t"<<q<<"\t"<<r<<"\t"<<s<<"\t"<<t<<"\t"<<res<<endl; } } } } } } if(PDNF.length()==0) cout<<"主析取范式不存在"<<endl; else { PDNF.erase(PDNF.length()-2); cout<<"主析取范式为:"<<PDNF<<endl<<endl; } if(PCNF.length()==0) cout<<"主合取范式不存在"<<endl; else { PCNF.erase(PCNF.length()-2); cout<<"主合取范式为:"<<PCNF<<endl<<endl; } PDNF=""; PCNF=""; } /********************************打印*****************************************************/ void Not_Not(char c)//功能:判断运算符是否为!,为什么呢?因为如果是!,我只需取一个元素 { //否则的话我必须取两个元素才能计算 if(c!='!') { a= Sim_stack.Top(); Sim_stack.Pop(); b= Sim_stack.Top(); Sim_stack.Pop(); } } //选择要计算的运算符 void Switch_Operator(char c) { switch(c) { case '~':Iif(); break; case '>':If(); break; case '|':Or(); break; case '&':And(); break; case '!':Not();break; } } //进行!运算 void Not() { a=Sim_stack.Top(); Sim_stack.Pop(); res= a==1?0:1; //一定要注意是等于号 Sim_stack.Push(res); } //进行合取运算 void And() { res=a*b; Sim_stack.Push(res); } //进行析取运算 void Or() { res= a+b==0?0:1; Sim_stack.Push(res); } //进行条件运算 void If() { res= (b==1&&a==0)?0:1; Sim_stack.Push(res); } //进行双条件运算 void Iif() { res= a==b?1:0; Sim_stack.Push(res); }