C语言实现主析取范式

第一次写,不喜勿喷
(先来水一波)
先保证输入的式子是合法的 (不合法我也不会,太弱了)
难点主要是计算真值表,可以用堆栈实现,建立两个堆栈,一个储存操作符,另一个储存数值 (手写堆栈)

int OPNUM[300], OPOP[300], inum = 0, inop = 0;//储存数字和操作符的堆

储存的是int类型,在这之前有将操作符转化成对应的优先级

int charge_operator(char ch){//判断优先级if (ch == '!') return 1;else if (ch == '&') return 2;else if (ch == '|') return 3;else if (ch == '$') return 4;//单条件else if (ch == '@') return 5;//双条件else if (ch == '(') return 6;else if (ch == ')') return 7;return 10;
}

如果上一个操作符和这个操作符的优先级相同或者上一个操作符的优先级大于这个操作的优先级,则可以计算,也就是取上一个操作的操作符,和数值栈的前两个元素计算,然后再压入栈。否则操作符直接入栈,操作符堆其实是维持一个单调递增的序列。

if(cha>=OPOP[inop] && inop){//保证有操作符int op = OPOP[inop];int a, b, c;a = OPNUM[inum-1], b = OPNUM[inum], inum--;//取数值栈的前两个c = operator_A(op, a, b);//计算数值OPNUM[inum]=c;//数值入栈OPOP[inop] = cha;//操作符入栈
}
else OPOP[++inop]=cha;

这里主要判断一下条件非,和左括号:
条件非的判断:只需要在每个数值入栈之前看一下操作符是不是条件非

//f数组用来储存表达式
if (f[i]=='0' || f[i] == '1'){if (OPOP[inop] == 1) {OPNUM[++inum] = (f[i] == '1'? 0:1); inop--;} //判断!的情况else OPNUM[++inum] = f[i] - '0';}

在条件非入栈的时候,看一下上一个操作符是不是条件非,如果是两个条件非就相互抵消了,例如!!0, 两个非就直接抵消。

如果是左括号直接入栈,如果是右括号,直接往前计算到左括号。
最后别忘记堆栈中剩余的元素

 while(inop!=0){int op = OPOP[inop];inop--;int a, b, c;a = OPNUM[inum-1], b = OPNUM[inum], inum--;c = operator_A(op, a, b);OPNUM[inum]=c;}

直接上代码

#include<stdio.h>
#include<bits/stdc++.h>
#define extraction '|' //析取
#define conjunction '&' //合取
#define non '!'//非
/*
双条件@
单条件$
*/
char forluma[1100]; //表示表达式和表达式的列数,数组从1开始
int n, col, row,num;//用来储存真值表中的行数和列数,num表示变量的个数
int Map[300][300],mp[300],nowval[30];//用mp维护数组,map存放真值表,nowval存当前表达式每个字母的取值
void init(){memset(forluma,0, sizeof(forluma));memset(Map, 0, sizeof(Map));memset(mp, 0, sizeof(mp));col=0,row=0;
}
void read(){char ch;int cnt = 0;while(scanf("%c", &ch) != EOF){if ((ch >='A' && ch <= 'Z') || ch == '(' || ch == ')' || ch ==extraction || ch == conjunction || ch == non|| ch == '@' || ch == '$'){//去掉输入的空格空格forluma[++cnt] = ch;}if (ch >='A'&&ch<='Z'&&!mp[ch]){//用mp维护字母mp[ch]=++num;}}n = cnt, cnt = 0;for (int i = 1; i <= 100; i++){//离散化变量if (mp[i])mp[i]=++cnt;}
}
int operator_A(int ch, int x, int y){//计算式子的值if (ch == 2) return x & y;else if (ch == 3) return x | y;else if (ch == 4){if (x == 1 && y == 0) return 0;else return 1;} else if(ch == 5){if (x == y) return 1;else return 0;}return 0;
}
int charge_operator(char ch){//判断优先级if (ch == '!') return 1;else if (ch == '&') return 2;else if (ch == '|') return 3;else if (ch == '$') return 4;else if (ch == '@') return 5;else if (ch == '(') return 6;else if (ch == ')') return 7;return 10;
}char f[1200];//赋值的式子
int calculate(){for (int i = 1; i <= n; i++){//把每个字母的值赋值给式子if (forluma[i] >='A' && forluma[i] <= 'Z') f[i]=nowval[mp[forluma[i]]] + '0';else f[i] = forluma[i];}int OPNUM[300], OPOP[300], inum = 0, inop = 0;//储存数字和操作符的堆for (int i = 1; i <= n; i++){if (f[i]=='0' || f[i] == '1'){if (OPOP[inop] == 1) {OPNUM[++inum] = (f[i] == '1'? 0:1); inop--;} //判断!的情况else OPNUM[++inum] = f[i] - '0';}else {int cha = charge_operator(f[i]);if(cha == 7){//右括号的情况int op = OPOP[inop]; inop--;//取运算符while(op != 6){//一直算到左括号int a, b, c;a = OPNUM[inum-1], b = OPNUM[inum], inum--;c = operator_A(op, a, b);OPNUM[inum]=c;op=OPOP[inop--];}op=OPOP[inop];if(op==1) {OPNUM[inum] = !OPNUM[inum];inop--;}//判断'('前面是不是条件非}else if(cha == 6) OPOP[++inop] = cha;else if (cha == 1){//条件非的判断if(OPOP[inop] == 1) inop--;//!!0 = 0,两个非相互抵消else OPOP[++inop] = cha;}else{if(cha>=OPOP[inop] && inop){//保证有操作符,上一个操作符的优先级大于等于这个操作的优先级int op = OPOP[inop];int a, b, c;a = OPNUM[inum-1], b = OPNUM[inum], inum--;c = operator_A(op, a, b);OPNUM[inum]=c;OPOP[inop] = cha;}else OPOP[++inop]=cha;}}}while(inop!=0){//最后清空操作符栈int op = OPOP[inop];inop--;int a, b, c;a = OPNUM[inum-1], b = OPNUM[inum], inum--;c = operator_A(op, a, b);OPNUM[inum]=c;}return OPNUM[1];
}
void dfs(int now_x){//枚举每一种情况if (now_x  == num){row++;for (int i = 1; i <= now_x; i++) Map[row][i] = nowval[i];Map[row][now_x+1] = calculate();return ;}nowval[now_x + 1] = 0;dfs(now_x + 1);nowval[now_x + 1] = 1;dfs(now_x + 1);
}void work(){dfs(0);printf("真值表:\n\t\t");char abc[30];int cnt = 0;for (int i = 1; i <= 100; i++){if (mp[i]) {printf("%c ", i);abc[++cnt]=i;}}printf("\n\t\t");for(int i = 1; i<=row; i++){for (int j = 1; j <= num + 1; j++){printf("%d ",Map[i][j]);}printf("\n\t\t");}char xi[2000], he[2000];int x=0, h=0;for (int i = 1; i <= row; i++){if (Map[i][num+1]==1){if (x) xi[++x] = '|';xi[++x] = '(';for (int j = 1; j <= num; j++){if(j!=1)xi[++x]='&';if (Map[i][j] == 0)xi[++x]='!';xi[++x]=abc[j];}xi[++x]=')';}else {if (h)he[++h]='&';he[++h]='(';for (int j = 1; j <= num; j++){if (j!=1)he[++h]='|';if (Map[i][j]==1)he[++h]='!';he[++h]=abc[j];}he[++h]=')';}}printf("\n主析取范式:");for (int i = 1; i <= x; i++) {if (xi[i]=='|') printf("∨");else if (xi[i]=='&') printf("∧");else if (xi[i]=='!') printf("ㄱ");else printf("%c",xi[i]);}printf("\n主合取范式:");for (int i = 1; i <= h; i++){if (he[i]=='|') printf("∨");else if (he[i]=='&') printf("∧");else if (he[i]=='!') printf("ㄱ");else printf("%c",he[i]);}
}int main(){printf("请输入逻辑表达式:\n");printf("与逻辑:&  或逻辑:|  非逻辑:! 单条件:$  双条件:@\n");printf("请注意:表达式错误程序可能无法运行或者结果错误\n");init();read();work();
}

输入:

(P$R)&(Q$!R)&(!R$(P|Q))

输出:

请输入逻辑表达式:
与逻辑:&  或逻辑:|  非逻辑:! 单条件:$  双条件:@
请注意:表达式错误程序可能无法运行或者结果错误
真值表:P Q R 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 0 0 0 1 0 1 1 1 1 0 0 1 1 1 0 主析取范式:(ㄱP∧ㄱQ∧R)∨(ㄱP∧Q∧ㄱR)∨(P∧ㄱQ∧R)
主合取范式:(P∨Q∨R)∧(P∨ㄱQ∨ㄱR)∧(ㄱP∨Q∨R)∧(ㄱP∨ㄱQ∨R)∧(ㄱP∨ㄱQ∨ㄱR)

如有错误欢迎指正

主析取范式主合取范式相关推荐

  1. 【c++】[自动生成真值表/主析取范式/主合取范式的计算器]

    关于自动生成真值表/主析取范式/主合取范式的计算器 我用c++写了一个,需要的自取,如果好用请点赞 链接:https://pan.baidu.com/s/1Ji1zPDtjAc6-TDxovEzMVw ...

  2. 求主析取范式与主合取范式

    定义设A为恰含命题变元p1,-,pn的公式.公式A称为A的主析(合)取范式(majordisjunctive(conjunctive)normal form),如果A是A的析(合)取范式,并且其每个合 ...

  3. 离散数学范式c语言实验报告,离散数学实验报告-利用真值表法求主析取范式及主合取范式的实现...

    1.实 验 报 告( / 学年 第 一 学期)课程名称离散数学实验名称利用真值表法求主析取范式及主合取范式的实现实验时间年月日指导单位指导教师学生姓名班级学号学院(系)专 业 实 验 报 告实验名称利 ...

  4. 【数理逻辑】范式 ( 合取范式 | 析取范式 | 大项 | 小项 | 极大项 | 极小项 | 主合取范式 | 主析取范式 | 等值演算方法求主析/合取范式 | 真值表法求主析/合取范式 )

    文章目录 一. 相关概念 1. 简单 析取 合取 式 ( 1 ) 简单合取式 ( 2 ) 简单析取式 2. 极小项 ( 1 ) 极小项 简介 ( 2 ) 极小项 说明 ( 3 ) 两个命题变项 的 极 ...

  5. 利用真值表法求取主析取范式以及主合取范式的实现(C++)

    代码如下: #include <iostream> #include <stack> #include <string> #include <vector&g ...

  6. matlab析取范式求主析取范式用电脑,(p∧q)∨r 求其主析取范式 再用主析取范式求主合取范式...

    共回答了21个问题采纳率:90.5% 主合取范式:若干个极大项的合取. 主析取范式:若干个极小项的析取. 例, 求公式(p∧q)∨r的主析取范式及主合取范式. 主析取范式: (p∧q)∨r (p∧q∧ ...

  7. c语言编程输出主析取范式,c++编程:从键盘上任意输入一个主析取范式,输出与之等值的主合取范式...

    满意答案 zxuu11 2013.09.15 采纳率:44%    等级:8 已帮助:2365人 //从键盘上任意输入一个主析取范式,输出与之等值的主合取范式.┐∧∨ # include # incl ...

  8. 离散数学 求命题公式的主析取范式和主合取范式

    Description 输入命题公式的合式公式,求出公式的真值表,并输出该公式的主合取范式和主析取范式. Input 命题公式的合式公式 Output 公式的主析取范式和主合取范式,输出形式为:&qu ...

  9. 【离散数学】Java语言实现利用真值表法求主析取范式和主合取范式

    C++版本的看这个链接: [离散数学]C++语言实现利用真值表法求主析取范式和主合取范式_zhtstar的博客-CSDN博客https://blog.csdn.net/weixin_56319483/ ...

  10. 离散实验 真值表求主析取范式、主合取范式的计算机语言实现

    离散数学 实验一 标题:真值表求主析取范式.主合取范式的计算机语言实现 其他课程的一些其他实验源码也可在本人github主页找到哦 链接如下:https://github.com/Schiz0mani ...

最新文章

  1. 终于不瞎编了!AI学会了“谷歌一下”,回答问题正确率达90% | DeepMind
  2. 查看MySQL表占用空间大小
  3. C++学习笔记6:多文件编程
  4. Java 高级特性 --- 反射
  5. 非替换元素和替换元素
  6. c高级语言程序设计B试题,高级语言程序设计试题(B)卷.doc
  7. new 对象时的暗执行顺序
  8. 【NOI OpenJudge】【1.3】编程基础之算术表达式与顺序执行
  9. Atitit. 提升可读性推荐标准规范解决方案 关于编程语言的v5 docx
  10. 计算硬盘的计算机,硬盘整数分区计算器免费版
  11. sever串口wifi拓展板_什么是串口WIFI模块
  12. 美国行政区划 数据mysql,美国,行政区划地理数据库大全.doc
  13. Spring Securiy +aouth2.0+jwt整合,实现鉴权登录
  14. 3029. 【NOIP2011DAY2】观光公交
  15. numpy矩阵与向量类型的向量乘法
  16. C语言高级应用---操作linux下V4L2摄像头应用程序
  17. 【深度学习】神经网络的学习过程
  18. Cookie,sessionstorage,localstorage,Token ,JWT,session的区别
  19. IFrame语法小全
  20. Google 的封杀与被封杀

热门文章

  1. SPSS学习资料汇总
  2. 计算机没有光驱降无法启动,windows 未能启动 原因可能是最近更改了硬件或软件 没有光驱怎么办...
  3. 蓝牙耳机哪个牌子好?国庆出游蓝牙耳机推荐
  4. 计算机应用中存在性证明的代数拓扑方法(附顾险峰教授简历,公号回复“代数拓扑”、“顾险峰”可下载PDF资料,欢迎赞赏转发支持社区)
  5. 上海计算机应用基础自考上机,上海市自学考试公共实践课程《计算机应用基础(实践)》上机考核大纲_自考资讯自考_自考报名_中国教育在线...
  6. NLP-自然语言处理入门(持续更新)
  7. 新手对vue中特殊的标签属性ref和key的理解
  8. matlab一维插值extrap,MSC Patran中基于Matlab插值函数的多场创建
  9. linux常用的英文单词收集
  10. 并联机构工作空间求解_结构计算软件—结构力学求解器