zoukankan      html  css  js  c++  java
  • c++实现真值表

    首先感谢下面两位博主的帖子!

    我直接搬过来用了,根据这个我改写了c++输出真值表的代码,再次感谢!

    后缀表达式求值点击打开链接

    参考资料1:

    1 后缀表达式的求值
    将中缀表达式转换成等价的后缀表达式后,求值时,不需要再考虑运算符的优先级,只需从左到右扫描一遍后缀表达式即可。具体求值步骤为:从左到右扫描后缀表 达式,遇到运算符就把表达式中该运算符前面两个操作数取出并运算,然后把结果带回后缀表达式;继续扫描直到后缀表达式最后一个表达式。 
    例如,后缀表达式(abc*+def*/-) 的求值

    2 后缀表达式的求值的算法
    设置一个栈,开始时,栈为空,然后从左到右扫描后缀表达式,若遇操作数,则进栈;若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的 放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。此时,栈中仅有一个元素,即为运算的结果。
    例,求后缀表达式:1 2 + 8 2 - 7 4 - / * 的值, 
    栈的变化情如下:

    步骤

    栈中元素

    说明

    1

    1

    1 进栈

    2

    12

    2 进栈

    3

     

    遇+ 号退栈2 和1

    4

    3

    1+2=3 的结果3 进栈

    5

    38

    8 进栈

    6

    382

    2 进栈

    7

    3

    遇- 号退栈2 和8

    8

    36

    8-2=6 的结果6 进栈

    9

    367

    7 进栈

    10

    3674

    4 进栈

    11

    36

    遇- 号退栈4 和7

    12

    36

    7-4=3 的结果3 进栈

    13

    3

    遇/ 号退栈3 和6

    14

    32

    6/3=2 的结果2 进栈

    15

     

    遇* 号退栈2 和3

    16

    6

    3*2=6 进栈

    17

    6

    扫描完毕,运算结束

    从上可知,最后求得的后缀表达式之值为6 ,与用中缀表达式求得的结果一致,但后缀式求值要简单得多。
    五、中缀表达式变成等价的后缀表达式的算法
    将中缀表达式变成等价的后缀表达式,表达式中操作数次序不变,运算符次序发生变化,同时去掉了圆括号。转换规则是:设立一个栈,存放运算符,首先栈为空, 编译程序从左到右扫描中缀表达式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;若遇到运算符,则必须与栈顶比较,运算符级别比栈顶级 别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。当栈变成空时, 输出的结果即为后缀表达式。将中缀表达式(1+2)*((8-2)/(7-4)) 变成等价的后缀表达式。
    现在用栈来实现该运算,栈的变化及输出结果如下:

    步骤

    栈中元素

    输出结果

    说明

    1

    (

     

    ( 进栈

    2

    (

    1

    输出1

    3

    (+

    1

    + 进栈

    4

    (+

    1 2

    输出2

    5

     

    1 2 +

    + 退栈输出,退栈到( 止

    6

    *

    1 2 +

    * 进栈

    7

    *(

    1 2 +

    ( 进栈

    8

    *((

    1 2 +

    ( 进栈

    9

    *((

    1 2 + 8

    输出8

    10

    *((-

    1 2 + 8

    输出2

    11

    *((-

    1 2 + 8 2

    - 进栈

    12

    *(

    1 2 + 8 2 -

    - 退栈输出,退栈到( 止

    13

    *(/

    1 2 + 8 2 -

    / 进栈

    14

    *(/(

    1 2 + 8 2 -

    ( 进栈

    15

    *(/(

    1 2 + 8 2 - 7

    输出7

    16

    *(/(-

    1 2 + 8 2 - 7

    - 进栈

    17

    *(/(-

    1 2 + 8 2 - 7 4

    输出4

    18

    *(-

    1 2 + 8 2 - 7 4 -

    - 退栈输出,退栈到( 止

    19

    *

    1 2 + 8 2 - 7 4 - /

    / 退栈输出,退栈到( 止

    20

     

    1 2 + 8 2 - 7 4 - / *

    * 退栈并输出



    图解后缀表达式的计算过程

    点击打开链接

    参考资料2:

    为了解释后缀表达式的好处,我们先来看看,计算机如何应用后缀表达式计算出最终的结果20的。

    后缀表达式:9 3 1-3*+ 10 2/+

    • 规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。

    下面是详细的步骤:

    1. 初始化一个空。此桟用来对要运算的数字进出使用。

    2. 后缀表达式中前三个都是数字,所以9、3、1进栈。

    3. 接下来是减号“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再将2进栈。

    4. 接着是数字3进栈。

    5. 后面是乘法“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。

    6. 下面是加法“+”,所以找中6和9出找,9与6相加,得到15,将15进栈。

    7. 接着是10与2两数字进栈。

    8. 接下来是符号因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈。

    9. 最后一个是符号“+”,所以15与5出找并相加,得到20,将20进栈。

    10. 结果是20出栈,栈变为空。

    • 果然,后缀表达法可以很顺利解决计算的问题。但是我有个疑问,就是这个后缀表达式“9 3 1-3*+ 10 2/+”是如何通过算式“9+(3-1)*3+10/2”变化而来呢?

    #include <iostream>
    #include <string>
    #include<string.h>
    #include <stack>
    #include<cstdio>
    using namespace std;
    //用二维数组为真值表赋值
    int  table2[4][2]= {{0,0},{0,1},{1,0},{1,1}};
    int  table3[8][3]= {{0,0,0},{0,0,1},{0,1,0},{1,0,0},
        {0,1,1},{1,0,1},{1,1,0},{1,1,1}
    };
    int table4[16][4]= {{0,0,0,0},{0,0,0,1},{0,0,1,0},{0,1,0,0},
        {1,0,0,0},{0,0,1,1},{0,1,0,1},{1,0,0,1},
        {0,1,1,0},{1,0,1,0},{1,1,0,0},{0,1,1,1},
        {1,1,0,1},{1,0,1,1},{1,1,1,0},{1,1,1,1}
    };
    //*"合取",+"析取",!"",>"条件",<"双条件"
    int prior(char ch)//确定优先级
    {
        switch(ch)
        {
        case '!':
            return 5;
        case '+':
            return 3;
        case '*':
            return 4;
        case '>':
            return 2;
        case '<':
            return 1;
        default:
            return 0;
        }
    }
    bool isOperator(char ch)//判断是否为运算操作符
    {
        switch(ch)
        {
        case '!':
        case '+':
        case '*':
        case '>':
        case '<':
            return true;
        default :
            return false;
        }
    }
    stack<char>s1;
    stack<int>s2;
    string getPostfix(string &infix)//中缀表达式转后缀表达式
    {
        string postfix;
        while(!s1.empty())s1.pop();
        int i,j,k;
        char tmp;
        for(i=0; i<infix.size(); i++)
        {
            tmp=infix[i];
            if(isOperator(tmp))
            {
                while(!s1.empty()&&isOperator(s1.top())&&prior(s1.top())>=prior(tmp))
                {
                    postfix.push_back(s1.top());
                    s1.pop();
                }
                s1.push(tmp);
            }
            else if(tmp=='(')
            {
                s1.push(tmp);




            }
            else if(tmp==')')
            {
                while(s1.top()!='(')
                {
                    postfix.push_back(s1.top());
                    s1.pop();
                }
                s1.pop();
            }
            else if(tmp>='A'&&tmp<='Z')postfix.push_back(tmp);
            else
            {
                printf("请输入合法的表达式 ");
                break;
            }
        }
        while (!s1.empty())
        {
            postfix.push_back(s1.top());
            s1.pop();
        }
        return postfix;
    }
    int Calculate(const string& postfix)//计算后缀表达式
    {
        int  left,right;
        int  flag;
        while(!s2.empty())s2.pop();
        for(int i=0; i<postfix.size(); ++i)
        {
            char c = postfix[i];
            switch (c)
            {
            case '+':
                right=s2.top();
                s2.pop();
                left=s2.top();
                s2.pop();
                if(left==0&&right==0)flag=0;
                else flag=1;
                s2.push(flag);
                break;
            case '*':
                right=s2.top();
                s2.pop();
                left=s2.top();
                s2.pop();
                if(left==1&&right==1)flag=1;
                else flag=0;
                s2.push(flag);
                break;
            case '>':
                right=s2.top();
                s2.pop();
                left=s2.top();
                s2.pop();
                if(left==1&&right==0)flag=0;
                else flag=1;
                s2.push(flag);
                break;
            case '<':
                right=s2.top();
                s2.pop();
                left=s2.top();
                s2.pop();
                if(left==right)flag=1;
                else flag=0;
                s2.push(flag);
                break;
            case '!':
                flag=s2.top();
                s2.pop();
                if(flag==0)flag=1;
                else flag=0;
                s2.push(flag);
                break;
            default:
                s2.push(c-'0');
                break;
            }
        }
        int result = s2.top();
        s2.pop();
        return result;
    }
    int Print(string &tmp,char name[],int n)//真值表输出
    {
        //tmp是中缀式,tmp2是后缀式,n是变量的个数
        string tmp2;
        tmp2=getPostfix(tmp);
        int i,j,k,m;
        m=tmp2.size();//m保存后缀式的长度
        if(n==1)
        {
            printf("%5c",name[0]);
            printf("    ");
            cout<<tmp<<endl;//输出中缀式
            for(j=0; j<2; j++)
            {
                string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
                printf("%5d",j);
                i=0;
                while(i<m)
                {
                    if(tmp1[i]==name[0])tmp1[i]=j+'0';
                    i++;
                }
                printf("%5d ",Calculate(tmp1));
            }
        }
        else if(n==2)
        {
            for(i=0; i<2; i++)printf("%5c",name[i]);
            printf("    ");
            cout<<tmp<<endl;//输出中缀式
            for(j=0; j<4; j++)
            {
                string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
                for(k=0; k<2; k++)printf("%5d",table2[j][k]);
                i=0;
                while(i<m)
                {
                    if(tmp1[i]==name[0])tmp1[i]=table2[j][0]+'0';
                    else if(tmp1[i]==name[1])tmp1[i]=table2[j][1]+'0';
                    i++;
                }
                printf("%5d ",Calculate(tmp1));
            }
        }
        else if(n==3)
        {
            for(i=0; i<3; i++)printf("%5c",name[i]);
            printf("    ");
            cout<<tmp<<endl;//输出中缀式
            for(j=0; j<8; j++)
            {
                string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
                for(k=0; k<3; k++)printf("%5d",table3[j][k]);
                i=0;
                while(i<m)
                {
                    if(tmp1[i]==name[0])tmp1[i]=table3[j][0]+'0';
                    else if(tmp1[i]==name[1])tmp1[i]=table3[j][1]+'0';
                    else if(tmp1[i]==name[2])tmp1[i]=table3[j][2]+'0';
                    i++;
                }
                printf("%5d ",Calculate(tmp1));
            }
        }
        else if(n==4)
        {
            for(i=0; i<4; i++)printf("%5c",name[i]);
            printf("    ");
            cout<<tmp<<endl;//输出中缀式
            for(j=0; j<16; j++)
            {
                string tmp1=tmp2;//将后缀式赋给临时字符串,用于计算
                for(k=0; k<4; k++)printf("%5d",table4[j][k]);
                i=0;
                while(i<m)
                {
                    if(tmp1[i]==name[0])tmp1[i]=table4[j][0]+'0';
                    else if(tmp1[i]==name[1])tmp1[i]=table4[j][1]+'0';
                    else if(tmp1[i]==name[2])tmp1[i]=table4[j][2]+'0';
                    else if(tmp1[i]==name[3])tmp1[i]=table4[j][3]+'0';
                    i++;
                }
                printf("%5d ",Calculate(tmp1));
            }
        }
    }
    bool judge(char name[])//判断变量名是否合法
    {
        int i,n=strlen(name);
        if(n>=5)return false;
        for(i=0; i<n; i++)if(name[i]<'A'||name[i]>'Z')return false;
        return true;
    }


    int main()
    {
        int i,n;
        char variablename[10];
        printf("------------------------------------------------ ");
        printf("         欢迎使用真值表计算程序!!! ");
        printf("------------------------------------------------ ");


        while(1)
        {
            printf("请您输入变量名(温馨提示:变量名均为大写字母,变量名之间不能有空格,可输入Esc退出本程序) ");
            scanf("%s",variablename);//输入变量名
            if(strcmp(variablename,"Esc")==0)break;
            n=strlen(variablename);
            if(!judge(variablename))//判断变量名输入是否合法
            {
                printf("表达式不合法或者变元超过四个,请重新输入 ");
                continue;
            }
            string postfixtmp;
            printf("请您输入合法表达式(*表示合取,+表示析取,!表示非,>表示条件,<表示双条件) ");
            cin>>postfixtmp;
            Print(postfixtmp,variablename,n);//输出真值表
        }
        return 0;
    }



    参考代码:

    #include <iostream>
    #include <string>
    #include <stack>
    using namespace std;


    int prior(char c)
    {
        switch (c)
        {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        default:
            return 0;
        }
    }


    bool isOperator(char c)
    {
        switch (c)
        {
        case '+':
        case '-':
        case '*':
        case '/':
            return true;
        default:
            return false;
        }
    }


    string getPostfix(const string& expr)
    {
        string output;  // 输出
        stack<char> s;  // 操作符栈
        for(int i=0; i<expr.size(); ++i)
        {
            char c = expr[i];
            if(isOperator(c))
            {
                while(!s.empty() && isOperator(s.top()) && prior(s.top())>=prior(c))
                {
                    output.push_back(s.top());
                    s.pop();
                }
                s.push(c);
            }
            else if(c == '(')
            {
                s.push(c);
            }
            else if(c == ')')
            {
                while(s.top() != '(')
                {
                    output.push_back(s.top());
                    s.pop();
                }
                s.pop();
            }
            else
            {
                output.push_back(c);
            }
        }
        while (!s.empty())
        {
            output.push_back(s.top());
            s.pop();
        }
        return output;
    }


    // 从栈中连续弹出两个操作数
    void popTwoNumbers(stack<int>& s, int& first, int& second)
    {
        first = s.top();
        s.pop();
        second = s.top();
        s.pop();
    }


    // 计算后缀表达式的值


    int Calculate(string& postfix)
    {
        int first,second;
        stack<int>s;
        for(int i=0; i<postfix.size(); ++i)
        {
            char c = postfix[i];
            switch (c)
            {
            case '+':
                popTwoNumbers(s, first, second);
                s.push(second+first);
                break;
            case '-':
                popTwoNumbers(s, first, second);
                s.push(second-first);
                break;
            case '*':
                popTwoNumbers(s, first, second);
                s.push(second*first);
                break;
            case '/':
                popTwoNumbers(s, first, second);
                s.push(second/first);
                break;
            default:
                s.push(c-'0');
                break;
            }
        }
        int result = s.top();
        s.pop();
        return result;
    }


    int main()
    {
       string expr = "5+2*(6-3)-4/2";
        string postfix =getPostfix(expr);
        int result = Calculate(postfix);
        cout << "The result is: " << result << endl;
        return 0;
    }




  • 相关阅读:
    2021.4.2 Python基础及介绍
    2021.4.1 团队组队
    冲击信号
    信号卷积(线性卷积)
    数字图像处理基本概念
    计算机视觉发展及主要研究方向
    SVM 之 SMO 算法
    FP Growth 算法
    Apriori 算法
    26 实战页式内存管理 下
  • 原文地址:https://www.cnblogs.com/hjch0708/p/7554848.html
Copyright © 2011-2022 走看看