离散实验演示

1.实验目的

 通过实验理解命题、命题公式及真值表的概念和正确表示方法,掌握范式的定义,学会利用真值表求出命题的主析取范式和主合取方式。能够利用真值表判断命题是否为永真式、永假式,判断两个命题是否是蕴含的或等价的。在此基础上,实现对命题推理的正确性进行判断,解决一些实际推理问题。

2.实验要求

(1) 测试用例要包含以下多种情况 :

(a) 对命题表达式正确性的判断

(b) 包含5个逻辑联结词

(c) 根据真值表求出命题的主析取范式和主合取方式

(d) 输入两个命题公式,判断其逻辑关系

(e) 输入一个逻辑推理式子,判断其正确性。

(2) 实验报告中给出算法设计思想及流程图

(3) 给出测试结果截图

(4) 写出实验总结、分析及心得

3.实验内容

输入:

命题公式

输出:

(1) 命题真值表

(2) 命题的类别

(3) 命题的主析取范式与主合取范式

(4) 两个命题公式的逻辑关系

(5) 判断命题推理的正确性

4.代码:

#include<iostream>
#include<math.h>
#include<string.h>
#include<stack>
#include<vector>
using namespace std;
 
int sum=2; 
stack<bool> OPND;//操作数或运算结果栈
stack<char> OPTR;//运算符栈
const char operateChar[8] = { '+', '-', '|', '&', '!', '(', ')','#' };
//运算符(+:等价、-:蕴涵、|:析取、&:合取、!:否定
string VarList;//保存公式中的变元
 
//判断字符是否是运算符
bool In(char ch) {
    for (int i = 0; i < (int)strlen(operateChar); i++)
        if (operateChar[i] == ch)
            return true;
    return false;
}
 
//比较运算符的优先级
char Precede(char theta1, char theta2) {
    //运算符优先级表
    char operate_Table[8][9] = {
    "><<<<<>>",
    ">><<<<>>",
    ">>><<<>>",
    ">>>><<>>",
    ">>>>><>>",
    "<<<<<<=E",
    ">>>>>E>>",
    "<<<<<<E="
    };
    int theta1_Index=0, theta2_Index=0;//定义运算符1和运算符2的索引
    for (int i = 0; i < (int)strlen(operateChar); i++){
        if (operateChar[i] == theta1)
            theta1_Index = i ;
        if (operateChar[i] == theta2)
            theta2_Index = i ;
    }
    return operate_Table[theta1_Index][theta2_Index];
}
//计算表达式,并将结果返回(双目)
bool Calculate(bool x, char operate, bool y) {
    switch (operate)
    {
    case '+': return (((!x) || y) && (x || (!y))); break;
    case '-': return ((!x) || y); break;
    case '|': return x || y; break;
    case '&': return x && y; break;
    }
    return -1;
}
 
//判断是否是字母(仅小写字母)
bool isAlpha(char ch) {
    if (((int)ch >= 97 && (int)ch <= 122)&&VarList.find(ch)==-1)//若字符的ascii码在97~122中则是字母
        return true;
    else return false;
}
 
//提取公式字符串中全部命题变元,并按递增顺序存放在VarList中<br>//比如  (!a-d)-(c+b)     VarList值就是 "abcd"
void createVarList(string source) {
    int indexNum=0;//比较字母用的下标
 
    for (auto ch:source) {
        if (isAlpha(ch))
            VarList += ch;
    }
    for (int i = 0; i < VarList.length()-1;i++) {
        for (int j = 0; j < VarList.length() - i-1; j++) {
            if ((int)VarList[j] > (int)VarList[j + 1]) {
                char temp = VarList[j];
                VarList[j] = VarList[j + 1];
                VarList[j + 1] = temp;
            }
        }
    }
}
 
//计算表达式
bool InfixValue(string source) {
    OPTR.push('#');
    char item = source[0];
    bool OPNDtop2, OPNDtop1;
    char OPTRtop;
    int i = 1;
    while (item != '#' || OPTR.top() != '#') {
        if (!In(item)) {
            if (item == '0')
                OPND.push(false);
            else
                OPND.push(true);
            item = source[i++];
        }
        else if (OPTR.top() == '!')
        {
            OPTR.pop();
            OPNDtop1 = OPND.top();
            OPND.pop();
            OPND.push(!OPNDtop1);
        }
        else
        {
            switch (Precede(OPTR.top(), item))
            {
            case '<':
                OPTR.push(item);
                item = source[i++];
                break;
            case '>':
                OPTRtop = OPTR.top();
                OPTR.pop();
                OPNDtop1 = OPND.top();
                OPND.pop();
                OPNDtop2 = OPND.top();
                OPND.pop();
                OPND.push(Calculate(OPNDtop2, OPTRtop, OPNDtop1));
                break;
            case '=':
                OPTR.pop();
                item = source[i++];
                break;
            }
        }
    }
    return OPND.top();
}
 
//依次取值的二进制值加1
void IncreaseVarValue(char(&v)[26], int& flag) {
    int m = 1;
     
    int n = VarList.length();
    for (int j = n - 1; j > -1; j--) {
        int temp;
        temp = int(v[j]) - 48;
        flag = flag + temp;
        if (flag == 2) {
            v[j] = '0'; flag = 1;
        }
        else {
            v[j] = '1'; flag = 0; break;
        }
    }
 
}
 
//得到真值表
void TruthTable(string expression,bool * &truthTab,string *&expressionValueList,string *&trowList,int &CircleNum) {
    int m = 1;
    int n = VarList.length();
    int flag;
    char trow[26];//表达式中变元的依次取值
    for (int i = 0; i < n; i++) { m *= 2; trow[i] = '0'; }
    string* expressionValueList_IN = new string[m];
    string* trowList_IN = new string[m];
    bool *truthtable_IN=new bool[m];//真值表中的值 
    CircleNum = m;
 
    //转换成用0或1表示的表达式
    for (int i = 0; i < m; i++) {
        string value1 = expression;//因为公式是字符串无法直接计算,所以定义value1,将里面的命题变元变成0或1
        //使表达式的变元用0或1表示
        for (int j = 0; j < n; j++) {
            char x = VarList[j];
            for (int k = 0; k < expression.length(); k++) {
                char a = value1[k];
                if (value1[k] == x)
                    value1[k] =trow[j];
            }
                 
        }
        trowList_IN[i] = trow;
        expressionValueList_IN[i] = value1;
        truthtable_IN[i] = InfixValue(value1);//将得出来的值依次给truthtable
        flag = 1;
        IncreaseVarValue(trow,flag);
    }
    truthTab = truthtable_IN;
    expressionValueList = expressionValueList_IN;
    trowList = trowList_IN;
}
 
 
//输出真值表
void PrintTable(string expression) {
    string* expressionValueList;//用来保存所有的表达式
    string* trowList;//保存变元的所有取值
    bool* truthtab;//保存所有的表达式的值
    int CircleNum;//循环次数
    createVarList(expression);
    TruthTable(expression, truthtab, expressionValueList, trowList,CircleNum);
    //打印真值表
    for (int i = 0; i < VarList.length(); i++) {
        cout << VarList[i] << "\t";
    }
    cout << expression <<"\t" <<"值"<<endl;
 
    for (int i = 0; i < CircleNum; i++) {
        for (int j = 0; j < VarList.length(); j++) {
            cout << trowList[i][j] << "\t";
        }
        cout << expressionValueList[i] << "\t" << truthtab[i] << endl;
        if(truthtab[i])sum++;
    }
    if(sum==CircleNum+2)sum=1;
    if(sum==2)sum=0;
}
string CategorizeProposition(const string& proposition) {
    // 判断命题是否是等价命题
    bool isEquivalent = false;
    for (char ch : proposition) {
        if (ch == '+') {
            isEquivalent = true;
            break;
        }
    }

    // 判断命题是否是蕴涵命题
    bool isImplication = proposition.find('-') != string::npos;

    // 判断命题是否是合取命题
    bool isConjunction = proposition.find('&') != string::npos;

    // 判断命题是否是析取命题
    bool isDisjunction = proposition.find('|') != string::npos;

    // 判断命题是否是否定命题
    bool isNegation = proposition.find('!') != string::npos;

    string category = "";
	if (isEquivalent) category += "等价命题 ";
    if (isImplication) category += "蕴涵命题 ";
    if (isConjunction) category += "合取命题 ";
    if (isDisjunction) category += "析取命题 ";
    if (isNegation) category += "否定命题 ";


    return category;
}
// 命题的主析取范式(DNF)
string GetDNF(const string& proposition) {
    // 分割命题公式中的子句
    vector<string> clauses;
    string clause = "";
    for (char ch : proposition) {
        if (ch == '|') {
            clauses.push_back(clause);
            clause = "";
        } else {
            clause += ch;
        }
    }
    clauses.push_back(clause);

    // 构建主析取范式
    string dnf = "";
    for (const string& c : clauses) {
        dnf += "(" + c + ") & ";
    }
    dnf.erase(dnf.length() - 3);  // 移除最后的 "& "
    return dnf;
}

// 命题的主合取范式(CNF)
string GetCNF(const string& proposition) {
    // 分割命题公式中的子句
    vector<string> clauses;
    string clause = "";
    for (char ch : proposition) {
        if (ch == '&') {
            clauses.push_back(clause);
            clause = "";
        } else {
            clause += ch;
        }
    }
    clauses.push_back(clause);

    // 构建主合取范式
    string cnf = "";
    for (const string& c : clauses) {
        cnf += "(" + c + ") | ";
    }
    cnf.erase(cnf.length() - 3);  // 移除最后的 "| "
    return cnf;
}
int main() {
    while (true) {
        cout << "*****************************************************" << endl;
        cout << "***          +表示等价             ***" << endl;
        cout << "***          -表示蕴涵             ***" << endl;
        cout << "***          &表示合取             ***" << endl;
        cout << "***          |表示析取             ***" << endl;
        cout << "***          注:必须用#结束       ***" << endl;
        cout << "***          注:变元为小写字母    ***" << endl;
        cout << "***          输入1退出程序         ***" << endl;
        cout << "*****************************************************" << endl;
        cout << "请输入命题公式:";
        string expression;
        cin >> expression;
        if (expression == "1") {
            break;
        }
        //如果没有#
        if (expression.find('#') != expression.length() - 1)
        {
            cout << "请以#结束!" << endl;;
            system("pause");
            system("cls");
            continue;
        }
        PrintTable(expression);
        if(sum==1)cout<<"\n"<<"这个表达式是永真"<<endl;
		else if(sum==0) cout<<"\n"<<"这个表达式是永假"<<endl; 
		else cout<<"\n"<<"这个命题不是永真式也不是永假式"<<endl; 
		
		string category = CategorizeProposition(expression);
    	cout << "命题类型:" << category << endl;
		expression.pop_back();
    	string dnf = GetDNF(expression);
    	cout << "主析取范式(DNF):" << dnf << endl;

    	string cnf = GetCNF(expression);
    	cout << "主合取范式(CNF):" << cnf << endl;
    	
        system("pause");
        system("cls");
    }
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非黑皆白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值