离散数学大作业代码及感想

题目要求
对给出的任意一个合式公式(不超过四个命题变元),用程序编程表示出来,能够计算它在各组真值指派下所应有的真值,画出其真值表,并输出构成主析取范式的所有小项。涉及的运算符包括∧(&),∨(|),¬(!),→(−>),↔(<−>)五种运算符,对于无法由键盘输入的运算符,可以使用括号内的符号代替。例如输入:
(?⟶?)∨?
难度:较难
说明:
a) 能支持1-4个变元
b) 能支持1-4次逻辑运算
c) 人机交互友好,排版美观
IDE:Microsoft Visual C++ 6.0
代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#define MAXSIZE 40
typedef char elemtype;
char str[40],st[40],st1[40],st2[40];
int table1[16][5];
int flag=1;
/*str接收输入的字符,st是转化后的字符,
st1储存变量,st2变量转化为相应公式;
table1储存真值表*/
/*
数据结构自己学的,然后写后缀表达式时一直提示一些符号没有
然后我猜想是头文件没有,但是网上找了好多,都不对
于是我就对着买的书,把这些定义全部打上了。

  */
typedef struct				//	定义栈结构
{	elemtype date[MAXSIZE];
	int top;
}SqStack;
void InitStack(SqStack *&s)			//初始化栈
{
	s=(SqStack * ) malloc(sizeof(SqStack));
	s->top=-1;
}
void DestoryStack(SqStack *&s)			//销毁栈
{
	free(s);
}
bool StackEmpty(SqStack *s)			//判断栈是否为空
{
	return(s->top==-1);
}
bool Push(SqStack *&s, elemtype e)			//入栈
{
	if(s->top==MAXSIZE-1)
		return false;
	s->top++;
	s->date[s->top]=e;
	return true;
}
bool Pop(SqStack *&s,elemtype &e)		//出栈
{
	if(s->top==-1)
		return false;
	e=s->date[s->top];
	s->top--;
	return true;
}
bool GetTop(SqStack *s,elemtype &e)			//取栈顶元素
{
	if(s->top==-1)
		return false;
	e=s->date[s->top];
	return true;
}
int calFun(char st2[])		//	计算后缀表达式
{
	SqStack *S;			//定义栈
	int i=0;
	char x,x1,x2;
	InitStack(S);			//初始化栈
	while (st2[i]!='\0')
	{
		switch(st2[i])
		{
			case'&':				//计算析取
				Pop(S, x2);
				Pop(S, x1);
				x=(x1-'0')&&(x2-'0');
				Push(S,(x+'0'));
				i++; break;
			case'|':			//计算合取
				Pop(S, x2);
				Pop(S, x1);
				x=(x1-'0')||(x2-'0');
				Push(S,(x+'0'));
				i++; break;
			case'-':			//计算条件
				Pop(S, x2);
				Pop(S, x1);
				x=!(x1-'0')||(x2-'0');
				Push(S,(x+'0'));
				i++; break;
			case'=':		//计算双条件
				Pop(S, x2);
				Pop(S, x1);
				x=(x1-'0')==(x2-'0');
				Push(S,(x+'0'));
				i++; break;
			case'~':			//计算否定
				Pop(S,x1);
				x=!(x1-'0');
				Push(S,(x+'0'));
				i++; break;
			default:			
				while(st2[i]=='1'||st2[i]=='0')
				{
					Push(S,st2[i]);
					i++;
				}
		}
	}
	GetTop(S,x);			//取栈顶元素,即合式公式真值
	DestoryStack(S);		//销毁栈
	return (int)(x-'0');		//返回真值
}


void suffix(char *z,char st2[])		//	将中缀表达式转化为后缀表达式
{									
	char e;
	SqStack *Optr;			//定义栈
	InitStack(Optr);		//初始化栈
	int i=0;
	while(*z!='\0')			
	{
		switch(*z)
		{
		case'(':					//左括号
			Push(Optr,'(');
			z++;
			break;
		case')':					//右括号
			Pop(Optr,e);
			while(e!='(')
			{
				st2[i++]=e;
				Pop(Optr,e);
			}
			z++;
			break;
		case'-':						//条件和双条件
		case'=':
			while(!StackEmpty(Optr))
			{
				GetTop(Optr,e);
				if(e!='(')
				{
					st2[i++]=e;
					Pop(Optr,e);
				}
				else
					break;
			}
			Push(Optr,*z);
			z++;
			break;
		case'&':
		case'|':					//合取和析取
			while(!StackEmpty(Optr))
			{
				GetTop(Optr,e);
				if(e!='('&&e!='-'&&e!='=')
				{
					st2[i++]=e;
					Pop(Optr,e);
				}
				else
					break;
			}
			Push(Optr,*z);
			z++;
			break;
		case'!':				//否定
			while(!StackEmpty(Optr))
			{
				GetTop(Optr,e);
				if(e!='!')
					{
						st2[i++]=e;
						Pop(Optr,e);
					}
					else
						break;
			}
			Push(Optr,*z);
			z++;
			break;
		default:				//对应真值
			while(*z=='0'||*z=='1')
			{
				st2[i++]=*z;
				z++;
			}
			//st2[i++]='#';			//我不知道这行有什么用,书上有,我加上后运行不了
		}
	}
	while(!StackEmpty(Optr))		
	{
		Pop(Optr,e);
		st2[i++]=e;				//出栈
	}
	st2[i]='\0';			//给st2加上结束符
	DestoryStack(Optr);			//销毁栈
}

void disjunctiveFun(int table1[][5],int h,int num)
{
	int i,j;
	printf("主析取范式小项为:\n");			//如果合式公式真值为1就打印
	for(i=0;i<h;i++)
	{	if(table1[i][num]==1)
		{
			for(j=0;j<num;j++)
				
			{	//printf("%d",table1[i][j]);
				if(table1[i][j]==0)				//对应字母为0,加!
					printf("%c",'!');
					printf("%c",st1[j]);
				if(j!=num-1)					//加个&
					printf("%c",'&');
				

					
			}
			printf("\n");
		}	
	}
}
void trueTable(char st[],int num)		//打印真值表
{
	int h,i,j,k;
	int a;
	int table[40];
	char z[40];
	h=(int)pow(2,num);		//计算真值表的行数
	for(i=0;i<num;i++)
		{
			printf("%c\t", st1[i]);
		}
		printf("%s\n",str);
		strcpy(z,st);
		
	for(i=0;i<h;i++)
	{	strcpy(z,st);
		for(j=0;j<num;j++)
			
		{
			table[j]=(i/(int)pow(2,j)%2);		//真值表赋值
			printf("%d\t", table[j]);
			table1[i][j]=table[j];			//储存真值
			
		}
		for(k=0;z[k]!='\0';k++)		//将字母转化为对应真值
		{
			for(j=0;st1[j]!='\0';j++)
			{
				if(z[k]==st1[j])
				{
					z[k]=table[j]+'0';			//弄了好长时间,char不能储存int
				}
			}
		}
		suffix(z,st2);			//转化为后缀表达式
	//	printf("%s",st2);
		a=calFun(st2);			//计算后缀表达式
		printf("%d\n",a);
	//	printf("%s\n",z);
		table1[i][num]=a;		//合适公式真值储存
	}
	disjunctiveFun(table1,h,num);		//调用打印主析取范式函数
}
int judgeNum(char st[])		//判断变量个数是否正确并且提取字母
{
	int i,j,k=0,num=0 ;
	for(i=0;st[i]!='\0';i++)
	{
		if(st[i]>='A'&&st[i]<='Z')
		{	
			for(j=0;j<i;j++)
			{
				if(st[j]==st[i])break ;
			}
			if(i==j)
			{
				st1[k++]=st[i];		//将字母存放到数组st1中
				num++ ; 
			}	
		}
		
	}
	if(num>=1&&num<=4);
	else{	flag=0;}
	return num;
}
void judgeSymbol(char st[])		//判断符号是否输入正确
{
	int i,j,num;
	char s0[40];
	strcpy(s0,st);
	for(i=0;s0[i]!='\0';i++)			//先把括号移除
	{
		if(s0[i]=='(') 
			for(j=i;s0[j]!='\0';j++)
			s0[j]=s0[j+1];
		if(s0[i]==')')
			for(j=i;s0[j]!='\0';j++)
			s0[j]=s0[j+1];
	}
	for(i=0;s0[i+1]!='\0';i++)		//判断字母是否连着字母
	{
		if(s0[i]>='A'&&s0[i]<='Z')
		{
			if(s0[i+1]=='&'||s0[i+1]=='|'||s0[i+1]=='-'||s0[i+1]=='=');
			else{
				flag=0;
				break;}
		}
		if(s0[i]=='!')		//判断!后跟的是不是字母
		{
			if(s0[i+1]>='A'&&s0[i+1]<='Z');
				else{
				flag=0;
				break;}
		}
		if(s0[i]=='&'||s0[i]=='|'||s0[i]=='-'||s0[i]=='=')		//判断符号后跟的是不是字母
		{
			if(s0[i+1]>='A'&&s0[i+1]>='Z'||s0[i+1]!='!');
				else{
				flag=0;
				break;}
		}
	}
	if(flag==1)
		num=judgeNum(st);		//判断变量个数并且返回值
	if(flag==1)
		trueTable(st,num);
	else printf("合式公式错误!\n");


}
void judgeParentheses(char st[])		//判断括号匹配是否正确
{
	int i,left,right;		
	left=0;right=0;
	for(i=0;st[i]!='\0';i++)
	{	if(st[i]=='(')left++;
		if(st[i]==')')right++;
		if(left>right+1||left+1<right)break;
	}
	if(left!=right){flag=0;}
	else judgeSymbol(st);		//调用判断符号是否正确

}
void transform(char st[])		//把条件和双条件转化为-和=表示
{
	int i,j;
	for(i=0;st[i]!='\0';i++)		//把双条件转化为=
	{
		if(st[i]=='<')
		{
			st[i]='=';
			if(st[i+2]!='\0')
				for(j=i;st[j]!='\0';j++)
				st[++i]=st[i+2];
			else if(st[i+2]=='\0')
				st[++i]='\0';
		}
	}
	for(i=0;st[i]!='\0';i++)		//把条件转化为-
	{
		if(st[i]=='-')
		{
			if(st[i+1]!='\0')
				for(j=i;st[j]!='\0';j++)
				st[++i]=st[i+1];
			else if(st[i+2]=='\0')
				st[++i]='\0';
		}

	}
}
void main()	
{
	while(1){		//循环运行
	printf("请输入1-4变元的一个合式公式:\n");
	printf("仅支持大写英文字母的变元!\n");
	printf("合取(&),析取(|),否定(!),条件(->),双条件 (<->):\n");
	gets(str);
	strcpy(st,str);
	transform(st);		//调用转化函数
	judgeParentheses(st);		//调用判断函数
	system("pause");	//	按一下继续
	system("cls");		//清屏
	}
}


感想:转专业来到物联网学院,因为转专业需要补修大一课程的原因,打乱了自己的课表,和物联网不同的班级上课,发现每个班的优秀的同学都好多的,感觉自己大一像是玩了一样,而他们却学课外的知识,什么Python、java、单片机、MySQL等等。
这次离散数学大作业,感觉内容还好吧,虽然对我来说有点吃力,没系统的学过数据结构,C语言主要内容学完的情况下,能够完成感觉自己还是不错的。上课课程其他地方没有落下,就是某些算法,耦合度等关键词,因为数据结构没上,了解的也不是很多。只能大二下再补课。
写完这次大作业之后,感觉写其他的程序代码也不是很长。首先,克服了感觉自己代码输长了就闲麻烦,或者感觉输入的不正确。其次,为以后打程序打下了一个比较良好的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值