1、离散数学实验求真值表一 实验目的 熟悉掌握命题逻辑中的联接词、真值表、主范式等,进一步能用它们来解决实际问题。二 实验内容 1. 从键盘输入两个命题变元P和Q的真值,求它们的合取、析取、条件和双条件的真值。(A) 2. 求任意一个命题公式的真值表(B,并根据真值表求主范式(C)三 实验环境C或C语言编程环境实现。四 实验原理和实现过程(算法描述)A:首先提示用户输入真值指派,然后判断用户输入的是否是0或者1,如果不是则利用while语句提示错误,然后提示重新输入直至输入正确,再根据用户输入的真值给代表合取,析取,蕴含,双条件的变量赋值,再以两行表格形式输出所得结果。最后提示按#键退出,否则继续
2、循环求真值。B:主要思路:首先提示用户输入表达式,然后编写并调用一个函数将表达式转换为逆波兰式,在转换的同时,插入部分语句将表达式中的变量名存储到数组bianlN中,然后输出存好的各变量名及用户输入的表达式(建立表头),将每次的真值指派存在数组zhi中,编写函数zzhi()每次调用zzhi()时都使数组zhi中的真值加1,(利用递推实现加一时可能的进位,)然后编写并调用一函数qiuzhi()计算每次真值指派下的逆波兰表达式的值,再输出各真值指派和求出的表达式的真值,然后调用函数zzhi()将真值指派的数组加1,最后外围利用while语句循环输出每个不同的真值指派和该指派下表达式的值。将表达式转
3、换成逆波兰式并将变量提取的算法:首先需要分配2个栈,一个作为临时存储运算符的栈fu,一个作为输入逆波兰式的栈nibol,从中缀式的左端开始取字符,逐序进行如下步骤: (1)若取出的字符是字母,则该字母直接送入nibol栈。同时为了找出所有变量,将该变量名与数组bianl中已有的元素比较,如果bianl中还没有该字母,则该字母是新出现的变量,将其录入数组bianl中。(2)若取出的字符是“(”,则直接送入fu栈栈顶。 (3)若取出的字符是“)”,则将距离fu栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入nibol栈,此时抛弃“(”。 (4)若取出的字符是运算符,则将该运算符与fu栈栈顶元素比
4、较,如果该运算符优先级大于fu栈栈顶运算符优先级,(此处是编写程序时自己判断好优先级了再按不同情况处理)则将该运算符进fu栈,否者,将fu栈的栈顶运算符弹出,送入nibol栈中,直至fu栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入fu栈。 (5) 重复上面的14步,直至处理完所有的输入字符 (6)最后将残留在符号栈fu中的运算符依次出栈。由于是用数组做的栈,所以,使用逆波兰式求值时只需直接从数组nibol的第一个元素nibol0开始依次读取就行了。计算逆波兰式的值的算法:把转换好的逆波兰式从nibol0开始依次读取,如果是字母,则先判断字母是第几个变量,将数组zhi(存放了真
5、值指派)中对应的真值zhii放入数组result(作为一个栈)中,遇到双目运算符就将result中栈顶的两个元素出栈,执行运算,得到的结果再入栈,如果是单目运算符!,则只将一个元素出栈并计算和入栈。增值:用一个数组存放每一次的真值指派,并用递推实现真值的加1进位:zzhi(int n)/数组zhi存每次的真值指派,调用zzhi(bl+1);时给n赋值为变量数加1,以防止最后一个输出完时再增值时溢出 if(zhin=0) zhin=1; else if(zhin=1) zhin=0; zzhi(n-1); /递推,实现进位 C:在B的基础上加了两个二维数组biao,biao2,将真值为1和0的真
6、值指派分别存在数组biao和biao2中,然后按合取和析取主范式的不同定义,用循环将对应真值的变量以原或反变量形式输出期间也输出合取、析取符和括号,使之成为主范式再编写好主要的功能之后,我又在源程序基础上加了一些判断输入错是的提示和处理。具体见实验数据分析和源程序的注释五 实验数据及结果分析;A:当输入的真值不为0或者1时提示错误并要求重新输入可循环输入直到输入#才退出,如图所示,以表格的形式输出结果,并且真值都正确B和C:首先提示输入表达式(合取、析取、蕴含、双条件分别用&,|,,=表示),然后如果输入的是正确的表达式则以表格形式输出该表达式的真值表、主析取范式和主合取范式,如下图所示,所得
7、真值表和主范式是正确的当输入错误的表达式格式时,提示错误,并让用户选择是否继续输入表达式(按#退出)然后返回原界面,继续求真值表和主范式。如下图所示:当输入p&Q!R(!R前漏写运算符)时,提示表达式不合规范,要求重新输入,也可选择按#退出。括号不匹配:输入错误的符号:六 源程序清单;A:#includemain() char flag; int he,xi,yunh,dengj,p,q; printf(*欢迎进入*n); printf(t(本次实验计算二元表达式的值)nn); do printf(请输入P,Q的真值指派(0或1)n); printf(p=); scanf(%d,&p); wh
8、ile(p!=0&p!=1) printf(输入有误!请重新输入!np=); fflush(stdin); scanf(%d,&p); printf(Q=); scanf(%d,&q); while(q!=0&q!=1) printf(输入有误!请重新输入!nQ=); fflush(stdin); scanf(%d,&q); he=(p=1&q=1)?1:0; xi=(p=1|q=1)?1:0; yunh=(p=0|q=1)?1:0; dengj=(p=q)?1:0; printf(tPtQtPQtPQtPQtPQn); printf(t%dt%d t%d t%d t%d t %d,p,q,h
9、e,xi,yunh,dengj); printf(nt(按#退出,其它任意键继续)n); fflush(stdin); scanf(%c,&flag); while(flag!=#);B和C:#include#include #include#include#define N 20char yuanN*N=0,fuN=0,nibolN*N=0,bianlN;int zhiN=0;/全局变量分别存储原表达式yuan,求逆波兰式时的符号fu,/存储逆波兰式nibol,存储变量bianl,存储真值指派zhi,int nitop=-1,ftop=-1,bl=-1;/存储逆波兰式和求逆波兰式时要用到的存
10、符号的数组的栈顶指针以及变量下标int error0=0;int biaoN*NN,geshu=0;/存储使真值为一的真值指派,用来求主析取范式int biao2N*NN,geshu2=0;void main0();/函数声明nibolan() /将输入的表达式转换为逆波兰式 int i,j,k,flag,fg=-1;/flag记录某变量是否已出现,fg记录上个变量是字母1,运算符号2,左括号0,右括号3 j=strlen(yuan); for(i=0;i=A&yuani=a&yuani=z) /字母作为运算数直接入栈 if(fg=1|fg=3)/字母前不能是字母或右括号 printf(输入错
11、误!表达式不规范请重新输入!);error0=1;return; fg=1; nibol+nitop=yuani; flag=1; for(k=0;k) if(fg=0|fg=2) printf(输入错误!表达式不规范请重新输入!);error0=1;return; fg=2; while(fuftop=!|fuftop=&|fuftop=|fuftop=) nibol+nitop=fuftop-; fu+ftop=yuani; else if(yuani=) if(fg=0|fg=2) printf(输入错误!表达式不规范请重新输入!);error0=1;return; fg=2;while
12、(fuftop=!|fuftop=&|fuftop=|fuftop=|fuftop=) nibol+nitop=fuftop-; fu+ftop=yuani; else printf(输入了错误的符号!请重新输入!);error0=1;return; /如果输入错误的符号,则提示错误, while(ftop=0) nibol+nitop=fuftop-;zzhi(int n)/用数组zhi存每次的真值指派,调用时给n赋值为变量数加1,即zzhi(bl+1); if(zhin=0) zhin=1; else if(zhin=1) zhin=0; zzhi(n-1); /递推 int qiuzhi
13、() int i,j,resultN,res=-1,a,b; for(i=0;i=A&niboli=a&niboli=z) for(j=0;j|niboli=) a=resultres-; b=resultres-; if(niboli=&) result+res=(a=1&b=1)?1:0; else if(niboli=|) result+res=(a=1|b=1)?1:0; else if(niboli=) result+res=(b=0|a=1)?1:0; else if(niboli=) result+res=(a=b)?1:0; else if(niboli=!) a=result
14、res-; result+res=!a; return resultres;/返回计算完毕时最终的结果void main0()/为实现循环输入将main函数提取成模块main0 int i,j,m=0,n1,result0; printf(*欢迎进入*n); printf(本次实验输出表达式的真值表)n请输入表达式:); printf(合取、析取、蕴含、双条件分别用&,|,,=表示n); memset(yuan,0,sizeof(yuan); memset(fu,0,sizeof(fu); memset(nibol,0,sizeof(nibol); memset(bianl,0,sizeof(
15、bianl); memset(zhi,0,sizeof(zhi); nitop=-1;ftop=-1;bl=-1;error0=0;geshu=0;geshu2=0; memset(biao,0,sizeof(biao); memset(biao2,0,sizeof(biao2); scanf(%s,yuan); nibolan();/ system(cls); if(error0) return; for(i=0;i=bl;i+) printf(t%c,bianli); printf(t%sn,yuan); n1=pow(2,bl+1); do result0=qiuzhi(); if(re
16、sult0=0) for(i=1;i=bl+1;i+) printf(t%d,zhii); biao2geshu2i=zhii; geshu2+; else for(i=1;i=bl+1;i+) printf(t%d,zhii); biaogeshui=zhii; geshu+; printf(t %dn,result0); zzhi(bl+1); while(+m(int)n1); printf(主析取范式为:n); for(i=0;igeshu;i+) for(j=1;j=bl;j+) if(biaoij=1) printf(%c,bianlj-1); else printf(%c,bia
17、nlj-1); if(biaoij=1) printf(%c,bianlj-1); else printf(%c,bianlj-1); if(igeshu-1) printf( ); else printf(n); printf(主合取范式为:n); for(i=0;igeshu2;i+) printf((); for(j=1;j=bl;j+) if(biao2ij=0) printf(%c,bianlj-1); else printf(%c,bianlj-1); if(biao2ij=0) printf(%c,bianlj-1); else printf(%c,bianlj-1); if(i
18、geshu2-1) printf() ); else printf()n); main() char ch; while(1) main0(); printf(任意键继续,按#退出); fflush(stdin); scanf(%c,&ch); system(CLS); if(ch=#) break; 七 其他收获和体会。本次试验收获颇丰,不仅加深了对离散数学的知识的理解,而且积累了很多编写程序的经验,锻炼了动手能力和调试程序的能力。写实验A的时候,为了实现提示错误和循环输入用了while语句,但是,最初运行的时候却出现了死循环,后来找了很久,才知道是要清空缓存,调用了函数fflush(std
19、in)。实验B,刚开始看到题目不知道怎么下手,想起上课时老师说到过逆波兰式,然后去找了一些资料学习了逆波兰式的原理,再花了很多时间将所学的理论写成程序,期间遇到了很多问题,比如:如何给变量赋真值,怎样让真值以二进制的形式加一,怎样判断优先级后来都想出了解决的办法:将真值存在数组中,求值时先用for循环找出该变量的次序再直接替换了成对应的真值,用递推的办法实现二进制进位的问题,编程的时候手动判断优先级(可能是比较笨的办法)然后采取相应的措施实验C:B编出来之后,C就在B的基础上加了一些数组,将真值为1和0的真值指派分别存在不同的数组中,然后用循环输出主范式。总而言之,这次实验尽管花费了很多时间,但是收获真的很大,尤其是经验的积累,对c语言又进一步地熟练了。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1