命题逻辑中的主范式的求解(c语言实现)

在求解命题逻辑中主范式的时候,对于输入的式子(字符串)的处理极其重要,这关系到范式的求解的成功与否。

      输入的公式如:p->q,计算机并不“认识”这种式子。因而可以将其转化为后缀式(逆波兰式):pq->,让计算机按照它的方式扫描、计算。同时实现此求解的过程还需要将一些十进制的数据转换为二进制,和一些小技巧。废话不多说,代码如下:

//c语言代码求主范式 
#include <stdio.h>
#include <string.h>
//合取符号 &  ;析取符号 |;
//非 !;条件 >;
//双条件 =;

//通过构造堆栈来将输入的式子转化为后缀式(即逆波兰式) 
typedef struct{
	int dex;
	char a[100];
}inf;
typedef struct{
	int c[30];	//用来表示命题变项 如:含有'a'时 c[0]=1;否则c[0]=0; 
	int d[30];	//储存命题变量相应的真假 
}date;
inf sca;	//输入存储 
inf pro;	//得到处理后的逆波兰式 
inf b;	//用来储存运算符号
int result[30];	//用来储存合式公式在赋值后的结果
int res; 
date mac;	//用来记录命题变项的种类  及  赋值情况 
int tem[100];	//用来存储命题变项的真假 
int Fi[100];     //用来记录合取范式的下标 

//输入合式公式,转换成逆波兰式 
//方便对式子的处理 
void get_(){			
	gets(sca.a);
	sca.dex=strlen(sca.a);
	int i=0;
	pro.dex=-1;
	b.dex=-1;
	//用数字字符取代输入的逻辑运算符,以便校准它们的运算优先级 
	for(i=0;i<=sca.dex;i++){
		if(sca.a[i]=='(')sca.a[i]='7';
		if(sca.a[i]=='=')sca.a[i]='2';
		if(sca.a[i]=='>')sca.a[i]='3';
		if(sca.a[i]=='|')sca.a[i]='4';
		if(sca.a[i]=='&')sca.a[i]='5';
		if(sca.a[i]=='!')sca.a[i]='6';
		if(sca.a[i]==')')sca.a[i]='8';	}
	for(i=0;i<=sca.dex;i++){
		//遍历输入字符串,if语句储存字母
		if(sca.a[i]-'a'>=0&&sca.a[i]-'a'<26){ 
			pro.dex++;
			pro.a[pro.dex]=sca.a[i];
		/*记录字符串中命题变项的个数 及 信息*/ 
			mac.c[sca.a[i]-'a']=1;
		}
		//else语句对运算符进行处理 
		else{ if(sca.a[i]=='7'){	//当'(' 在堆栈外时,优先级大于逻辑预算符 
			    b.dex++;			//放入堆栈后,它的优先级降到最低 
			    b.a[b.dex]='1';	
				}
			else  if(b.dex==-1){
			b.dex++;
			b.a[b.dex]=sca.a[i];
				}
		/*接着通过各个运算符的优先级进行入栈和出栈*/ 
			else if(sca.a[i]=='8'){
				while(b.a[b.dex]!='1'){
					pro.dex++; 
					pro.a[pro.dex]=b.a[b.dex];
					b.dex--;
				}b.dex--;
			}
			else if(sca.a[i]<b.a[b.dex]) {
				while(sca.a[i]<b.a[b.dex]){
					pro.dex++;
					pro.a[pro.dex]=b.a[b.dex];
					b.dex--;
					}
				b.dex++;
				b.a[b.dex]=sca.a[i];
		 		}
			else if(sca.a[i]>b.a[b.dex]){
				b.dex++;
				b.a[b.dex]=sca.a[i];
				}
			else if(sca.a[i]==b.a[b.dex]){
				pro.dex++;
				pro.a[pro.dex]=b.a[b.dex];
				b.a[b.dex]=sca.a[i];
			}
			}			
		}
		//将最后一个逻辑运算符弹出 
		pro.dex++;
	    pro.a[pro.dex]=b.a[b.dex];
	    b.dex--;
	}
int numb(){
	int n=0;//遍历mac.c[]中1的个数,求变项的个数 
	int count=0;
	for(;n<=30;n++)
	if(mac.c[n])count++;
	return count;
}
//最大赋值情况 ,如命题变量为3时,最大赋值情况为2^3-1;
int get_numb(int count){ 
	int i=0;
	int n=1;
	for(;i<count;i++){
		n*=2;
	}
	return n-1;
}
//将赋值情况由十进制转换二进制(如:2个命题变项,对应的赋值情况0~2^2-1,
//将所有情况转换为二进制,即可对应真值表中的赋值) 
void get_b(int i){ 
      int u=0;
      for(;u<=numb();u++){
      	tem[u]=0;
	  }u=0;
	while(i!=0){
		tem[u]=i%2;
		u++;
		i/=2;
	}
}
//对第二个结构date mac储存真值
void save(){
	int i=0;
	int q=get_numb(numb());
	for(;i<=q;i++){get_b(i);
    int j=29; 
    int count=0;
	for(;j>=0;j--){
		if(mac.c[j]==1){
			mac.d[j]=tem[count];
			count++;
			}
		}                    //i 值为命题变项所赋值的十进制 
	if(calculate())Fi[i]=1;	//将结果为 1 的赋值情况进行标 
	}                       //结果为 1 的赋值转换为十进制对应析取范式下标 
	
} 
/*对所得到的各种值的情况进行逻辑运算*/ 
int calculate(){
	pro.dex=strlen(pro.a);
	int k=0;
	res=-1;//用res标记result[]的值的存储位置,相当一个堆栈 
	//result[]仅储存命题变项的真值 
	for(;k<=pro.dex;k++){
		if(pro.a[k]-'a'>=0&&pro.a[k]-'a'<26){
			res++;
			result[res]=mac.d[pro.a[k]-'a'];
		
		}
		/*对储存的命题变项进行运算,得到的结果将储存在result[0]中*/ 
		else if(pro.a[k]>='1'&&pro.a[k]<='8'){
				if(pro.a[k]=='6')result[res]=!result[res];
				else if(pro.a[k]=='5')result[res-1]=result[res-1]&&result[res],res--;
				else if(pro.a[k]=='4')result[res-1]=result[res-1]||result[res],res--;
				else if(pro.a[k]=='3')result[res-1]=result[res]||!result[res-1],res--;
				else if(pro.a[k]=='2')result[res-1]=(!result[res]||result[res-1])&&(!result[res-1]||result[res]),res--;
		}
	}
	return result[0];
}
//遍历得到主析取范式 
void disjunctive(){
	int j=get_numb(numb());
	int i=0;
	for(;i<=j;i++){
	
		if(Fi[i]){
			if(i!=0)printf("|");
			printf("m%d",i);
		}
	}
}
//未标记的位置(储存值为0)对应合取范式,遍历得到主合取范式 
void conjunctive(){
	int i=get_numb(numb());
	int j=0;
	for(;j<=i;j++){
		if(!Fi[j]){
			if(j!=0)printf("&");
			printf("M%d",j);
		}
	}
	
}
/*输出逆波兰式 将数字化的逻辑运算符还原,遇到命题变项则输出,遇到括号丢弃*/ 
void put_nibolan(){
	int i=0;
	for(;pro.a[i]!=0;i++){
		if(pro.a[i]=='1')
		;
		else if(pro.a[i]=='2')printf("=");
		else if(pro.a[i]=='3')printf(">");
		else if(pro.a[i]=='4')printf("|");
		else if(pro.a[i]=='5')printf("&");
		else if(pro.a[i]=='6')printf("!");
		else printf("%c",pro.a[i]);
	}
}
int main(){
	get_();
	printf("后缀式为:");
	put_nibolan();
	puts("");
	save();
	printf("主析取范式为:");
	disjunctive();
	puts("");
	printf("主合取范式为:");
	conjunctive();
	return 0;
}

    代码中涉及到一些数据结构的知识:堆栈的使用。通过堆栈的“先进后出”的特点,使后缀式的实现更加简单。

输出结果:

p>(p|q)
后缀式为:ppq|>
主析取范式为:m0|m1|m2|m3
主合取范式为:
--------------------------------
Process exited after 2.371 seconds with return value 0
请按任意键继续. . .

   同样的,也可以用后缀式来计算一些加减乘除的多项式运算(虽然可能用计算器就可以轻松做到了)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值