简单命题公式的实现,判断是否合法

  在学校懵懵懂懂的学了有将近半年多的时间了,誓为成为石进老师那样的人而努力着。

  原来“+”是双条件!!好了,现在所有逻辑运算符都支持了,另外还编写了判断用户输入的命题公式是否合法的函数。

  离散数学居然有上机题!不过题目大多基于数据结构的知识,这正好检验一下自己对相关知识的掌握情况。

  这周的上机题目是“命题公式”:形如q->p(q蕴含于p)在不同赋值情况下的真假性。

  先分析一下思路,总体上讲,在我能力范围内的表达式求值方法通常是利用栈来实现(在此之外还有二叉树),命题公式的求值同样如此,因为有不同的赋值情况,所以我们要利用一个数组通过下标识别的方法来进行赋值。

  系统一下:1.键入命题公式;2.扫描命题公式,得到其中的命题变元;3.计算该命题公式在不同的赋值情况下的结果。

  涉及到的主要函数有:1.比较逻辑运算符的优先级;2.将表达式中的所有命题变元插入到全局数组;3.查找命题变元在全局数组中的位置(便于进行赋值);4.对赋值数组每次进行二进制加一(每一个命题变元均对应两种赋值即0或1)。5.判断用户输入的命题公式是否合法。

  其中对于命题公式是否合法,有如下条件限制:

  1.命题公式必须由字母(代表命题变元)、运算符和括号组成;

  2.不允许右括号后接字母;

  3.不允许运算符后接运算符或右括号;

  4.不允许左括号后接运算符(!除外);

  5.不允许左括号前有字母或右括号;

  6.命题公式的开头必须是:字母、!、左括号这三者其一;

  7.命题公式结尾必须是字母或者有括号;

  8.左右括号必须匹配。


下面上源码:

// 离散数学-命题公式.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include
#include
#include
#include
#include
#include
using namespace std;

int number;
char *tmp;
int j = 0;
const int length = 6;//命题变元的最大长度
char varist[length];
string expression;
bool* v;

bool first(string a);//命题公式必须由字母、运算符和括号组成
bool second(string a);//不允许右括号后接字母
bool third(string a);//不允许运算符后面接运算符或右括号
bool fourth(string a);//不允许左括号后接运算符(!除外)
bool fifth(string a);//不允许左括号前有字母或右括号
bool sixth(string a);//命题公式开头必须是:字母、!、左括号这三者其一
bool seventh(string a);//命题公式结尾必须是字母或者右括号
bool eighth(string a);//左右括号匹配

int compare(char op1, char op2);//运算符优先级的比较
void createvarlist(string s);//将表达式中的所有命题变元插入到全局数组
bool calculate(string s, bool* varValue);//求命题公式在一组赋值(存放在bool数组中)下的真值取值情况,并将其真值返回
void increase(bool* v);//将数组v中的当前赋值取值+1
int seek(char p);//查找指定变元在变元数组中的存放位置,并返回其下标
bool count(bool op1, bool op2, char op);//计算op1与op2做op运算符的运算,并把结果返回.

int main()
{
    cout << "请输入命题公式,并以'#'号结束" << endl;
    getline(cin, expression);//而不是getline(cin,expression,'#')
    cout << "表达式为:" << expression << endl;
    createvarlist(expression);

    if (first(expression) && second(expression) && third(expression) && fourth(expression) && fifth(expression) && sixth(expression) && seventh(expression) && eighth(expression))
    {
        v = new bool[number];//赋值数组初始化
        for (int i = 0; i < number; i++)
            v[i] = false;

        for (int i = 0; i < number; i++)//真值表的表头输出
            cout << setw(3) << varist[i];
        cout << "     " << expression << endl;

        for (int i = 0; i < pow(2, number); i++)//每一种赋值情况
        {
            for (int j = 0; j < number; j++)
                cout << setw(3) << v[j];
            cout << "        " << calculate(expression, v);//未带有#(则引起报错)
            increase(v);
            cout << endl;
        }
    }
    else
        cout << "命题公式不合法" << endl;
    system("pause");
    return 0;
}

bool first(string a)
{
    for (int i = 0; i < a.length() - 1; i++)
    {
        if (strchr("+-|&!()", a[i]) || (a[i] >= 'A'&&a[i] <= 'z'))
            continue;
        else
            return false;
    }
    return true;
}
bool second(string a)
{
    for (int i = 0; i <= a.length() - 1; i++)
    {
        if (a[i] == ')')
        {
            if (a[i + 1] >= 'A'&&a[i + 1] <= 'z')//A的ASCII码:65,z的ASCII码:122
            {
                return false;
            }
            else
                continue;
        }
        else
            continue;
    }
    return true;
}
bool third(string a)
{
    for (int i = 0; i < a.length() - 1; i++)
    {
        if (strchr("+-|&!", a[i]))
        {
            if (strchr("+-|&!", a[i + 1]) || a[i + 1] == ')')
                return false;
            else
                continue;
        }
        else
            continue;
    }
    return true;
}
bool fourth(string a)
{
    for (int i = 0; i < a.length() - 1; i++)
    {
        if (a[i] == '(')
        {
            if (strchr("+-|&", a[i + 1]))
                return false;
            else
                continue;
        }
        else
            continue;
    }
    return true;
}
bool fifth(string a)
{
    for (int i = 0; i < a.length() - 1; i++)
    {
        if (a[i] == '('&&i >= 1)
        {
            if (a[i - 1] == ')' || (a[i - 1] >= 'A'&&a[i - 1] <= 'z'))
                return false;
            else
                continue;
        }
        else
            continue;
    }
    return true;
}
bool sixth(string a)
{
    if (a[0] == '!' || (a[0] >= 'A'&&a[0] <= 'z') || a[0] == '(')
        return true;
    else
        return false;
}
bool seventh(string a)
{
    if ((a[a.length() - 2] >= 'A'&&a[a.length() - 2] <= 'z') || a[a.length() - 2] == ')')
        return true;
    else
        return false;
}
bool eighth(string a)
{
    int b = 0;
    char *tmp = new char[a.length() - number - 1];//存放括号
    for (int i = 0, j = 0; i < a.length() - 1; i++)
    {
        if (strchr("()", a[i]))
        {
            tmp[j] = a[i];
            j++;
        }
        else
            continue;
    }
    for (int x = 0; x < (a.length() - 1 - number); ++x)
    {
        switch (tmp[x])
        {
        case '(':
            ++b;
            break;
        case ')':
            ++b;
            break;
        }
    }
    if (b % 2 == 0)
        return true;
    else
        return false;
}


int compare(char op1, char op2)//比较两运算符的优先级
{
    if (op2 == '#' || (op1 == '-'&&op2 == ')') || (op1 == '+'&&op2 == ')'))//特别声明出来的,判断条件的缺失
        return 1;
    if (op1 == '('&&op2 == ')' || op1 == '#'&&op2 == '#')
        return 0;// 优先级相同
    else if (op1 == '#' || op1 == '(' || op2 == '(' || op2 == '!' || op1 == '-' || (op1 == '|' && op2 == '&')/* || (op1 == '|' &&op2 == '!') || (op1 == '&'&&op2 == '!')*/)
        return -1;//op1的优先级低于op2(入栈)
    else
        return 1;//op1的优先级高于op2(计算)
}
void createvarlist(string s)//命题变元的提取
{
    char ch;
    for (unsigned int i = 0; i < s.size() && (ch = s[i]) != '#'; i++)//扫描命题公式中所有字符
        if (!strchr("+-|&!()#", ch))        //若ch不是运算符,则为命题变元
        {
            int j;
            for (j = number - 1; j >= 0 && varist[j] > ch; j--)//在变元表varList数组中查找ch的插入位置,使之保持有序
                varist[j + 1] = varist[j];
            if (varist[j] < ch)       //若varList[j]==ch,则表示该变元已经存放在varList数组中,无需再次插入
            {
                varist[j + 1] = ch;
                number++;
            }
        }
}
int seek(char p)
{
    int loc;
    for (loc = 0; varist[loc] != p&&loc < number; loc++);
    return loc;
}
void increase(bool* v)
{
    for (int i = number - 1; i >= 0; i--)
    {
        if (v[i] + 1 == 1)//最后位为0
        {
            v[i] = 1;
            break;
        }
        if (v[i] + 1 == 2)//最后位为1
        {
            v[i] = 0;
            continue;
        }
    }
}


bool count(bool op1, bool op2, char op)
{
    switch (op)
    {
    case '&':
        if (op1 == 1 && op2 == 1)
            return true;
        else
            return false;
    case '|':
        if (op1 == 0 && op2 == 0)
            return false;
        else
            return true;
    case '-':
        if (op1 == 0 && op2 == 1)//考虑到命题变元的出栈顺序是相反的
            return false;
        else
            return true;
    case '+'://双条件
        if (op1 != op2)
            return false;
        else
            return true;
    }
}

bool calculate(string s, bool* value)
{
    stack optr;  //定义运算符栈
    stack opnd;  //定义操作数栈

    char op, ch = '#';
    int i = 0;
    bool a, b;
    optr.push(ch);
    while ((ch = s[i]) != '#' || optr.top() != '#')
    {
        if (!strchr("+-|&!()#", ch))//是变元(即为操作数),则取变元的当前赋值压入堆栈中
        {
            opnd.push(value[seek(ch)]);
            ++i;
        }
        else
        {
            op = optr.top();
            switch (compare(op, ch))
            {
            case 0:
                optr.pop();
                i++;
                break;
            case -1:
                optr.push(ch);
                i++;
                break;
            case 1:
                if (optr.top() == '!')
                {
                    opnd.top() = !opnd.top();
                    optr.pop();
                    break;
                }
                else
                {
                    a = opnd.top();
                    opnd.pop();
                    b = opnd.top();
                    opnd.pop();
                    opnd.push(count(a, b, optr.top()));
                    optr.pop();
                    break;
                }

            }
        }
    }
    if (!optr.empty() && optr.top() != '#')//清空optr栈,以进行下一循环
    {
        optr.pop();
    }
    return opnd.top();
}

  使用了STL中的Stack(懒),当然也可以自己写。在这些函数中,我自鸣得意的(汗)的一个是二进制加一的increase函数,说到底是运用了continue和break;

  其中‘|’是析取,‘&’是合取,‘!’是非,‘-’是蕴含连接词,‘+’是双条件。

  在该程序中,非常容易出现错误的一个函数是比较运算符优先级这个函数。

  结果展示一下:

简单命题公式的实现,判断是否合法_第1张图片 简单命题公式的实现,判断是否合法_第2张图片

你可能感兴趣的:(离散数学)