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. 这些算法在印度农村医疗中发挥极大作用,未来还将发挥哪些作用?
  2. 基于ECS部署LAMP环境实验记录
  3. Java程序设计学习笔记(一)
  4. 卸载重装svn后原来项目不受管理,版本不对应还是,升级工作副本解决?
  5. 如何在 ASP.NET Core 中使用 ActionFilter
  6. 【OJ】洛谷字符串题单题解锦集
  7. mysql转达梦7_从mysql换成达梦7后,查询语句报错,这个是druid的问题吗
  8. c++多边形扫描线填充算法_python 小乌龟turtle画随机正多边形
  9. GitHub 疑被审查?著名“换脸”开源项目遭限制访问
  10. 高通骁龙cpu排行_最新手机性能排行榜出炉:高通骁龙865霸榜,前十不见华为!...
  11. Web Uploader文件上传插件
  12. python pywinauto 自动控制微信, 关键字回复、收款、定时任务, 代替人工成为微信客服
  13. excel题库做成刷题得html,实例教你制作简易的Excel出题库,送给在一直忙碌的你!...
  14. ENVI5.4中Himawari-8数据处理(向日葵8号卫星H-8)
  15. jQueryEasyU校验邮箱、手机号等
  16. 汉诺塔python创新设计_递归经典案例汉诺塔 python实现
  17. Deep Multimodal Representation Learning(深度多模态表示学习)
  18. 计算机科学与技术论文选题怎么选,比较好写的计算机科学与技术专业论文选题 计算机科学与技术专业论文题目如何取...
  19. 考研经验帖——特别说明很适合8月才开始准备的小伙伴
  20. 很遗憾未能成功连接服务器神武,神武十年《见证》逍遥游戏里的超级学霸 最希望被别人抄“作业”...

热门文章

  1. cachecloud安装指南
  2. 宇视网络视频录像机添加摄像机提示离线
  3. 华为铁三角:铁三角模式诞生背景与思考
  4. 电脑Win7系统桌面图标太大怎么调小
  5. Matlab中的atmoscoesa函数与atmosisa函数——不同海拔下的标准大气参数查询
  6. jenkins(一)------Windows环境下jenkins下载和安装
  7. 第十五课.K均值算法
  8. C语言习题二:比赛评分系统
  9. java浅拷贝与深拷贝及拷贝工具推荐
  10. Delta并联机构在ADAMS仿真中的运动副设置