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("请输入合法的表达式\n");
            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\n",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\n",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\n",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\n",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("------------------------------------------------\n");
    printf("         欢迎使用真值表计算程序!!!\n");
    printf("------------------------------------------------\n");


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




  • 17
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值