离散数学实验1报告.docx
《离散数学实验1报告.docx》由会员分享,可在线阅读,更多相关《离散数学实验1报告.docx(32页珍藏版)》请在冰豆网上搜索。
离散数学实验1报告
“离散数学”实验报告
(实验ABC)
专业:
自动化
班级:
¥¥
学号:
¥¥¥
姓名:
日期:
2011年12月05日
第一章实验概述
1.1实验目的
熟悉掌握命题逻辑中的联接词、真值表、主范式等,进一步能用它们来解决实际问题,具体说来,有以下几点——
1.掌握离散数学中涉及的相关概念。
2.培养学生的逻辑思维能力和算法设计的思想。
3.熟练掌握C/C++语言程序设计的基本方法和各种调试手段。
4.熟练掌握包括数组、链表以及邻接表或邻接矩阵等数据结构的建立和运用。
1.2实验内容
1.从键盘输入两个命题变元P和Q的真值,求它们的合取、析取、条件和双条件的真值。
(A)
2.求任意一个命题公式的真值表(B),并根据真值表求主范式(C)
注意:
题目类型分为A,B,C三类,其中A为基本题,完成A类题目可达到设计的基本要求,其他均为加分题,并按字母顺序分数增加越高。
1.3实验环境
C或C++语言编程环境实现。
第二章实验原理和实现过程
2.1实验原理
2.1.1逻辑连接词的运算
真值表是数理逻辑中的一个重要概念,实践证明运用真值表可以解答数理逻辑的绝大部分问题,也无须高深的知识和技巧,具有直观明了的特点,尽管某些列表比较麻烦,但仍不失为是一种行之有效的好办法。
为了实现二元合取、析取、条件和双条件表达式的计算,可以充分利用联接词和逻辑运算符之间的相似性实现程序功能。
2.1.2真值表与主范式
命题公式的主析(合)取范式具有重要的意义,根据公式的主析(合)取范式,不仅可以判断两个公式是否等价,而且还可以判断一个公式是否为永真式(重言式)或永假式(矛盾式)。
一般我们将公式中的命题变元放在真值表的左边,将公式的结果放在真值表的右边。
命题变元可用数值变量表示,合适公式的表示及求真值表转化为逻辑运算结果;可用一维数表示合式公式中所出现的n个命题变元,同时它也是一个二进制加法器的模拟器,每当在这个模拟器中产生一个二进制数时,就相当于给各个命题变元产生了一组真值指派。
2.2实验过程(算法描述)
2.2.1程序整体思路
本程序完成了实验所要求的全部功能,其基本思路是——“运用模块化的思想,将实现实验A内容和实验BC内容的程序分开编写,然后将它们以头文件A.h和BC.h的形式添加到主程序ABC.c中,在要使用不同的函数时,进行调用就可以完成相应的功能了。
”
本程序的一大特色就是开发者同时使用了C语言和C++语言来进行开发,用C语言来开发主程序ABC.c和实验A.h头文件,用C++语言来开发实验BC.h头文件,通过编译实现了全部的功能。
2.2.2实现实验A算法
在实验A中,为了实现二元合取、析取、条件和双条件表达式的计算,我充分利用联接词和逻辑运算符之间的相似性实现程序功能。
详细说来,编写了一个用于判断的函数,先将从键盘获取的“T”或“F”的字符转化为对应的1或0,然后运用C语言中的位运算符号进行相应运算,并且在显示屏上输出相应的真值。
值得注意的一点是,在本子程序中,开发者使用了“标志号”的概念来进行程序控制。
具体说来就是,在进行程序检查时和退出实验A功能界面时使用了标志号进行程序的跳转,同时还有在进行输入判断时对输入函数进行控制。
例如,在每次调用判断函数进行判断前,对标志号进行检测。
判断函数是一个根据标志号来判断是否循环的循环函数。
一般情况下进行判断时,标志号为0,当每次判断完成后,就会根据用户相应的选择来对标志号进行置数;当用户想要退出实验A所实现的功能界面时,程序会根据用户的键盘输入值将标志号置为1,那么判断函数再次循环之前,在对标志号进行检测时,程序会自动退出子函数调用,返回主界面。
2.2.3实现实验BC算法
实验BC的实现算法,开发者采用了指导老师所推荐的算法逻辑,其具体说明如下:
(1)将二进制加法模拟器赋初值0。
(2)计算模拟器中所对应的一组真值指派下合式公式的真值。
(3)输出真值表中对应于模拟器所给出的一组真值指派及这组真值指派所对应的一行真值。
(4)产生下一个二进制数值,若该数值等于2n-1,则结束,否则转
(2)。
注意,在进行表达式求值的时候,可先将带括号的中缀表达式利用栈结构转换为不带括号的后缀表达式(逆波兰式),然后进行计算。
实验BC的程序编写思路大体上完全符合这样的设计思路,通过对数据结构中“堆栈”的概念来进行设计。
具体说来,程序中定义了两个重要的数组,一个用于表达式的计算,另外一个用于指派真值。
首先编写了一个将输入的字符串转化为可计算的表达式的函数,之后定义联结词的栈内和栈外的优先级,用于表达式的转化。
然后,编写了一个计算函数,用于模仿实数加法器进行表达式计算,并且用数组构建了一个二进制加法器,用于指派真值。
为了提高程序的容错能力,还编写了一个检查输入格式的函数。
最后,就是问题的解决函数了,首先将用户输入的表达式进行输入格式的检查,确认无误后,将字符串转化为可计算的表达式,保存在特定的堆栈中,之后,模仿实数加法器产生一个真值,同时对表达式进行计算,输出到真值表的显示界面上,并且根据真值来入栈,成真指派入析合栈,成假指派入合析栈,最后根据析合栈和合析栈的内容来进行析合范式与合析范式的输出。
第三章实验数据及结果分析
3.1主程序ABC.c的功能测试及结果分析
主程序是根据用户不同的选择来调用不同的函数,从而满足用户的使用需求,当然主程序界面友好,有清楚地操作说明,方便用户进行使用。
同时,它也有基本的容错能力,能够对没有按照要求的输入进行控制,在屏幕上显示提示语,要求用户重新输入。
这就是主程序控制的主界面。
3.1.1输入数字“1”
当输入数字“1”时,程序会显示实现实验A的功能界面。
3.1.2输入数字“2”
当输入数字“2”时,程序会显示实现实验BC的功能界面。
3.1.3输入数字“3”
当输入数字“3”时,程序会显示退出界面。
3.1.4输入其他字符时
当输入其他字符时时,程序会在屏幕上显示相应的提示语,要求用户重新输入。
3.2实验A的功能测试和结果分析
3.2.1测试数据为“p=T和q=F”
当测试数据为“p=T和q=F”时,程序会显示他们的合取、析取、条件和双条件的真值。
3.2.2测试数据为“p=F和q=F”
当测试数据为“p=F和q=F”时,程序会显示他们的合取、析取、条件和双条件的真值。
3.2.3测试数据为“p=A和q=F”
当测试数据为“p=A和q=F”时,程序检测出p是非法的输入格式,会在屏幕上显示相应的提示语,要求用户重新输入。
3.2.4测试数据为“p=T和q=A”
当测试数据为“p=T和q=A”时,程序检测出q是非法的输入格式,会在屏幕上显示相应的提示语,要求用户重新输入。
3.2.5测试数据为“p=F和q=F”,之后返回主界面
3.3实验BC的功能测试和结果分析
3.3.1测试数据为“a&b|c#”
当测试数据为“a&b|c#”时,程序会求出这个命题公式的真值表,并根据真值表求出主范式。
3.3.2测试数据为“(a>b)|(c&d)#”
当测试数据为“(a>b)|(c&d)#”时,程序会求出这个命题公式的真值表,并根据真值表求出主范式。
3.3.3测试数据为“(a>b)|(c&d)”
当测试数据为“(a>b)|(c&d)”时,程序检测出表达式的后面没有“#”,判断此次是非法的输入格式,会在屏幕上显示相应的提示语,要求用户重新输入。
3.3.4测试数据为“a&b|c”
当测试数据为“a&b|c”时,程序检测出表达式的后面没有“#”,判断此次是非法的输入格式,会在屏幕上显示相应的提示语,要求用户重新输入。
第四章实验收获和心得体会
4.1实验收获
通过这次实验,我学习了很多东西,也成长了许多,它使我意识到了很多原来没有意识到的东西。
首先,我重新认识到C和C++语言的重要性,深刻的认识到了这些语言通过有序的组织可以实现意想不到的效果。
其次,我知道了离散数学的那些抽象深奥的公式竟然也可以通过编程在计算机上实现,这种尝试让在课堂上学习的那些知识变得生动可爱,它们不再是黑板上、书本里面那一个个无聊死板的字眼,而是充满想象力、拥有无穷魅力的精灵。
再次,它提高了我的计算机编程能力,使我感觉到了编程的乐趣,提供给我无穷的继续学习编程语言的动力。
最后,这次实验令我感觉到了理论和实际的结合原来可以如此紧密的,他们之间的联系可以产生神奇的效果和无穷的力量。
4.2心得体会
这次真的使我意识到了很多原来没有意识到的问题,有时候一些很小的问题,也会令人很是头痛。
在刚开始编写程序的时候,为了实现最基本的输入和输出功能,我却花了大量的时间在那上面。
原因在后来查阅的很多资料后才知道的,像scanf函数之类的小函数,其实是还有很多需要注意的地方的。
之后,在编写头文件程序的时候,遇到很多诸如跳转控制、数组操作、堆栈运用等等具体的问题。
经过不断的尝试摸索,通过查阅大量资料,后来才慢慢的攻克一个个的难点。
在C语言和C++语言的运用时,经常会有混淆的地方,通过一次次的提醒和注意,到后来终于可以慢慢的将它们区分开了。
最重要的体会就是,通过自己不断的努力,很好的完成一个任务,这种能够成就感,才是作为一个大学生最大的快乐。
第五章实验源程序清单
5.1主程序ABC.c的代码
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"A.h"
#include"BC.h"
charflag1,flag3,flag4;
voidini()
{
printf("*******************************************************************************\n");
printf("\n");
printf("请选择您要进行的操作项目:
\n");
printf("1、输入两个命题变元的真值,求它们的合取、析取、条件和双条件的真值\n");
printf("2、求任意一个命题公式的真值表,并根据真值表求主范式\n");
printf("3、退出系统\n");
printf("\n");
printf("********************************************************************************\n");
}
voidend()
{
printf("\n");
printf("********************************************************************************\n");
printf("\n");
printf("谢谢使用本系统,欢迎下次使用!
\n");
printf("\n");
printf("********************************************************************************\n");
printf("\n");
}
voidmain()
{
while(!
flag3)
{
while(!
flag1)
{
if(flag4==0)
system("cls");
ini();
scanf("%d",&i);
fflush(stdin);
if(i==1||i==2||i==3)
{
system("cls");
flag3=1;
flag4=0;
if(i==1)
PQ();
elseif(i==2)
{
symbola;
a.solve();
}
else
flag1=1;
}
else
{
printf("输入格式有误,请重新输入!
\n");
flag4=1;
}
}
}
end();
}
5.2头文件A.h的代码
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
chari,p,q,t,mea,flag,flag2;
intp1,q1;
voidana()
{
while(!
flag2)
{
printf("请输入p的真值(T或F)\n");
scanf("%c",&p);
fflush(stdin);
if(p=='T'||p=='F')
{
printf("请输入q的真值(T或F)\n");
scanf("%c",&q);
fflush(stdin);
if(q=='T'||q=='F')
{
if(p=='F')
p1=0;
else
p1=1;
if(q=='F')
q1=0;
else
q1=1;
if(p1|q1)
t='T';
else
t='F';
printf("p析取q为%c\n",t);
if(p1&q1)
t='T';
else
t='F';
printf("p合取q为%c\n",t);
if((!
p1)|q1)
t='T';
else
t='F';
printf("p条件q为%c\n",t);
if(p1==q1)
t='T';
else
t='F';
printf("p双条件q为%c\n",t);
flag2=1;
}
else
printf("输入格式有误,请重新输入!
\n");}
else
printf("输入格式有误,请重新输入!
\n");}
}
voidPQ()
{
while(!
flag)
{
ana();
flag2=0;
printf("******************************是否要继续输入?
(Y或N)****************************\n");
scanf("%c",&mea);
fflush(stdin);
if(mea=='N')
flag=1;
}
flag=0;
}
5.3头文件BC.h的代码
#include"stdafx.h"
#include"iostream"
#include"cstring"
#include"stack"
#include"cmath"
#definemaxsize100
usingnamespacestd;
charstr[100];//输入的表达式
intzhipai[20]={0};//用于指派真值的数组
intlength;//逻辑表达式长度
charexpression[100];//用于计算的数组
classsymbol{
public:
voidsolve();
voidClear(){}
private:
voidchange();
intCalculate();
voidcheck();
boolGet2Operands(double&left,double&right);
voidDoOperator(charop);
stacks;//运算栈
};
boolsymbol:
:
Get2Operands(double&left,double&right){//取两运算值
if(s.size()==0){
cerr<<"MissOperand!
"<returnfalse;
}
right=s.top();
s.pop();
if(s.size()==0){
cerr<<"MissOperand!
"<returnfalse;
}
left=s.top();
s.pop();
returntrue;
}
voidsymbol:
:
DoOperator(charop){//单次运算
doubleleft,right;
boolresult=Get2Operands(left,right);
if(result)
switch(op){
case'|':
s.push(left||right);break;//或运算
case'&':
s.push(left&&right);break;//与运算
case'>':
s.push(!
left||right);break;//蕴涵运算
case'!
':
s.push((!
right)&&left);break;//非运算
case'=':
s.push(left==right);break;//等价运算
}
else
Clear();
}
voidsymbol:
:
change()//将输入的字符串转化为可计算的表达式
{
intk=0;
intflag=1;
intcount=0;//命题变元个数
for(inti=0;i{
k=1;
for(intm=0;m{
if(isalpha(str[m]))//将原来的命题变元修改为真值
{
if(flag==1)
{
if(zhipai[k]==0)
expression[m]='0';
else
expression[m]='1';
k++;
}
else
expression[m]='0';
flag=1;
for(intt=m;t>=0;t--)
{
if((str[m+1]==str[t])&&isalpha(str[m+1])&&isalpha(str[t]))
flag=0;
}
}
else
expression[m]=str[m];//逻辑联结词不变
}
for(intt=0;t{
for(intj=t;j{
if(str[t]==str[j])
{
expression[j]=expression[t];//相同的命题变元复制赋值
}
}
}
}
}
voidplus(inta[],intq)//二进制加法器,用于指派真值
{
a[q]=a[q]+1;
for(inti=q;a[i]==2;i--)
{
a[i]=0;
a[i-1]=a[i-1]+1;
}
}
intisp(charch)//联结词的栈内优先级
{
switch(ch){
case'#':
return0;break;
case'(':
return1;break;
case'!
':
return10;break;
case'=':
return9;break;
case'&':
return7;break;
case'|':
return5;break;
case'>':
return3;break;
case')':
return12;break;
default:
return-1;break;
}
}
inticp(charch)//联结词的栈外优先级
{
switch(ch){
case'#':
return0;break;
case'(':
return12;break;
case'!
':
return11;break;
case'=':
return8;break;
case'&':
return6;break;
case'|':
return4;break;
case'>':
return2;break;
case')':
return1;break;
default:
return-1;break;
}
}
intsymbol:
:
Calculate()//模仿实数加法器进行表达式计算
{
stackh;
charch,y;
h.push('#');
for(inttemp=0;tempch=expression[temp];
if(isdigit(ch))//命题变元真值入栈
{
if(ch=='0')
s.push(0);
else
s.push
(1);
}
elseif(ch==')')//运算括号内的
{
for(y=h.top(),h.pop();y!
='(';y=h.top(),h.pop()){
DoOperator(y);}
}
else{
if(ch=='!
')//非运算,在!
前加1,将!
视作双目操作符
{
s.push
(1);
}
for(y=h.top(),h.pop();isp(y)>icp(ch);y=h.top(),h.pop())
DoOperator(y);
h.push(y);
h.push(ch);
}
}
while(h.size()!
=1){
y=h.top();
h.pop();
DoOperator(y);
}
cout<returns.top();
}
voidsymbol:
:
check();//检查函数的预先声明
voidsymbol:
:
solve()//问题的解决
{
cout<<"********************************************************************************"<cout<<"请输入命题逻辑表达式:
"<cout<<"(注意:
命题变元在a~z中选取,变元个数不要超过20个,或运算用|,与运算用&,非运算用!
,蕴涵运算用>,等价运算用=,以#结尾)"<cout<<""<cout<<"************************