整理东西发现早先用C/C++写的一份代码,用到了栈数据结构,想想应该可以贴出来。主要目的是输入命题,然后输出所有的成真赋
程序需要实现输入一个条件表达式,输出其所有成真赋值。
程序分为两个部分,一个是检查输入的表达式以及命题是否正确及匹配。一个是核心代码,用于求结果。根据命题个数得出不同赋值方式的的个数(认为是一组二进制数,因此以十进制保存,即若有三个命题则从 0 ~ 23 -1)再代入表达式,即以栈的数据结构对表达式求值。表达式求值规则为,数值全部入栈,符号优先级大于栈顶的入栈,反之出栈运算,将结果再入栈。最终结果若为0则将其标记。一个条件判定结束后,对下一个条件做相同的判定,已经被标记的赋值方式不再代入计算。当所有条件判定结束后,即可输出结果。
#include <iostream>
#include <stdlib.h>// system("cls");函数所在的库
#include <string>
#include <stack>//STL
using namespace std;
class Check
//条件检测类,构造函数输入命题,SetCon(string s)输入条件
//Condition_Check()检测函数,正确返回true,错误返回false
{
string con;//条件
string pro;//命题
public:
Check(string s)//输入命题
{
pro = s;
}
void SetCon(string s)//输入条件
{
con=s;
}
bool Word_Check()//判断命题是否为字母
{
for(int i=0;pro[i];i++)
if(!(pro[i]>='a' && pro[i]<='z' || pro[i]>='A' && pro[i]<='Z'))
return false;
return true;
}
bool Pro_Check(char ch)//命题检测,ch是否为命题之一
{
for(int i=0;pro[i];i++)
if(ch==pro[i])
return true;
return false;
}
bool Double_Sigh(char ch)
{
if(ch=='|' || ch=='&' || ch=='>' || ch=='=')
return true;
return false;
}
bool Condition_Check()//条件检测,判断是否符合条件
{
if(!Word_Check())//判断命题是否为字母
return false;
int left = 0,right = 0;
for(int i=0;con[i];i++)
{
if( !Pro_Check(con[i]) && !Double_Sigh(con[i]) && con[i]!='!' && con[i]!='(' && con[i]!=')' )//是否为命题或符号
return false;
if(!Pro_Check(con[i]))//不是命题则进入
{
if( i>0 && con[i]=='!' && ( Pro_Check(con[i-1]) || con[i-1]==')' ))//!之前不为 命题和 )
return false;
if( con[i+1] && con[i]=='!' && ( Double_Sigh(con[i+1]) || con[i+1]== ')' ))// ! 之后不为 | & > = )
return false;
if( i>0 && Double_Sigh(con[i]) && ( Double_Sigh(con[i-1]) || con[i-1]=='(' ))// | & > = 前不为 | & > = (
return false;
if( con[i+1] && Double_Sigh(con[i]) && ( Double_Sigh(con[i+1]) || con[i+1]==')' ))// | & > = 后不为 | & > = )
return false;
if( i>0 && con[i]=='(' && (Pro_Check(con[i-1]) || con[i-1] == ')' ))//( 前不为 命题和) 之后的问题在上面已经判断
return false;
if( con[i+1] && con[i]==')' && Pro_Check(con[i+1]) )
return false;
if(con[i]=='(')left++;
if(con[i]==')')right++;
}
}
if(left!=right)//左右括号个数的比较,括号进一步判配置于栈运算时
return false;
return true;
}
};
int Calculate(int a , char op , int b = 0)//计算函数,单目运算省略第三个参数
{
switch(op)
{
case '!':return !a;
case '&':return a&&b;
case '|':return a||b;
case '>':return !a||b;
case '=':return a==b;
}
}
char Precede(char a, char b)//a为栈顶符号,b为待入栈符号
{
int i,j;
char pre[][8]={
/*运算符之间的优先级制作成一张表格*/
{'>','>','>','>','>','<','>','>'},
{'<','>','>','>','>','<','>','>'},
{'<','<','>','>','>','<','>','>'},
{'<','<','<','>','>','<','>','>'},
{'<','<','<','<','>','<','>','>'},
{'<','<','<','<','<','<','>','0'},
{'>','>','>','>','>','0','>','>'},
{'<','<','<','<','<','<','0','='}};
switch(a){
case '!': i=0; break;
case '&': i=1; break;
case '|': i=2; break;
case '>': i=3; break;
case '=': i=4; break;
case '(': i=5; break;
case ')': i=6; break;
case '#': i=7; break;
}
switch(b){
case '!': j=0; break;
case '&': j=1; break;
case '|': j=2; break;
case '>': j=3; break;
case '=': j=4; break;
case '(': j=5; break;
case ')': j=6; break;
case '#': j=7; break;
}
return pre[i][j];
}
int FindNum(char ch,string pro) //如果是命题就返回下标 否则返回-1
{
for(int i=0; pro[i] ; i++)
if(pro[i] == ch)
return i;
return -1;
}
int main()
{
string str,pro;
int i,j,k,l,n,m,x,y;
int START = 1; //循环标志位 以及 错误标志位
int *a;//存放命题的值
bool *flag;//结果
char ch;
string *name;
stack <int> num;//数值栈(命题)
stack <char> op;//符号栈
op.push('#');//符号栈预读#
do{
cout<<"----------------------------离散数学实验一----------------------------"<<endl;
cout<<"| |"<<endl;
cout<<"| 能够识别的运算符有 非! 且& 或| 蕴含> 等价= 请勿输入错误运算符 |"<<endl;
cout<<"| 命题范围为26个字母,支持大小写 |"<<endl;
cout<<"| 本程序有表达式查错功能,但是请尽量输入正确的表达式 |"<<endl;
cout<<"| 本程序使用DEV-C编写 |"<<endl;
cout<<"| 尽量不要输入中文,编码不支持容易出现乱码 |"<<endl;
cout<<"| |"<<endl;
cout<<"----------------------------------------------------------------------"<<endl;
cout<<"-问题描述:某科研所要从一些人中挑选一部分人出国进修。由于工作需要,仅选派符合条件的人。"<<endl;
cout<<"-请输入简单命题个数: ";
cin>>n;
name = new string[n];//存放名字
a = new int[n]; //存放命题的值,下标对应命题下标
flag = new bool[1<<n]; //判断结果0 ~ (1<<n)-1
for(i=0;i<1<<n;i++)flag[i]=true;//初始化flag
cout<<"-请输入命题,格式为 命题<空格>名字<回车>"<<endl;
for(i=0;i<n;i++)
cin>>pro[i]>>name[i];//输入命题和名字
pro[i] = 0;//字符串最后0结束符
Check check(pro);
cout<<"-请输入条件个数: ";
cin>>m;
for(i=1;i<=m;i++)// 处理每个条件
{
cin>>str;
check.SetCon(str);//输入条件到检测对象中
if(check.Condition_Check())//检测条件是否符合规则
{
for(j = 0 ; j < 1<<n ;j++)//循环判断出正确结果
{
while(!num.empty()) num.pop();//清空栈
while(op.top()!='#')op.pop();//清空栈
//程序运行正常的情况下这两句不会运行
l = j;
for(k=n-1;k>=0;k--)//把数值放入数组a中
{
a[k]=l%2;
l/=2;
}
for(k = 0 ; str[k] ; k++)
{
x = FindNum(str[k],pro);
if( x != -1 ) //数值入栈
{
num.push(a[x]);
}
else
{
ch = op.top();
if( str[k] == ')' )//如果是右括号则不进栈,持续出栈直到左括号
{
op.pop();
while(ch!='(')
{
y = num.top();
num.pop();
if(ch == '!')
{
num.push( Calculate(y,ch) );
}
else
{
x = num.top();
num.pop();
num.push( Calculate(x,ch,y) );
}
ch = op.top();
op.pop();
}
}
else if( Precede(ch,str[k]) =='<' )//待入栈的优先级高于栈顶,就入栈
{
op.push(str[k]);
}
else if( Precede(ch,str[k]) =='>' )//待入栈的优先级低于栈顶,就出栈
{
y = num.top();
num.pop();
if(ch == '!')
{
num.push( Calculate(y,ch) );
}
else
{
x = num.top();
num.pop();
num.push( Calculate(x,ch,y) );
}
op.pop();
op.push(str[k]);
}
}
}
ch = op.top();
while(ch!='#')
{
op.pop();
y = num.top();
num.pop();
if(ch == '!')
{
num.push( Calculate(y,ch) );
}
else
{
x = num.top();
num.pop();
num.push( Calculate(x,ch,y) );
}
ch = op.top();
}
if(num.top()==0)//结果不符合要求,标记为false
{
flag[j] = false;
}
num.pop();
}
}
else//错误条件结束本次实验
{
START = 0;
break;
}
}
if(START)
{
for(i=1,j = 0 ; j < 1<<n ; j++)
{
if(flag[j])
{
cout<<"Case"<<i<<":"<<endl;
i++;
l = j;
for(k=n-1;k>=0;k--)//把数值放入数组a中
{
a[k]=l%2;
l/=2;
}
for(k=0;k<n;k++)
{
if(a[k]==1)
cout<<name[k]<<" :去 ";
else
cout<<name[k]<<" :不去 ";
cout<<endl;
}
}
}
if(i==1)
cout<<"------------NO CASE------------"<<endl;
}
else
cout<<"-输入错误!"<<endl;
delete []a;
delete []flag;
cout<<"-还要继续吗?输入1继续,输入0结束"<<endl;
cin>>START;
system("cls");
if(!START)
{
cout<<"-结束。。。"<<endl;
}
}while(START);
return 0;
}