目的:读入一个逻辑表达式,包含多个变量及各种逻辑运算,输出该逻辑表达式的真值表;
思路:
1.与计算多项式的思路一致,利用双栈存储从左到右遍历;
栈具有LIFO的特点,利用栈可以储存离当前操作符最近的符号与数据,从左到右遍历,直到最终得出表达式的值;
2.两个栈一个存储符号,一个存储数据,设置栈内栈外符号位的优先级;
相同符号栈内优先级大于栈外优先级;
左括号栈内优先级最高,栈外优先级紧大于‘#’;
右括号与左括号相反;
将‘#’优先级设为最低,放入栈底,方便比较并判断终止条件;
3.每次读入一位,若为数据入数据栈;若为操作符,进行优先级比较
当栈内运算符优先级大于栈外运算符优先级,执行运算;
当栈内运算符优先级等于栈外运算符优先级,必为左右括号,弹出左括号;
当栈内运算符优先级小于栈外运算符优先级,将该符号入栈;
代码实现:
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
#include <stack>
#include <map>
#include <cmath>
using namespace std;
int num[10];//按位存储生成的二进制码
int letter_num;//全局变量存储表达式中变量数目
map<char,int> m;//用map将字符与数字绑定,方便对应
char letter[10];//储存所有字符变量
char relation[256];//储存关系表达式
int show[100];//记录变量是否出现
int in[]={3,3,3,3,4,1,5,0};//栈内优先级
int out[]={2,2,2,2,4,5,1,0};//栈外优先级
char symbol[]={'^','V','>','<','~','(',')','#'};//储存操作符
int get(char x);//返回操作符对应下标
void get_num(int x);//更新按位二进制表示
int get_letter_num(char *);//统计并储存变量
char com(char x1,char x2);//比较优先级
bool if_variable(char x);//判断当前字符是否为变量
void print_truth_table(char *);//打印真值表
int figure(int x1,int rel,int x2);//计算基本表达式值
int main()
{
cin>>relation;
print_truth_table(relation);
return 0;
}
void print_truth_table(char* top)
{
int sum;
char* y;
int x,x1,x2;
char rel;
stack<int> data;//存储数据
stack<int> ope;//存储操作符
/*初始化*/
memset(show,0,sizeof(show));
memset(letter,0,sizeof(letter));
memset(num,0,sizeof(num));
ope.push(get('#'));
y=top;
x=get_letter_num(top);
x=(int)pow(2,x);//对应于2^x数的真值表
/*打印表头*/
for(int i=0;i<=letter_num;i++)
{
if(i==letter_num)
{
printf("%-10s\n",relation);
for(int j=0;j<=letter_num;j++)
cout<<"----------";
cout<<endl;
continue;
}
printf("%-10c",letter[i]);
}
while(x--)
{
top=y;//保存头指针,每次遍历完需重置
get_num(x);//更新二进制表示
int index=ope.top();
while(*top||index!=7)
{
sum=0;
if(*top=='-')
top++;
if(*top=='~')//取非将4压入操作栈
{
ope.push(4);
top++;
}
if(*top=='<')//若为等价符另右移两位
{
ope.push(get(*top));
top+=3;
}
if(if_variable(*top))//压入变量值
{
sum=m[*top];
data.push(sum);
top++;
}
else//符号操作
{
switch(com(symbol[ope.top()], *top))
{
case 1://'>'
if(ope.top()==4)//取反单独计算
{
x1=data.top();
data.pop();
x1=(x1+1)%2;
data.push(x1);
ope.pop();
break;
}
x1=data.top();
data.pop();
x2=data.top();
data.pop();
rel=ope.top();
ope.pop();
data.push(figure(x1,rel,x2));
break;
case 2://'<'
ope.push(get(*top));
if(*top)
top++;
break;
case 3://'='
ope.pop();
if(*top)
top++;
break;
}
}
index=ope.top();
}
/*打印结果*/
for(int i=0;i<=letter_num;i++)
{
if(i==letter_num)
{
printf("%d\n",data.top());
data.pop();
continue;
}
printf("%-10d",num[i]);
}
}
return ;
}
void get_num(int x)
{
for(int i=letter_num-1;i>=0;i--)
{
num[i]=x%2;
m.erase(letter[i]);
m.insert(make_pair(letter[i],num[i]));
x/=2;
}
return ;
}
int get(char x)
{
switch(x)
{
case '^':
return 0;
case 'V':
return 1;
case '>':
return 2;
case '<':
return 3;
case '~':
return 4;
case '(':
return 5;
case ')':
return 6;
case '#':
return 7;
default:
return 7;
}
}
int get_letter_num(char *x)
{
letter_num=0;
while(*x)
{
switch(*x)
{
case '^':
case 'V':
case '>':
case '<':
case '(':
case ')':
case '#':
case '-':
case '~':
x++;
break;
default:
if(!show[(int)*x])
{
letter[letter_num]=*x;
letter_num++;
show[(int)*x]=1;
}
x++;
break;
}
}
return letter_num;
}
char com(char x1,char x2)
{
int i1=get(x1);
int i2=get(x2);
if(in[i1] > out[i2])
return 1;
else if(in[i1] < out[i2])
return 2;
else
return 3;
}
bool if_variable(char x)
{
switch(x)
{
case '^':
case 'V':
case '>':
case '<':
case '(':
case ')':
case '#':
case '\0':
return false;
default:
return true;
}
}
int figure(int x1,int rel,int x2)
{
switch(rel)
{
case 0:
return x1&&x2;//与
case 1:
return x1||x2;//或
case 2:
return x1||!x2;//蕴含
case 3:
return (!x1&&!x2)||(x1&&x2);//等价
}
return 0;
}