离散数学命题公式求值及真值表

离散数学命题公式求值及真值表

题目要求

给定任意一个命题公式的真值表,并根据真值表求主范式。

算法思想

  1. 将逻辑表达式转换为后缀表达式,然后套用逆波兰表达式的求值方法
  2. 利用位运算,找出一个十进制整数对应二进制的每一位,给命题变项赋值
  3. 记录下成真赋值以及成假赋值,最后输出

代码

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <cmath>
#include <iomanip>

using namespace std;
/**
 * 用new_value替换src字符串中的old_value
 * @param src
 * @param old_value
 * @param new_value
 */
void replace(string &src, const string &old_value, const string &new_value);
/**
 * 获取一个整数二进制的某一位
 * @param num
 * @param bit 位数
 * @return
 */
int valueAtBit(int num, int bit);

/**
 * 计算给定真值及联结词的真值
 * @param p 命题变项p的赋值
 * @param q 命题变项q的赋值
 * @param model 联结词
 * @return 运算的真值
 */
int value(char p, char q, char op);

/**
 * 根据给定的表达式求取命题变项的个数
 * @param p_var 用于存放命题变项
 * @param ex 表达式
 */
void get_p_var(vector<char> &p_var, const string &ex);

/**
 * Infix expression is regarded as suffix expression
 * @param midExpression the mid expression
 * @return the suffix expression
 */
string midToSuf(const string &midExpression);

/**
 * Calculate the suffix expression with stack and record the value
 * @param suf suf expression
 * @param p_var
 * @param result real value set
 * @param assigment
 */
void calculate(const string &suf, vector<char> &p_var, vector<char> &result, vector<char> &t_assigment, vector<char> &f_assigment);
/**
 * 由后缀表达式计算
 * @param str
 * @return value
 */
int getValue(const string &str);

void setOut(vector<char> var, vector<char> result, vector<char> t_assigment, vector<char> f_assignment);
/**
 * 整数转二进制串
 * @param i
 * @param size
 * @return
 */
string intToStr(int i, int size);

int main() {
    // 读入需要求的表达式
    string ex;
    string suf_ex; // Suffix expression corresponding to infix expression
    // 记录命题变项
    vector<char> p_var;
    vector<char> result; // alphaStack propositional variables stack
    vector<char> t_assignment; // True assignment
    vector<char> f_assignment;
    string t_str, f_str;
    cout << "please input expression:(!:否定(括号外的否定需化入括号内)  &:合取  |:析取  >:蕴涵  =:等价)";
    cin >> ex;
    // Analytic expression, determine the number of propositional variables
    get_p_var(p_var, ex);
    // Infix expression is regarded as suffix expression
    suf_ex = midToSuf(ex);
    // Calculate the suffix expression and record the value
    calculate(suf_ex, p_var, result, t_assignment, f_assignment);
    setOut(p_var, result, t_assignment, f_assignment);
	return 0;
}

void setOut(vector<char> var, vector<char> result, vector<char> t_assigment, vector<char> f_assignment) {
	cout << "真值表如下:" << endl;
	int size = var.size();
	int k = pow(2, size);
	for (int i = 0; i < size; ++i) {
		cout << setiosflags(ios::left) << setfill(' ') << setw(2) << var[i];
	}
	cout << endl;
	string value;
	string t;
	for (int j = 0; j < k; ++j) {
		value = intToStr(j, size);
		for (int i = 0; i < size; ++i) {
			cout << setiosflags(ios::left) << setfill(' ') << setw(2) << value[i];
		}
		t = to_string(result[j]);
		cout << "    " << t << endl;
	}
	cout << "主析取范式:" << endl;
	int length = t_assigment.size();
	for (int l = 0; l < length; ++l) {
		t = to_string(t_assigment[l]);
		t.insert(0, 1, 'm');
		if (l + 1 != length) {
			t.append(1, '|');
		}
		cout << t;
	}
	cout << endl;
    cout << "主合取范式:" << endl;
    t.clear();
    length = f_assignment.size();
    for (int l = 0; l < length; ++l) {
        t = to_string(f_assignment[l]);
        t.insert(0, 1, 'M');
        if (l + 1 != length) {
            t.append(1, '&');
        }
        cout << t;
    }
}

int value(char p, char q, char op) {
	int val = 0;
	if (!isdigit(p) || !isdigit(q)) {
		throw "输入不合法";
	}
	bool p_v = p != '0';
	bool q_v = q != '0';
	switch (op) {
		case '=':
			val = p_v == q_v;
			break;
		case '>':
			val = p_v ? q_v ? 1 : 0 : 1;
			break;
		case '|':
			val = q_v || p_v;
			break;
		case '&':
			val = p_v && q_v;
			break;
		default:
			break;
	}
	return val;
}

void get_p_var(vector<char> &p_var, const string &ex) {
	bool exists = false;
	int length = ex.length();
	for (int i = 0; i < length; ++i) {
		exists = false;
		// if ex[i] is not a alpha, then continue.
		if (!isalpha(ex[i])) {
			continue;
		}
		for (char j : p_var) {
			// 如果当前命题变项已经存放,则直接跳过当前字符
			if (ex[i] == j) {
				exists = true;
				break;
			}
		}
		if (!exists) {
			p_var.push_back(ex[i]);
		}
	}
}

bool isOperator(char ch) {
	return ch == '|' || ch == '&' || ch == '>' || ch == '=' || ch == '(' || ch == ')';
	// 否则返回false
}

int getPriority(char ch) {
	int level = 0; // 优先级
	switch (ch) {
		case '(':
			level = 1;
			break;
		case '=':
			level = 2;
			break;
		case '>':
			level = 3;
			break;
		case '|':
			level = 4;
			break;
		case '&':
			level = 5;
			break;
		case ')':
			level = 6;
			break;
		default:
			break;
	}
	return level;
}

string midToSuf(const string &midExpression) {
	string str;
	int length = midExpression.length();
	stack<char> op;
	char top = ' ';
	for (int i = 0; i < length; ++i) {
		char ca = midExpression[i];
		if (isalpha(ca) || isdigit(ca) || ca == '!') { // 如果是数字
			if (ca == '!') {
				str.append(1, ca);
				str.append(1, midExpression[++i]);
				continue;
			} else {
				str.append(1, ca);
			}
		} else if (isOperator(ca)) {// 操作符
			if (!op.empty()) {
				top = op.top();
			}
			if (op.empty() || ca == '(' || getPriority(top) < getPriority(ca)) {
				op.push(ca);
				if (ca == ')') {
					while (true) {
						top = op.top();
						op.pop();
						if (top == '(') {
							break;
						} else {
							if (top == ')') {
								continue;
							}
							str.append(1, top);
						}
					}
				}
			} else {
				top = op.top();
				op.pop();
				op.push(ca);
				str.append(1, top);
			}

		} else {
			throw "expression is error";
		}
	}
	// 第二个while结束
	while (!op.empty()) {
		top = op.top();
		op.pop();
		str.append(1, top);
	}
	return str;
}

void calculate(const string &suf, vector<char> &p_var, vector<char> &result, vector<char> &t_assigment, vector<char> &f_assigment) {
	int size = p_var.size();
	int k = pow(2, size);
	string oldStr;
	string newStr;
	string temp;
	string t_value;
	for (int i = 0; i < k; ++i) {
		temp = suf;
		// 赋值
		t_value = intToStr(i, size);
		for (int j = 0; j < size; ++j) {
			newStr.append(1, t_value[size - 1 - j]);
			oldStr.append(1, p_var[size - 1 - j]);
			replace(temp, oldStr, newStr);
			newStr.clear();
			oldStr.clear();
		}
		int length = temp.length();
		for (int l = 0; l < length; ++l) {
			if (temp[l] == '!') {
				char t = temp[++l];
				int v = t - '0';
				v = !v;
				temp.replace( l , 1, to_string(v));
			}
		}
		replace(temp,"!","");
		int v = getValue(temp);
		if (v != 0) {
			t_assigment.push_back(i);
		} else {
		    f_assigment.push_back(i);
		}
		result.push_back(v);
	}
}

string intToStr(int i, int size) {
	string str;
	for (int j = 0; j < size; ++j) {
		int r = valueAtBit(i, j + 1);
		str.append(1, r + '0');
	}
	reverse(str.begin(), str.end());
	return str;
}

int getValue(const string &str) {
	stack<char> num;
	int size = str.size();
	for (int i = 0; i < size; ++i) {
		char t = str[i];
		if (isdigit(t)) {
			num.push(t);
		} else {
			char c1 = num.top();
			num.pop();
			char c2 = num.top();
			num.pop();
			int v = value(c2, c1, t);
			num.push(v + '0');
		}
	}
	return num.top() - '0';
}

int valueAtBit(int num, int bit) {
	return (num >> (bit - 1)) & 1;
}

void replace(string &src, const string &old_value, const string &new_value) {
	// 每次重新定位起始位置,防止上轮替换后的字符串形成新的old_value
	for (string::size_type pos(0); pos != string::npos; pos += new_value.length()) {
		if ((pos = src.find(old_value, pos)) != string::npos) {
			src.replace(pos, old_value.length(), new_value);
		} else break;
	}
}

总结

我这代码写的太low了
有时间再对这个代码进行优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值