南京邮电大学离散数学实验一(求主析取和主合取范式)

1、

(1)数据结构和存储结构:创建Stack类,模拟stack栈容器。将所输入的合式公式按照后缀表达式入栈。形成逆波兰表达式。根据数学公式计算得到结果。

(2)函数之间的调用关系和数据传递方式:如图所示

在这里插入图片描述

2

(1)C++核心算法的源代码(仅展示两个变元时的算法)

{
	if (var_cnt == 2) //二个变元  
	    {  
	        for (int i = 0; i < Suffix_Formula.length(); i++)  
	        {  
	            if (Suffix_Formula[i] == 'P' || Suffix_Formula[i] == 'Q') //当为变元时  
	            {  
	                v = Suffix_Formula[i] == 'P' ? p : q;  
	                Sim_stack.Push(v); //将v入栈  
	                continue; //  
	            }  
	            Not_Not(Suffix_Formula[i]); //当不是非运算时,选中两个字符参与运算  
	            Switch_Operator(Suffix_Formula[i]); //选择设置了优先级的运算符  
	        }  
	    }  
	  
	void Not_Not(char c)//功能:判断运算符是否为!,为什么呢?因为如果是!,我只需取一个元素  
	{                   //否则的话我必须取两个元素才能计算  
	    if (c != '!')  
	    {  
	        a = Sim_stack.Top();  
	        Sim_stack.Pop();  
	        b = Sim_stack.Top();  
	        Sim_stack.Pop();  
	    }  
	}  
	  
	void Switch_Operator(char c)  
	{  
	    switch (c)  
	    {  
	    case '~':Iif(); break;  
	    case '>':If(); break;  
	    case '|':Or(); break;  
	    case '&':And(); break;  
	    case '!':Not(); break;  
	    }38}
}

(2)时间复杂度:

由于本程序仅支持2-5个变元。若为n个变元,则其时间复杂度为O(n3)。

3

(1)测试

测试1:
输入  
[ P&!Q ]  
输出  
真值表如下  
P       Q       P&!Q  
1       1       0  
1       0       1  
0       1       0  
0       0       0  
主析取范式为:(P∧┐Q):  
主合取范式为:(┐P∨┐Q)(P∨┐Q)(P∨Q)  
测试2:
输入  
[ !P&Q<->R ]  
输出  
真值表如下  
P       Q       R       !P&Q<->R  
1       1       1       0  
1       1       0       1  
1       0       1       0  
1       0       0       1  
0       1       1       1  
0       1       0       0  
0       0       1       0  
0       0       0       1  
主析取范式为:(P∧Q∧┐R)(P∧┐Q∧┐R)(┐P∧Q∧R)(┐P∧┐Q∧┐R)  
主合取范式为:(┐P∨┐Q∨┐R)(┐P∨Q∨┐R)(P∨┐Q∨R)(P∨Q∨┐R)  
测试3:
输入  
[ (P->!Q)<->R|S ]  
输出  
真值表如下  

P       Q       R       S       (P->!Q)<->R|S  
1       1       1       1       0  
1       1       1       0       0  
1       1       0       1       0  
1       1       0       0       1  
1       0       1       1       1  
1       0       1       0       1  
1       0       0       1       1  
1       0       0       0       0  
0       1       1       1       1  
0       1       1       0       1  
0       1       0       1       1  
0       1       0       0       0  
0       0       1       1       1  
0       0       1       0       1  	
0       0       0       1       1  
0       0       0       0       0  
主析取范式为:(P∧Q∧┐R∧┐R)(P∧┐Q∧R∧R)(P∧┐Q∧R∧┐R)(P∧┐Q∧┐R∧R)(┐P∧Q∧R∧R)(┐P∧Q∧R∧┐R)(┐P∧Q∧┐R∧R)(┐P∧┐Q∧R∧R)(┐P∧┐Q∧R∧┐R)(┐P∧┐Q∧┐R∧R)  	  
主合取范式为:(┐P∨┐Q∨┐R∨┐R)(┐P∨┐Q∨┐R∨R)(┐P∨┐Q∨R∨┐R)(┐P∨Q∨R∨R)(P∨┐Q∨R∨R)(P∨Q∨R∨R)  

完整代码

#include <cstdio>
#include <cstring>
#include <windows.h>
#include <iostream>
using namespace std;

string Original_Formula;//用户输入的命题公式
string Simp_Formula;//将用户输入的命题公式中->和<->转化为>和~
string Suffix_Formula;//将简化后的式子转化为后缀表达式
string PCNF;//主合取范式
string PDNF;//主析取范式
char ch[15] = "()PQRST!&|-><";//把用户输入的式子简化时需要该语句

int p, q, r, s, t;//for循环打印真值表时使用
int a, b, res;//逻辑运算时使用,比如a==1, b==0传到了And()(合取函数)里,这时候res为0;
int v = 0;//还未写注释
int var_cnt;//计算用户输入的变量的个数(各不相同的变量的个数,重复的算一个)

//用一个类来模拟栈
class  Stack
{
public:
    Stack(int mSize)
    {
        maxtop = mSize - 1; //maxtop为st数组下标最大值,mSize为st数组元素个数
        st = new char[mSize];//动态内存分配
        top = -1;
    }
    ~Stack()//析构函数,释放st[]内存
    {
        delete[] st;
    }

    bool Push(char x)//模拟入栈
    {
        if (top == maxtop)//如果栈溢出,返回false
            return false;
        st[++top] = x;
        return true;
    }
    bool Pop()
    {
        if (top == -1)
            return false;
        top--;//模拟出栈
        return true;
    }
    char Top()
    {
        return st[top];//模拟取栈顶元素
    }
private:
    int top;
    char* st;
    int maxtop;
};

void Not();//非运算
void And();//合取运算
void Or();//析取运算
void If();//条件运算
void Iif();//双条件运算
void Menu();//打印菜单,增强用户体验
void count_varcnt(); //计算用户输入的变量的个数(各不相同的变量的个数,重复的算一个)
void InputANDjude_formula();// 用户输入的命题公式并进行检查,如果有异常输入,输出警告,并重新输入
bool Jude_canin(char);//判断运算符能否入栈
void Change_to_sufexp();//将处理后的命题公式转化为逆波兰表达式
void Calculate();//进行逻辑运算
void Print();//打印结果
void Not_Not(char);//忘记了,稍后补回来
void Switch_Operator(char);//运算符优先级,判断能否进栈
bool Enh_Robustness();//增强程序鲁棒性
Stack Sim_stack(200);//构造一个类对象,Sim_stack

int main()
{
    Menu();//输出菜单
    while (1)
    {
        do
        {
            InputANDjude_formula();//当检测到用户非法输入时,让用户再次输入
        } while (!Enh_Robustness());
        if (Original_Formula == "Over")//用户输入Over可结束程序
        {
            cout << "\\\\*^o^*// 谢谢使用 \\\\*^o^*//" << endl;
            system("pause");
            return 0;
        }

        count_varcnt();//计算出用户输入的变量的个数
        Change_to_sufexp();//将处理后的命题公式转化为逆波兰表达式
        Print();//打印
    }
    return 0;
}
/***********************************打印菜单*********************************************/
void Menu()
{
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    cout << "\t输入符号规定  " << endl;
    cout << "\t ┐:!       " << endl;
    cout << "\t∧:&        " << endl;
    cout << "\t∨:|        " << endl;
    cout << "\t→:->       " << endl;
    cout << "\t←→:<->    " << endl;
    cout << "-----------------------"<< endl;
    cout << endl;

    cout << "提醒:1.支持括号" << endl;
    cout << "     2.最多支持五个不同变元(P,Q,R,S,T),最少两个变元" << endl;
    cout << "     3.两个变元用P,Q;三个用P,Q,R:以此类推" << endl;
    cout << "\n" << endl;
}

/*************************输入并且进行简化************************************************/
void InputANDjude_formula()
{
    char str1[100] = { 0 }, str2[100]; //str1为输入式子,str2为处理后的式子,并将处理后的式子赋给Simp_Formula
    int cnt = 0;
    cout << "请输入命题公式:(输入Over可结束程序)" << endl;
    gets_s(str1); //疑惑:将str1, str2改为全局变量后程序出错   要用gets(),不然鲁棒性不强
    for (int i = 0; i < strlen(str1);)//将用户输入的命题公式中->和<->转换成>和<
    {
        if (str1[i] == '-') { str2[cnt++] = '>'; i += 2; }
        else if (str1[i] == '<') { str2[cnt++] = '~'; i += 3; }
        else { str2[cnt++] = str1[i]; i += 1; }
    }
    str2[cnt++] = '\0';//重要,给字符串加上结束标记符
    Original_Formula = str1;// 原始输入
    Simp_Formula = str2; // 仅含有非、和取、析取的公式
}

/*************************输入正确性检查**************************************************/
bool Enh_Robustness()
{
    bool Rob = true;
    if (Original_Formula == "Over")
        return true;
    for (int i = 0; i < Original_Formula.length(); i++)
    {
        if (strchr(ch, Original_Formula[i]) == nullptr)
        {
            cout << "输入异常,请检查是否有空格,小写抑或非法字符" << endl << endl;
            Original_Formula = "";
            return false;
        }
    }
    return Rob;
}

/********************************计算出用户输入的变量的个数*******************************/
void count_varcnt()
{
    int Count = 0;
    bool P = true, Q = true, R = true, S = true, T = true;
    for (int i = 0; i < Simp_Formula.length(); i++)
    {
        if (Simp_Formula[i] == 'P' && P) { Count++; P = !P; }
        else if (Simp_Formula[i] == 'Q' && Q) { Count++; Q = !Q; }
        else if (Simp_Formula[i] == 'R' && R) { Count++; R = !R; }
        else if (Simp_Formula[i] == 'S' && S) { Count++; S = !S; }
        else if (Simp_Formula[i] == 'T' && T) { Count++; T = !T; }
        else  continue;
    }
    var_cnt = Count;
}

/********************************优先级运算***********************************************/
bool Jude_canin(char out)//
{
    char in = Sim_stack.Top();
    int i, o;
    switch (in)
    {
    case '#':i = 0; break;
    case '(':i = 1; break;
    case '~':i = 3; break;
    case '>':i = 5; break;
    case '|':i = 7; break;
    case '&':i = 9; break;
    case '!':i = 11; break;
    case ')':i = 12; break;
    }
    switch (out)
    {
    //case '#':o = 0; break;
    case '(':o = 12; break;
    case '~':o = 2; break;
    case '>':o = 4; break;
    case '|':o = 6; break;
    case '&':o = 8; break;
    case '!':o = 10; break;
    case ')':o = 1; break;
    }
    if (i < o) { return true; }
    else { return false; }
}

/*******************************将处理后的命题公式转化为逆波兰表达式**********************/
void Change_to_sufexp()
{
    string Tmp = "";// 临时的空字符串
    Sim_stack.Push('#');
    for (int i = 0; i < Simp_Formula.length(); i++)
    {
        if (Simp_Formula[i] == 'P' || Simp_Formula[i] == 'Q' || Simp_Formula[i] == 'R' || Simp_Formula[i] == 'S')
        {
            Tmp = Tmp + Simp_Formula[i];
            continue;
        }
        if (Jude_canin(Simp_Formula[i]))
            Sim_stack.Push(Simp_Formula[i]);
        else if (Simp_Formula[i] == ')')
        {
            while (Sim_stack.Top() != '(')
            {
                Tmp = Tmp + Sim_stack.Top();
                Sim_stack.Pop();
            }
            Sim_stack.Pop();
        }
        else
        {
            do
            {
                Tmp = Tmp + Sim_stack.Top();
                Sim_stack.Pop();
            } while (!Jude_canin(Simp_Formula[i]));
            Sim_stack.Push(Simp_Formula[i]);
        }
    }
    while (Sim_stack.Top() != '#')
    {
        Tmp = Tmp + Sim_stack.Top();
        Sim_stack.Pop();
    }
    Sim_stack.Pop();
    Suffix_Formula = Tmp;
}

/*******************************进行运算**************************************************/
void Calculate()
{
    if (var_cnt == 2) //二个变元
    {
        for (int i = 0; i < Suffix_Formula.length(); i++)
        {
            if (Suffix_Formula[i] == 'P' || Suffix_Formula[i] == 'Q')
            {
                v = Suffix_Formula[i] == 'P' ? p : q;
                Sim_stack.Push(v);
                continue;
            }
            Not_Not(Suffix_Formula[i]);
            Switch_Operator(Suffix_Formula[i]);
        }
    }
    if (var_cnt == 3) //三个变元
    {
        for (int i = 0; i < Suffix_Formula.length(); i++)
        {
            if (Suffix_Formula[i] == 'P' || Suffix_Formula[i] == 'Q' || Suffix_Formula[i] == 'R')
            {
                v = Suffix_Formula[i] == 'P' ? p : Suffix_Formula[i] == 'Q' ? q : r;
                Sim_stack.Push(v);
                continue;
            }
            Not_Not(Suffix_Formula[i]);
            Switch_Operator(Suffix_Formula[i]);
        }
    }
    if (var_cnt == 4) //四个变元
    {
        for (int i = 0; i < Suffix_Formula.length(); i++)
        {

            if (Suffix_Formula[i] == 'P' || Suffix_Formula[i] == 'Q' || Suffix_Formula[i] == 'R' || Suffix_Formula[i] == 'S')
            {
                v = Suffix_Formula[i] == 'P' ? p : Suffix_Formula[i] == 'Q' ? q : Suffix_Formula[i] == 'R' ? r : s;
                Sim_stack.Push(v);
                continue;
            }
            Not_Not(Suffix_Formula[i]);
            Switch_Operator(Suffix_Formula[i]);
        }
    }
    if (var_cnt == 5) //五个变元
    {
        for (int i = 0; i < Suffix_Formula.length(); i++)
        {
            if (Suffix_Formula[i] == 'P' || Suffix_Formula[i] == 'Q' || Suffix_Formula[i] == 'R' || Suffix_Formula[i] == 'S' || Suffix_Formula[i] == 'T')
            {
                v = Suffix_Formula[i] == 'P' ? p : Suffix_Formula[i] == 'Q' ? q : Suffix_Formula[i] == 'R' ? r : Suffix_Formula[i] == 'S' ? s : t;
                Sim_stack.Push(v);
                continue;
            }
            Not_Not(Suffix_Formula[i]);
            Switch_Operator(Suffix_Formula[i]);
        }
    }
}

/********************************打印*****************************************************/
void Print()
{
    if (var_cnt == 2)
    {
        cout << "真值表如下" << endl;
        cout << "P\t" << "Q\t" << Original_Formula << endl;
        for (p = 1; p >= 0; p--)
        {
            for (q = 1; q >= 0; q--)
            {
                Calculate();
                if (res == 1)
                    PDNF = PDNF + "(" + (p == 1 ? "P" : "┐P") + "∧" + (q == 1 ? "Q" : "┐Q") + ")" + "∨";
                else
                    PCNF = PCNF + "(" + (p == 0 ? "P" : "┐P") + "∨" + (q == 0 ? "Q" : "┐Q") + ")" + "∧";
                cout << p << "\t" << q << "\t" << res << endl;
            }
        }
    }
    if (var_cnt == 3)
    {
        cout << "真值表如下" << endl;
        cout << "P\t" << "Q\t" << "R\t" << Original_Formula << endl;
        for (p = 1; p >= 0; p--)
        {
            for (q = 1; q >= 0; q--)
            {
                for (r = 1; r >= 0; r--)
                {
                    Calculate();
                    if (res == 1)
                        PDNF = PDNF + "(" + (p == 1 ? "P" : "┐P") + "∧" + (q == 1 ? "Q" : "┐Q") + "∧" + (r == 1 ? "R" : "┐R") + ")" + "∨";
                    else
                        PCNF = PCNF + "(" + (p == 0 ? "P" : "┐P") + "∨" + (q == 0 ? "Q" : "┐Q") + "∨" + (r == 0 ? "R" : "┐R") + ")" + "∧";
                    cout << p << "\t" << q << "\t" << r << "\t" << res << endl;
                }
            }
        }
    }
    if (var_cnt == 4)
    {
        cout << "真值表如下" << endl;
        cout << "P\t" << "Q\t" << "R\t" << "S\t" << Original_Formula << endl;
        for (p = 1; p >= 0; p--)
        {
            for (q = 1; q >= 0; q--)
            {
                for (r = 1; r >= 0; r--)
                {
                    for (s = 1; s >= 0; s--)
                    {
                        Calculate();
                        if (res == 1)
                            PDNF = PDNF + "(" + (p == 1 ? "P" : "┐P") + "∧" + (q == 1 ? "Q" : "┐Q") + "∧" + (r == 1 ? "R" : "┐R") + "∧" + (s == 1 ? "R" : "┐R") + ")" + "∨";
                        else
                            PCNF = PCNF + "(" + (p == 0 ? "P" : "┐P") + "∨" + (q == 0 ? "Q" : "┐Q") + "∨" + (r == 0 ? "R" : "┐R") + "∨" + (s == 0 ? "R" : "┐R") + ")" + "∧";
                        cout << p << "\t" << q << "\t" << r << "\t" << s << "\t" << res << endl;
                    }
                }
            }
        }
    }
    if (var_cnt == 5)
    {
        cout << "真值表如下" << endl;
        cout << "P\t" << "Q\t" << "R\t" << "S\t" << "T\t" << Original_Formula << endl;
        for (p = 1; p >= 0; p--)
        {
            for (q = 1; q >= 0; q--)
            {
                for (r = 1; r >= 0; r--)
                {
                    for (s = 1; s >= 0; s--)
                    {
                        for (t = 1; t >= 0; t--)
                        {
                            Calculate();
                            if (res == 1)
                                PDNF = PDNF + "(" + (p == 1 ? "P" : "┐P") + "∧" + (q == 1 ? "Q" : "┐Q") + "∧" + (r == 1 ? "R" : "┐R") + "∧" + (s == 1 ? "R" : "┐R") + ")" + "∨";
                            else
                                PCNF = PCNF + "(" + (p == 0 ? "P" : "┐P") + "∨" + (q == 0 ? "Q" : "┐Q") + "∨" + (r == 0 ? "R" : "┐R") + "∨" + (s == 0 ? "R" : "┐R") + ")" + "∧";
                            cout << p << "\t" << q << "\t" << r << "\t" << s << "\t" << t << "\t" << res << endl;
                        }
                    }
                }
            }
        }
    }

    if (PDNF.length() == 0) 
    { 
        cout << "主析取范式不存在" << endl; 
    }
    else
    {
        PDNF.erase(PDNF.length() - 2);
        cout << "主析取范式为:" << PDNF << endl << endl;
    }
    if (PCNF.length() == 0)
        cout << "主合取范式不存在" << endl;
    else
    {
        PCNF.erase(PCNF.length() - 2);
        cout << "主合取范式为:" << PCNF << endl << endl;
    }
    PDNF = "";
    PCNF = "";
}

void Not_Not(char c)//功能:判断运算符是否为!,为什么呢?因为如果是!,我只需取一个元素
{                   //否则的话我必须取两个元素才能计算
    if (c != '!')
    {
        a = Sim_stack.Top();
        Sim_stack.Pop();
        b = Sim_stack.Top();
        Sim_stack.Pop();
    }
}

//选择要计算的运算符
void Switch_Operator(char c)
{
    switch (c)
    {
    case '~':Iif(); break;
    case '>':If(); break;
    case '|':Or(); break;
    case '&':And(); break;
    case '!':Not(); break;
    }
}

//进行!运算
void Not()
{
    a = Sim_stack.Top();
    Sim_stack.Pop();
    res = (a == 1 ? 0 : 1);   //一定要注意是等于号
    Sim_stack.Push(res);
}

//进行合取运算
void And()
{
    res = a * b;
    Sim_stack.Push(res);
}

//进行析取运算
void Or()
{
    res = (a + b == 0) ? 0 : 1;
    Sim_stack.Push(res);
}

//进行条件运算
void If()
{
    res = (b == 1 && a == 0) ? 0 : 1;
    Sim_stack.Push(res);
}

//进行双条件运算
void Iif()
{
    res = (a == b ? 1 : 0);
    Sim_stack.Push(res);
}
  • 17
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

亦是远方

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

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

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

打赏作者

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

抵扣说明:

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

余额充值