在求解命题逻辑中主范式的时候,对于输入的式子(字符串)的处理极其重要,这关系到范式的求解的成功与否。
输入的公式如: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
请按任意键继续. . .
同样的,也可以用后缀式来计算一些加减乘除的多项式运算(虽然可能用计算器就可以轻松做到了)。