命题逻辑之真值表

①C语言版

亮点:

1.qsort(b, j, sizeof(char), cmp);

C语言标准库函数

2.while(处理括号 || 处理否定 || 处理合取 ... );

可以消除运算符优先级的问题,但是还是解决不了同级运算符的先后问题。

如:p+q*r会变成p+(q*r)

3.模拟辗转相除法给变元赋值

代码简单明了,但是效率比不上位运算

#include "string.h"
#include "stdio.h"
#include "ctype.h"
#include "stdlib.h"

int cmp(const void* a, const void* b)
{
	return (*((char*) a) - *((char*) b));
}

int getalpha(char a[],char b[])
{
	char tmpc=' ';
	int n=strlen(a),i=0,j=0,k=0;
	for(i=0; i<n; i++)
	{
		if(isalpha(a[i]))					//改进1:使用isalpha()函数判断大小写,简洁明了
			//	if(((a[i]>='a')&&(a[i]<='z'))||((a[i]>='A')&&(a[i]<='Z')))
		{
			for(k=0; k<j; k++)
			{
				if(b[k]==a[i])
				{
					break;
				}
			}
			if(k>=j)
			{
				b[j]=a[i];
				j++;
			}
		}
	}

	qsort(b,j,sizeof(char),cmp);				//改进2:用快排代替冒泡排序,提高效率
	/*	for(i=0; i<j-1; i++)
		{
			for(k=0; k<j-i-1; k++)
			{
				if(b[k]>b[k+1])
				{
					tmpc=b[k];
					b[k]=b[k+1];
					b[k+1]=tmpc;
				}
			}
		}
	*/
	b[j]='\0';
	return j;
}

void fillValue(char a[],char varchar[],int nvar,
               char valchar[],char resultchar[])
{
	//a是原始公式,varchar是变元列表如pqrs,
	//valchar是变元的某次取值
	int nLen=strlen(a),i=0,j=0,k=0;
	for(i=0; i<nLen; i++)
		resultchar[i]=a[i];
	resultchar[i]='\0';
	for(i=0; i<nLen; i++)
	{
		//原公式中的每个字符
		for(j=0; j<nvar; j++)
		{
			//公式中的字符是第几个变元
			if(resultchar[i]==varchar[j])
			{
				//是第j个变元,其值换成第j个值
				resultchar[i]=valchar[j];
				break;
			}
		}
	}
}

bool negatecal(char a[])			//改进5:将函数返回类型改为bool,若在字符串中存在!1或!0,就把第一个!1或!0改成0或1,然后返回true;如果没找到,返回false
//void negatecal(char a[])			//...下面的函数进行完全相同的修改 
{
	int _result=0,i=0,j=0;
	while(i<strlen(a))
	{
		//如果当前位置起形如"!1"则换成"1"
		j=i;
		_result=0;
		if((j+1<strlen(a))&&(a[j]=='!')&&(a[j+1]=='1'))
		{
			a[j]='0';
			_result=1;
		}
		else if((j+1<strlen(a))&&(a[j]=='!')&&(a[j+1]=='0'))
		{
			a[j]='1';
			_result=1;
		}
		if(_result==1)
		{
			//如果有运算则后面的往前移
			j++;
			while(a[j+1]!='\0')
			{
				//后面的字符往前移1格
				a[j]=a[j+1];
				j++;
			}
			a[j]='\0';
			return 1;				//改进5
		}
		else
		{
			//没有!0或!1则看下一个指针
			i++;
		}
	}
	return 0;					//改进5
}

bool kuanhao(char a[])
{
	int _result=0,i=0,j=0;
	while (i<strlen(a)) 		//如果当前位置起形如(1)则换成1
	{
		j=i;
		_result=0;
		if ((j+2<strlen(a))&&(a[j]=='(')&&(a[j+1]=='1')&&(a[j+2]==')'))
		{
			a[j]='1';
			_result=1;
		}
		else if ((j+2<strlen(a))&&(a[j]=='(')&&(a[j+1]=='0')&&(a[j+2]==')'))
		{
			a[j]='0';
			_result=1;
		}
		if (_result==1)
		{
			j++;
			while (a[j+2]!='\0')
			{
				a[j]=a[j+2];
				j++;
			}
			a[j]='\0';
			return 1;
		}
		else
		{
			i++;
		}
	}
	return 0;
}

bool conYsh(char a[])
{
	int _result=0,i=0,j=0;
	while (i<strlen(a))  				//如果当前位置其形如1*1则换成"1"
	{
		j=i;
		_result=0;
		if ((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='*')&&(a[j+2]=='0'))
		{
			a[j]='0';
			_result=1;
		}
		else if ((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='*')&&(a[j+2]=='1'))
		{
			a[j]='0';
			_result=1;
		}
		else if ((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='*')&&(a[j+2]=='0'))
		{
			a[j]='0';
			_result=1;
		}
		else if ((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='*')&&(a[j+2]=='1'))
		{
			a[j]='1';
			_result=1;
		}
		if (_result==1)
		{
			j++;
			while (a[j+2]!='\0')
			{
				a[j]=a[j+2];
				j++;
			}
			a[j]='\0';
			return 1;
		}
		else
		{
			i++;
		}
	}
	return 0;
}

bool biCondYsh (char a[])		//1=1
{
	int _result=0,i=0,j=0;
	while(i<strlen(a))
	{
		j=i;
		_result=0;
		if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='=')&&(a[j+2]=='0'))
		{
			a[j]='1';
			_result=1;
		}
		else if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='=')&&(a[j+2]=='1'))
		{
			a[j]='0';
			_result=1;
		}
		else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='=')&&(a[j+2]=='0'))
		{
			a[j]='0';
			_result=1;
		}
		else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='=')&&(a[j+2]=='1'))
		{
			a[j]='1';
			_result=1;
		}
		if(_result==1)
		{
			j++;
			while(a[j+2]!='\0')
			{
				a[j]=a[j+2];
				j++;
			}
			a[j]='\0';
			return 1;
		}
		else
		{
			i++;
		}
	}
	return 0;
}

bool condYsh(char a[])			//1-1
{
	int _result=0,i=0,j=0;
	while(i<strlen(a))
	{
		j=i;
		_result=0;
		if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='-')&&(a[j+2]=='0'))
		{
			a[j]='1';
			_result=1;
		}
		else if((j+2<strlen(a))&&(a[j]=='0')&&(a[j+1]=='-')&&(a[j+2]=='1'))
		{
			a[j]='1';
			_result=1;
		}
		else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='-')&&(a[j+2]=='0'))
		{
			a[j]='0';
			_result=1;
		}
		else if((j+2<strlen(a))&&(a[j]=='1')&&(a[j+1]=='-')&&(a[j+2]=='1'))
		{
			a[j]='1';
			_result=1;
		}
		if(_result==1)
		{
			j++;
			while(a[j+2]!='\0')
			{
				a[j]=a[j+2];
				j++;
			}
			a[j]='\0';
			return 1;
		}
		else
		{
			i++;
		}
	}
	return 0;
}

bool disConjYsh(char a[])
{
	int _result=0,i=0,j=0;
	while (i<strlen(a))
	{
		j = i;
		_result =0;
		if ((j+2<strlen(a)) && (a[j]=='0') && (a[j+1]=='+')&& (a[j+2]=='0'))
		{
			a[j] = '0' ;
			_result=1;
		}
		else if ((j+2<strlen(a)) && (a[j]=='0') && (a[j+1]=='+')&& (a[j+2]=='1'))
		{
			a[j] = '1';
			_result=1;
		}
		else if ((j+2<strlen(a)) && (a[j]=='1') && (a[j+1]=='+')&& (a[j+2]=='0'))
		{
			a[j] ='1' ;
			_result=1;
		}
		else if ((j+2<strlen(a)) && (a[j]=='1') && (a[j+1]=='+')&& (a[j+2]=='1'))
		{
			a[j] ='1' ;
			_result=1;
		}
		if (_result==1)
		{
			j ++;
			while (a[j+2]!='\0')
			{
				a[j]=a[j+2];
				j++;
			}
			a[j]='\0';
			return 1;
		}
		else
		{
			i++;
		}
	}
	return 0;
}

int main(int argc,char* argv[])
{
	char pstate[120],pstate0[120],charList[120],charVal[120];
	char minItem[1024][52],truetable[1024];		//最多10个变量
	int i=0,nold=0,nnew=0,nvar=1,nRow=1,j=0,iMinItem=0;
//	int flagsum=1;	
	printf("请输入公式(析+,合*,条-,双=,否定!01) \n");
	gets(pstate0);
	fflush(stdin);

	nold=strlen(pstate0)+1;
	nnew=strlen(pstate0);
	strcpy(pstate,pstate0);			//改进3:strcpy函数拷贝字符串,简单快捷
	/*	for(i=0; i<nnew; i++)
		{
			pstate[i]=pstate0[i];
		}
		pstate[i]='\0';
	*/

	nvar=getalpha(pstate,charList);
	//真值表各个变元的值
	nRow=1;
	for(i=0; i<nvar; i++)
	{
		charVal[i]='0';
		nRow=nRow*2;
	}
	charVal[i]='\0';
	//真值表的首行
	printf("\n");
	for(i=0; i<nvar; i++)
		printf("%4c",charList[i]);
	printf("%15c%s\n",' ',pstate);

	for(i=0; i<nvar; i++)
		printf("%4c",'-');
	printf("|");
	for(i=0; i<60; i++)
		printf("%c",'-');
	printf("\n"); 
	
	int num;								//为改进4作铺垫
	for(i=0; i<nRow; i++)
	{
		num = i;
		for(j=nvar-1; j>=0; j--)			//改进4:new algorithm: 模拟"辗转相除法"给charList赋值,更简洁明了
		{
			charVal[j] = num % 2 + '0';
			num /= 2;
		}
		//真值表各行
		for(j=0; j<nvar; j++)
			printf("%4c",charVal[j]);
		//将值填入到公式中
		pstate[0]='\0';
		fillValue(pstate0,charList,nvar,charVal,pstate);

		while(negatecal(pstate)||kuanhao(pstate)||conYsh(pstate)||disConjYsh(pstate)||condYsh(pstate)||biCondYsh(pstate));
		//改进5:利用||的短路性质,保证处理顺序:否定、括号、合取析取、条件。消除了原代码的BUG

		/*		nold=strlen(pstate0)+1;			//原来处理字符串的办法 
				nnew=strlen(pstate);
				while(nnew<nold)
				{
					nold=strlen(pstate);
					negatecal(pstate);	 //否定
					kuanhao(pstate);	// (A)
					conYsh(pstate);		//1*1
					biCondYsh(pstate);	//1=1
					condYsh(pstate);	//1-1
					disConjYsh(pstate);	//1+1
					nnew=strlen(pstate);
				}
		*/
		if(strlen(pstate)==1)
		{
			if(pstate[0]=='1')
			{
				for (j=0; j<nvar; j++)
					minItem[iMinItem][j]=charVal[j];
				minItem[iMinItem][j]='\0';
				iMinItem++;
			}
			truetable[i]=pstate[0];
		}

		printf("%20c%s",' ',pstate);
		printf("\n");

		/*		flagsum=1;						//原算法:进位法 
				for(j=nvar-1; j>=0; j--)
				{
					if(charVal[j]=='1')
					{
						if(flagsum==1) 	
						{
							charVal[j]='0';
							flagsum=1;
						}
						else  //1+0=1 不变
						{
							break;
						}
					}
					else if(charVal[j]=='0')
					{
						if(flagsum==1)	
						{
							charVal[j]='1';
							flagsum=0;
						}		//0+0结束
						else
						{
							break;
						}
					}
				}
		*/
	}

	for (i=0; i<iMinItem; i++)
	{
		if (i==0)
			printf("m%s",minItem[i]);
		else
			printf("+m%s",minItem[i]);
	}
	printf("\n");

	for (i=0; i<iMinItem; i++)
	{
		if(i==0)
		{
			printf("(");
			for (j=0; j<nvar; j++)
			{
				if (j==0)
				{
					if (minItem[i][j]=='1')
						printf("%c",charList[j]);
					else
						printf("!%c",charList[j]);
				}
				else
				{
					if (minItem[i][j]=='1')
						printf("*%c",charList[j]);
					else
						printf("*!%c",charList[j]);
				}
			}
			printf(")");
		}
		else
		{
			printf("+(");
			for(j=0; j<nvar; j++)
			{
				if (j==0)
				{
					if (minItem[i][j]=='1')
						printf("%c",charList[j]);
					else
						printf("!%c",charList[j]);
				}
				else
				{
					if (minItem[i][j]=='1')
						printf("*%c",charList[j]);
					else
						printf("*!%c",charList[j]);
				}
			}
			printf(")");
		}
	}
}

运行结果展示:


②C++11版

亮点:

1.使用map容器储存变元—>0/1的映射

2.合理使用STL中的string::find和replace函数

3.增加判断了公式是否合法

// !否定,*合取,+析取,-条件,=双条件
#include <iostream>
#include <cstring>
#include <vector>
#include <cctype>
#include <cmath>
#include <map>
using namespace std;

map<char, bool> letter;				//用红黑树结构建立 p/q/r -> 0/1 的映射 //优点:查找方便且速度快,按字典顺序排序
vector<int> minum;
vector<int> maxum;

void setLetter( int num )				//set p/q/r with 0/1 
{
	for (auto p = letter.rbegin(); p != letter.rend(); ++p)	//new algorithm:模拟辗转相除法给p/q/r赋值
	{
		p->second = num % 2;
		num /= 2;
	}
}

bool rps( string& a, string f, string r )			//replace f with r in string a
{
	if (a.find( f ) != string::npos)				//string::find 
	{
		a.replace( a.find( f ), f.length(), r );	//string::replace 
		return true;
	}
	return false;
}

void setString( string& a )						//replace p/q/r with 0/1 in string
{
	for (auto &p : a)
		if (islower( p ))
		{
			if (letter[p]) p = '1';
			else p = '0';
		}
}

int getResult( string& tmp )					//get the result true/false
{
	//利用||判断符的"短路性",按照运算符优先级给原字符串替换,消除了原版本的bug 
	while (rps( tmp, "(0)", "0" ) || rps( tmp, "(1)", "1" ) ||
		rps( tmp, "!0", "1" ) || rps( tmp, "!1", "0" ) ||
		rps( tmp, "0+0", "0" ) || rps( tmp, "0+1", "1" ) || rps( tmp, "1+0", "1" ) || rps( tmp, "1+1", "1" ) ||
		rps( tmp, "0*0", "0" ) || rps( tmp, "0*1", "0" ) || rps( tmp, "1*0", "0" ) || rps( tmp, "1*1", "1" ) ||
		rps( tmp, "0-0", "1" ) || rps( tmp, "0-1", "1" ) || rps( tmp, "1-0", "0" ) || rps( tmp, "1-1", "1" ) ||
		rps( tmp, "0=0", "1" ) || rps( tmp, "0=1", "0" ) || rps( tmp, "1=0", "0" ) || rps( tmp, "1=1", "1" )
		);

	if (tmp == "1") return 1;
	else if (tmp == "0") return 0;
	else return -1;
}

void print( int num, bool isMax, int count )	//print the min_item or max_item 
{
	int temp = 0;
	setLetter( num );
	for (auto p = letter.begin(); p != letter.end(); ++p, ++temp)
	{
		if (p->second ^ isMax) cout << p->first;	//异或运算:若是小项,则输出值为0的变元;若是大项,输出值为1的变元 
		else cout << "!" << p->first;
		if (temp != count - 1)
		{
			if (isMax) cout << "+";
			else cout << "*";
		}
	}
}

int main()
{
	string input, tmp;
	cout << "说明:!否定,*合取,+析取,-条件,=双条件" << endl;
	cout << "请输入公式:";
	cin >> input;
	tmp = input;

	for (auto p : input)
		if (islower( p )) letter[p] = 0;	//把字母建立到map容器中去 

	setString( tmp );
	if (getResult( tmp ) == -1)			//首先判断公式是否合法 
	{
		cout << input << " 不合法!" << endl;
		return 0;
	}

	cout << endl << "真值表:" << endl;
	for (auto p : letter)
		cout << p.first << ' ';
	cout << '|' << input << endl;

	int count = pow( 2, letter.size() );
	for (int i = 0; i < count; ++i)				//for i = 0 to 2^letter_number
	{
		tmp = input;
		setLetter( i );
		setString( tmp );

		for (auto p : letter)
			cout << p.second << ' ';
		cout << '|';
		for (int j = 0; j < input.size() / 2; ++j)
			cout << ' ';

		if (getResult( tmp ))			//如果结果为1 
		{
			cout << 1 << endl;
			minum.push_back( i );		//储存到小项数组 
		}
		else
		{
			cout << 0 << endl;
			maxum.push_back( i );
		}
	}

	//print 主合/主析 
	cout << endl << "主析取范式:";
	if (minum.size() == 1) print( minum[0], false, letter.size() );
	else
	{
		for (auto p = minum.begin(); p != minum.end(); ++p)
		{
			cout << "(";
			print( *p, false, letter.size() );
			cout << ")";
			if (p != minum.end() - 1) cout << "+";
		}
	}
	cout << endl << endl;
	cout << "主合取范式:";
	if (maxum.size() == 1) print( maxum[0], true, letter.size() );
	else
	{
		for (auto p = maxum.begin(); p != maxum.end(); ++p)
		{
			cout << "(";
			print( *p, true, letter.size() );
			cout << ")";
			if (p != maxum.end() - 1) cout << "*";
		}
	}
	cout << endl << endl;
	system( "pause" );
	return 0;
}
运行结果:


猜你喜欢

转载自blog.csdn.net/leelitian3/article/details/79751829