重言式判别.docx
- 文档编号:24542162
- 上传时间:2023-05-28
- 格式:DOCX
- 页数:14
- 大小:130.19KB
重言式判别.docx
《重言式判别.docx》由会员分享,可在线阅读,更多相关《重言式判别.docx(14页珍藏版)》请在冰豆网上搜索。
重言式判别
重言式判别
一、问题描述
一个逻辑表达式如果对于其变元的任一种取值都为真,则称为重言式;反之,如果对于其变元的任一种取值都为假,则称为矛盾式;然而,更多的情况下,既非重言式,也非矛盾式。
试写一程序,通过真值表判断一个逻辑表达式属于那一类。
二、需求分析
(1)逻辑表达式从终端输入,长度不超过一行。
逻辑运算符包括“|”,“&”和“~”,
分别表示或、与和非,运算优先程度递增,但可以有括号改变,即括号内的运算优先。
逻辑变元为大写字母。
表达式中任何地方都可以含有多个空格符。
(2)若是重言式或矛盾式,可以只“显示Trueforever”或“Falseforever”,否则显示“Satisfactible”以及变量名序列,与用户交互。
若用户对表达式中变元取一组值,程序就求出并显示逻辑表达式的值。
(3)测试数据:
①(A|~A)&(B|~B)
②(A&|~A)&C
③A|B|C|D|E|~A
④A&B&C&~B
⑤(A|B)&(A|~A)
⑥A&~B|~A&B
三、概要设计
voidcreatzuhe(intn)
初始条件:
n是循环体,以便产生各种情况。
操作结果:
产生变量的各种取值组合。
voidcreate(bitree&root,bitreel,bitreer)
初始条件:
root是根结点,l是左子树,r是右子树。
操作结果:
按照运算符优先级关系建立二叉树。
charyouxianji(charlie,charhang)
初始条件:
lie是第一个运算符,hang是第二个运算符。
操作结果:
得出优先级比较关系。
voidcreatstack(sqstack&st)
初始条件:
若栈st存在。
操作结果:
把栈置空。
voidpush(sqstack&st,bitreee)
初始条件:
若栈st存在,对树结点e操作。
操作结果:
把操作符入栈。
voidpop(sqstack&st,bitree&e)
初始条件:
若栈st存在,对树结点e操作。
操作结果:
把操作符出栈。
voidGettop(sqstack&st,bitree&e)
初始条件:
若栈st存在,对树结点e操作。
操作结果:
取栈顶元素。
voidcreattree(chars[],bitree&tree)
初始条件:
是s[]存放运算符,tree是按照运算符优先级建立的二叉树。
操作结果:
判断重言式。
intvalue_tree(bitreetree)
初始条件:
tree是按照运算符优先级建立的二叉树。
操作结果:
对逻辑表达式求值。
算法思想:
自底向上地根据运算符地优先级来建立分子树函数;当逻辑表达式读完后-子根root就是一棵完整的二叉树。
用穷举法得出所有可能组合,对二叉树进行先序遍历,对存放在上面的表达式进行求值。
并用两个栈分别存放运算符和变量,来判别是否为重言式。
四、程序实现关键代码
typedefstructbtdnode{
chardata;
structbtdnode*lchild;
structbtdnode*rchild;
}*bitree;
//识别表达式使用的堆栈定义,它存放的都是树的结构;
typedefstructStack{
structbtdnode**base;//栈中的元素都是树的结点结构;
structbtdnode**top;
intstacksize;
}sqstack;
//用于产生变量的各种取值组合;
voidcreatzuhe(intn)
{
inti,num=0,j=0,e;
inttemp[max];
for(i=0;i zuhe[i]=0; while(n) { e=n%2; num++; temp[j++]=e; n=n/2; } j=j-1; num=N-num; while(j>=0) { e=temp[j--]; zuhe[num++]=e; } } //自底向上地根据运算符地优先级来建立分子树函数;当逻辑表达式读完后-子根root就是一棵完整的二叉树 intk=0;//建树的标志,k=1表示第一次建立分子树,要对左右孩子的指针域处理 voidcreate(bitree&root,bitreel,bitreer) { root->lchild=l; root->rchild=r;//分树的链接 if(l&&r) { if(int(l->data)>=65&&int(l->data)<=90) { l->lchild=NULL; l->rchild=NULL; } if(int(r->data)>=65&&int(r->data)<=90) { r->lchild=NULL; r->rchild=NULL; } } } //逻辑运算符的优先级判别; charyouxianji(charlie,charhang) { inti,j; charbijiao[7][7]={'','|','&','~','(',')','#', '|','>','<','<','<','>','>', '&','>','>','<','<','>','>', '~','>','>','>','<','>','>', '(','<','<','<','<','=','', ')','>','>','>','','>','>', '#','<','<','<','<','','='}; for(j=0;j<7;j++) if(bijiao[0][j]==lie) break; for(i=0;i<7;i++) if(bijiao[i][0]==hang) break; returnbijiao[i][j]; } //对操作符栈和变量堆栈的操作; voidcreatstack(sqstack&st)//置空栈 { st.base=(bitree*)malloc(stack_size_normal*sizeof(btdnode)); st.top=st.base; st.stacksize=stack_size_normal; } voidpush(sqstack&st,bitreee)//入栈 { if(st.top-st.base *st.top++=e; } voidpop(sqstack&st,bitree&e)//出栈 { e=*--st.top; } voidGettop(sqstack&st,bitree&e)//栈顶元素 { e=*(st.top-1); } ///////////////////////////////////////////////////////////////////////////////// //重言式的识别函数; voidcreattree(chars[],bitree&tree) { sqstackBiangliang_Stack;//变量栈; sqstackYunsuan_Stack;//逻辑运算符栈; creatstack(Biangliang_Stack);//变量栈的初始化; creatstack(Yunsuan_Stack);//逻辑运算符栈初始化; bitreelogic_di,variables,logics,e,a,b,theta,kuohao;//定义栈中的元素,theta为最后的二叉树的根 logic_di=(bitree)malloc(sizeof(btdnode));//定义新空间 logic_di->data='#';//令运算符栈顶元素为'#' push(Yunsuan_Stack,logic_di);//运算符入栈 while(*s! =NULL)//输入数据不为空 { if(int(*s)>=65&&int(*s)<=90)//且在大写字母A~Z之间(限定为A~Z) { variables=(bitree)malloc(sizeof(btdnode)); variables->data=*s; push(Biangliang_Stack,variables); } elseif(int(*s)>90||int(*s)<65) { Gettop(Yunsuan_Stack,e);//取运算符栈的栈顶元素进行优先级比较 switch(youxianji(*s,e->data))//优先级比较 { case'<': //栈顶的运算符优先级低,逻辑运算符进栈 logics=(bitree)malloc(sizeof(btdnode)); logics->data=*s; push(Yunsuan_Stack,logics);//如果ASC码小于,则入栈 break; case'=': pop(Yunsuan_Stack,kuohao);//脱括号并接受下一个字符; break; case'>': //如果ASC码大于,则运算符和变量出栈 pop(Yunsuan_Stack,theta);//弹出逻辑运算符 pop(Biangliang_Stack,a);//弹出变量 b=NULL; if(theta->data! ='~')//如果根结点的值大于"~" pop(Biangliang_Stack,b);//弹出变量 //建树的函数调用 k=k+1; create(theta,b,a);//建立二叉树 push(Biangliang_Stack,theta);//将临时的根作为新的变量压入变量栈中; if(*s! ='#'&&*s! =')')//(作用是当输入一个元素是运算符时,将其入栈,否则该运算符无法运算) { logics=(bitree)malloc(sizeof(btdnode)); logics->data=*s; push(Yunsuan_Stack,logics);//入运算符栈 } elses=s-1;//(防止在开头连续输入相同两个运算符,如果连续输入两个运算符,只能对第一个运算符进行运算) break; } } s++; } tree=theta; } //根据变量的取值组合并利用逻辑表达式的性质对树进行求值 intvalue_tree(bitreetree) { if(! tree)return0;//遇到空的结点; elseif(tree->data! ='|'&&tree->data! ='&'&&tree->data! ='~')//找到的是变量; returnzuhe[int(tree->data)-65]; elseif(int(tree->data)<65||int(tree->data)>90)//找到的是运算符; switch(tree->data) { case'|': return(value_tree(tree->lchild)||value_tree(tree->rchild));//如果是或,则将左子树和右子树进行或运算 case'&': return(value_tree(tree->lchild)&&value_tree(tree->rchild));//如果是与,则将左子树和右子树进行与运算 case'~': return(! value_tree(tree->rchild));////如果是非,则将左子树和右子树进行非运算 } } 五、调试分析 刚开始将程序编译到无错误时发现无法出现结果。 DEBUG调试发现变量根本没有附值,所以设计一个zuhe函数,将每个变量给值0或1,得出了结果。 由于将栈清空,所以每次读到第一个运算符时总要将其入栈,很麻烦,所以决定在栈放入“#”号,这样就只要判别优先级就可以决定进出栈。 发现连续输入两个运算符就会出现无法运行的情况,找到程序位置禁止连续输入相同的符号,使程序可读性更好。 六、测试结果和分析 测试数据①(A|~A)&(B|~B) 当A、B取值为0,0;0,1;1,0;1,1;时表达式的值分别为1,1,1,1,为重言式。 测试数据②(A&|~A)&C 当A、C取值为0,0;0,1;1,0;1,1;时表达式的值分别为0,0,0,0,为矛盾式。 测试数据③A|B|C|D|E|~A 测试结果为重言式。 测试数据④A&B&C&~B 测试结果为矛盾式。 ⑤(A|B)&(A|~A) 测试结果为非重言式和矛盾式。 测试数据⑥A&~B|~A&B 测试结果为非重言式和矛盾式。 从以上六个测试用例来看,结果正确。 但是程序还有一些有待解决的问题。 比如,表达式中没有解决空格的问题,当有空格存在,就无法继续下去。 另一个问题是表中显示的大写字母和表达式中的大写字母不对应,只是机械的按照次序。 但总的来说程序已经比较完善,书上的要求也基本符合,并且加入了对矛盾式的判别。 七、感想与建议 重言式是离散数学中一个很重要的概念,原本我以为这个程序会相对比较简单。 但在编的过程中明显发现了困难。 它运用到了二叉树存储结构,还利用了栈的概念对变量和运算符分别保存。 充分运用了我们学过的知识,对我们之前实验所做的很多东西进行了总结。 这个实验不仅仅是一次课程设计,更是对我们整个数据结构的第二章和第六章的复习,具有很重要的锻炼价值。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 重言式 判别