命题逻辑中的主范式的求解(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
请按任意键继续. . .

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

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以通过编写一个程序来实现利用真值表求任意一个命题公式的范式的功能。具体的实现方式可以参考以下代码示例: ```c #include <stdio.h> #include <stdbool.h> #include <stdlib.h> int main() { // 输入命题公式的变量个数 int n; printf("请输入命题公式的变量个数:"); scanf("%d", &n); // 根据变量个数生成真值表 int rows = 1 << n; // 真值表的行数 bool **table = (bool **)malloc(rows * sizeof(bool *)); for (int i = 0; i < rows; i++) { table[i] = (bool *)malloc(n * sizeof(bool)); for (int j = 0; j < n; j++) { table[i][j] = (i >> (n - j - 1)) & 1; // 生成第 i 行的值 } } // 输入命题公式的真值表 bool *result = (bool *)malloc(rows * sizeof(bool)); printf("请输入命题公式的真值表:\n"); for (int i = 0; i < rows; i++) { scanf("%d", &result[i]); } // 求范式 bool *prime_implicants = (bool *)malloc(rows * sizeof(bool)); for (int i = 0; i < rows; i++) { prime_implicants[i] = false; // 初始化为不是因子 } for (int i = 0; i < rows; i++) { if (result[i]) { // 如果结果为真 prime_implicants[i] = true; // 标记为因子 for (int j = i + 1; j < rows; j++) { bool is_implicant = true; // 判断是否为因子 for (int k = 0; k < n; k++) { if (table[i][k] != table[j][k] && table[i][k] != 2 && table[j][k] != 2) { is_implicant = false; break; } } if (is_implicant) { prime_implicants[j] = true; // 标记为因子 } } } } // 输出范式 printf("命题公式的范式为:"); for (int i = 0; i < rows; i++) { if (prime_implicants[i]) { printf("("); for (int j = 0; j < n; j++) { if (table[i][j]) { printf("%c", 'A' + j); } else { printf("!%c", 'A' + j); } if (j != n - 1) { printf("&&"); } } printf(")"); if (i != rows - 1) { printf("||"); } } } printf("\n"); // 释放内存 for (int i = 0; i < rows; i++) { free(table[i]); } free(table); free(result); free(prime_implicants); return 0; } ``` 在上面的代码,我们使用了动态内存分配来生成真值表并存储命题公式的真值表。然后,我们根据命题公式的真值表求出范式,并输出结果。需要注意的是,由于范式可能包含多个项,因此我们使用 `||` 运算符进行连接。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值