//寒假,离散老师说,把几个程序实现一下。但是在家里都没怎么去看。花了点时间结束。
1、求解最后的真值,一般可以用栈,二叉树,当然还有其他方法。(可以参考:http://www.cnblogs.com/U2USoft/archive/2009/03/26/1422545.html)
2、个人觉得麻烦的地方是,模拟离散数学中的真值表计算的过程。它并不是从左到右直接计算的。而是按照层次。优先级高的先计算,然后计算次优先级的,直到计算完整个表达式。模拟的程序要求输出每层运算的结果。
离散数学书上,真值表计算具体步骤要求如下:
a,找出公式中的所含的全体命题变量,列出2^n个赋值
b,按从高到低的顺序写出公式的各个层次;
c,对应各个赋值计算出各个层次的真值,直到计算公式的真值
下面有个程序输出的例子。(打印的输出暂默认>为->)_______________________________________________
请输入逻辑表达式,回车结束...
^(p->q)&q&r
真值表如下:
________________________________________________
p q r p>q ^(p>q) (^(p>q)&q) ((^(p>q)&q)&r)
0 0 0 1 0 0 0
0 0 1 1 0 0 0
0 1 0 1 0 0 0
0 1 1 1 0 0 0
1 0 0 0 1 0 0
1 0 1 0 1 0 0
1 1 0 1 0 0 0
1 1 1 1 0 0 0
________________________________________________
要继续计算? (y:是 n:否)
你的选择:
解决关键:
主要要找到每层的每个子命题(子公式),然后依次计算保存。
建立表达式二叉树,从树节点的深度(这里的叶子节点的深度最小)就可以知道它的层次,按树节点的深度从小到大选择树节点,依次计算这个深度下的所有树节点及其一下的节点构成的命题。这样就保证“层次”计算的要求。保存的每个表头,就是子命题公式(如^(p>q))。从表达式树回到表达式时要注意括号和^。最后打印就可以啦。此外打印时候,注意对齐方式。
本来是想每个子命题的运算完后,接着利用其计算结果继续计算大一点的子命题,以此扩展到整个明天的计算,但是好像有点烦,就放弃了。还是采用重复计算。
下面是一个真值表类的头文件:
[code=C++]
/////////////////////////////////////////////////////////////////////
// filename: truth_table.h
// Author: feng02
// purpose: 真值表类以及实现
// 用于将输入的公式命题在所有的赋值情况列成表
// 包括的联结词有(、)、&、|、^、->、<->;
// Main functions: SubStr,Evaluate,CreateExprBinTree等
// Edition: *V3[2010/3/22] V1[2010/3/3] V2[2010/3/13]
// modification : 1、修改添加函数,实现真值表的每层运算的输出
// 2、修改了函数的参数,便于重用
// References: 参考计算器程序,写了计算部分
// to be improved: 1、本函数计算第一层时,只要是第一层就直接读入计算,
// 没有优先级,如^p,p&q没有优先之分
// 2、最后的真值表输入格式有待改善
// 3、已经是二叉树就可以直接中序带入计算了;
// 但是本程序之前使用栈,所以还是化成表达式后用栈计算
// 4、程序效率和其他。
/////////////////////////////////////////////////////////////////////
#include
#include
#include
#include "BinaryTree.h"
#define MAXLIST 32 //charnum的最大值
#define MAXLENTH 500 //(输入的表达式重新变成表达式后的最大长度)
using namespace std;
class TRUTH_TABLE
{
public :
TRUTH_TABLE(BinTreeNode<char>*p); //构造函数
~TRUTH_TABLE(); //析构函数
bool Run(); //公共函数:提供一次完整的真值表计算
private:
void CreateExprBinTree(BinTreeNode<char> *&root,char exprstr[]);//建立表达式二叉树
int GetLeftPri(char c); //得到左逻辑符号的优先级
int GetRightPri(char c); //得到右逻辑符号的优先级
bool IsOpr(char c); //判断c是否为种联结词之一
void GetEprStr(char exprstr[]); //完成输入和保存exprstr,并去除空白字符' '
bool ChangeSign(char exprstr[]); //将->转换为>,将<->转换为*,判断是否存在字符
bool ChangeSubStr(BinTreeNode<char>* t,char str[], int &ipos);//将表达式二叉树重新转换成带括号表达式
void SetTruthList(); //按字母顺序设定truthlist的1,0值
int GetCharNum(char expstr[]); //计算并返回表达式中的命题变量(即不同字母)的个数
int GetChar2Num(char num, int times); //将char(p,q,r)转换成1,0
int OperateNum(int rnum, char theta, int lnum ); //计算rnum theta lnum并返回结果
void SubStr(BinTreeNode<char> *root); //寻找并计算每层的命题(子命题)
void Evaluate(char charnum, char exprstr[],int *&truthanswerlist);//对给定的命题或子命题计算逻辑运算结果
void ShowLastList(); //显示最后的逻辑运算结果
private:
BinTreeNode<char> *root; //根节点
CBinTree <char> *ptree; //表达式二叉树
int charnum; //不同字母的个数
int substrnum; //子表达式(表头)的个数
char charlist[MAXLIST]; //字母列表
char exprstr[MAXLENTH]; //以char保存输入的表达式
int *truthlist; //字母不同赋值列表
int *truthanswerlist[MAXLENTH]; //对应的真值表结果列表
char *substrlist[MAXLENTH]; //相应的子命题
};
[/code]