write a program to produce a truth table.

要求:程序接受命题公式输入,输出是该公式对应的真值表;

能够处理的连接词至少包括合取、析取、否定、和括号。

使用C语言编程;提交源代码(要求有注释)和可执行文件。

程序代码:

// sg12225028.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <IOSTREAM>
#include <VECTOR>
#include <STACK>
#include <STRING>

using namespace std;

//获取整型数据某一位的值
#define get_bit(datax,bitx) ((((unsigned)datax)>>bitx)&0x01)

void transform(const string &source,string &dest)
//把表达式字符串转换成后项表达式
{
	dest="";
	bool mark = false;//positive - false ; negtive - true 
	stack<char> stk_c;//栈 用来临时存放操作符
	for(int i=0;i<source.size();i++)
	{
		char c_tmp = source.at(i);
		if(c_tmp>='a'&&c_tmp<='z')
		{
			dest.append(1,c_tmp);
			if(mark) //添加负号
			{//添加取反操作进入目标字符串 恢复标志
				dest.append(1,'~');
				mark = false;
			}
			continue;
		}
		if(c_tmp == '~')
		{ //遇取反符号 设置标志
			mark = true;
			continue;
		}
		if(c_tmp=='(')
		{//遇左括号 压栈 临时存储
			stk_c.push(c_tmp);
			continue;
		}
		if(c_tmp == ')')
		{//遇右括号 弹出栈中左括号以后入栈内容
			while(!stk_c.empty() )
			{
				char c1 = stk_c.top();
				stk_c.pop();
				if(c1 == '(')
					break;
				dest.append(1,c1);
			}
			continue ;
		}
		if(c_tmp == '*')
		{//遇2元操作符 弹出栈中高优先级的操作符 并将当前操作符压栈
			char c2;
			while(!stk_c.empty() )
			{
				c2 = stk_c.top();
				if(c2 == '+' || c2 == '(')
					break;
				stk_c.pop();
				dest.append(1,c2);
			}
			stk_c.push(c_tmp);
			continue ;
		}
		if (c_tmp == '+')
		{//遇2元操作符 弹出栈中高优先级的操作符 并将当前操作符压栈
			char c3;
			while(!stk_c.empty() )
			{
				c3 = stk_c.top();
				if(c3 == '(')
					break;
				stk_c.pop();
				dest.append(1,c3);
			}
			stk_c.push(c_tmp);
			continue ;
		}
	}
	while(!stk_c.empty() )
	{//把最后留在栈中的操作符弹出 追加到目标字符串尾
		dest.append(1,stk_c.top());
		stk_c.pop();
	}
}

int get_num_vars(string &expression)
{//获取字符串中具有不同ascii的字符个数
	int num = 0;
	for(char a ='a';a<='z';a++)
	{
		if(expression.find(a,0)!=string::npos)
			num ++;
	}
	return num;
}

void resolve(string &expression)
{//根据后项表达式求解真值表
	//var_num 表达式中所使用的字符个数
	int var_num = get_num_vars(expression);

	//定义一张表 用来存储'a'-'z'在KEY的各个位上的映射
	//-1表示无映射 即未使用此变量
	//表中多出的一项用来存储表达式的临时结果 由于求解表达式需要多次循环迭代
	//故有此用法 方便求解
	int table_alpha[27];
	for(int tmp=0;tmp<27;tmp++)
		table_alpha[tmp]=-1;

	//最后的表项留给结果使用 赋值26可使寻址前后值不变
	table_alpha[26]=26;

	//offset用于在KEY的各个位之间寻址 确定各变量的值
	int offset = 0;

	//KEY的每一位表示一个变量 下述for循环可遍历所有变量的0 1组合情况
	for(unsigned int KEY = 0; KEY<(1<<var_num) ;KEY++)
	{
		string str=expression ;
		bool result = false;
		stack<char> oprands;//栈 用来临时存放操作数 即变量字符

		//取反标志 false 代表不取反;true代表取反
		bool mark[27];
		for(int tmp1=0;tmp1<27;tmp1++)
			mark[tmp1] = false;

		for(;!str.empty();str = str.substr(1))
		{//每次处理后 截断字符串 只保留未处理部分
			
			if(str.at(0)>='a'&&str.at(0)<='z')
			{//取操作数
				int op = str.at(0);

				//如果当前字符未分配过KEY的指定位,那么现在分配一个空余位
				//offset就是当前字符所分配到位 它总是正的
				//从低位到高位分配 当一个位被分配后 offset就移向下一个位
				if(table_alpha[op-'a']==-1)
					table_alpha[op-'a'] = offset++;
				
				//操作数压栈
				oprands.push(op);
				continue ;
			}

			//遇~号先保存相应变量的取反标志,后续在具体求取2元运算时处理
			if(str.at(0)=='~')
			{
				int id = oprands.top()-'a';
				mark[id]= !mark[id];
				continue ;
			}
			
			//遇到+或*操作,倒空操作数栈 求取表达式的值
			if(str.at(0)=='+' || str.at(0)=='*')
			{
				int oprand1,oprand2;
				int mark1,mark2;
				//oprand1 oprand2分别存储操作数(字符)相对于'a'的偏移量
				//方便在table_alpha mark 两张表中查询数据
				oprand1 = oprands.top() - 'a'; oprands.pop();
				oprand2 = oprands.top() - 'a'; oprands.pop();

				//mark1 mark2分别表示两个操作数的取反标志
				mark1 = mark[oprand1];
				mark2 = mark[oprand2];

				//oprand1 oprand2分别表示两个操作数的偏移量
				oprand1 = table_alpha[oprand1];
				oprand2 = table_alpha[oprand2];

				if(oprand1<26)//正常操作数 获取KEY响应位上的值
					oprand1 = mark1 ?(!get_bit(KEY,oprand1)): get_bit(KEY,oprand1) ;
				else if (oprand1==26)//如果是上次的结果
					oprand1 = result;

				if(oprand2<26)//正常操作数 获取KEY响应位上的值
					oprand2 = mark2 ?(!get_bit(KEY,oprand2)): get_bit(KEY,oprand2) ;
				else if (oprand2==26)//如果是上次的结果
					oprand2 = result;

				//计算结果
				if(str.at(0)=='+')
					result = oprand1 || oprand2 ;
				else
					result = oprand1 && oprand2 ;
				
				//将结果压栈 此处只需要压入结果相对于'a'的偏移量即26即可
				oprands.push('a'+26);
				continue ;
			}
		}
		//已处理完一次循环
		for(int mm1 = 25;mm1 >=0;mm1 --)
		{
			if(table_alpha[mm1]!=-1)
				cout << get_bit(KEY,table_alpha[mm1])<< "\t"<<ends;
		}
		cout << result <<endl;
	}
	for(int mm0 = 25;mm0 >=0;mm0 --)
	{
		if(table_alpha[mm0]!=-1)
			cout << (char)(mm0+'a')<< "\t"<<ends;
	}
	cout <<"R"<<endl;
}

int main(int argc, char* argv[])
{
	string exp,str2;
	cout << "输入一个表达式类似于: a+b*~c*(d+e):"<<endl;
	cin >>exp ;
	transform(exp,str2);
	cout<<"翻译成逆向表达式后:\n"<<str2 <<endl;
	cout <<"真值表如下:"<<endl;
	resolve(str2);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sanzhong104204

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值