1.为了方便计算,可以将中缀表达式转变为后缀表达式(逆波兰式)
方法:
(1)创建一个空栈opstack,用于存放运算符,创建一个空列表output用于保存输出结果
(2)使用python字符串的split函数将输入的中缀表达式(infix)字符串分割成列表并存入input列表中。
(3)从左到右遍历input列表的每个元素token
- 若token是运算数,直接append到output中;
- 若token是运算符,先判断它与opstack栈顶元素的运算优先级(注:小括号的优先级约定为最低),若:token的优先级小于等于栈顶元素优先级,则先从opstack中pop出栈顶元素并append到output,再将token push进opstack;否则直接将token push 进opstack
- 若token是左括号,一次pop出opstack中的元素并依次append到output,直到遇到左括号,将左括号继续pop出(但不append到output)
(4)当遍历完成input,将opstack中所有的剩余元素pop出并依次append到output
(5)将output转换为字符串,即为最终求得的后缀表达式
例如:
将(A+B)*C这样一个中缀表达式转换为后缀表达式(其中A,B,C)表示整数,按照上述算法,转换过程如下:
No. | opstack | output |
1 | ( | |
2 | ( | A |
3 | (+ | A |
4 | (+ | A B |
5 | A B + | |
6 | * | A B + |
7 | * | A B + C |
8 | A B + C * |
此部分代码实现:
operators = ['!','&','|','*','+']#按照优先级从高到低的顺序
#pop 函数删除栈顶的元素,top 函数查看栈顶元素。
#找到命题包含的变元
#中缀表达式转后缀表达式
def postfix(elements): #postfix “后缀的意思”
global operators
stack = list()#用于存放运算符
output = list()#用于保存输出结果
for ele in elements:
# ele是运算数,直接append到output
if ele not in operators and ele not in ('(',')'):
output.append(ele)
#若ele是左括号,直接将其push进stack
elif ele == '(':#小括号的优先级定为最低
stack.append(ele)
# 若ele是运算符,先判断它与stack栈顶元素的运算优先级。若:ele的优先级小于等于栈顶元素的优先级,
# 则先从stack中pop出栈顶元素并append到output,再将ele push进stack;
# 否则直接将ele push进stack
elif ele in ('!', '&', '|', '*', '+'):
if len(stack) == 0:
stack.append(ele)
continue
while (ele == '!' and stack[-1] == '!') or \
(ele == '&' and stack[-1] in ('!', '&')) or \
(ele == '|' and stack[-1] in ('!', '&', '|')) or \
(ele == '*' and stack[-1] in ('!', '&', '|', '*')) or \
(ele == '+' and stack[-1] in ('!', '&', '|', '*', '+')):
val = stack.pop()
output.append(val)
if not stack:
break
stack.append(ele)
#若ele是右括号,依次pop出stack中的元素并依次append到output,
#直到遇到左括号,将左括号继续pop出(但不append到output)
elif ele == ')':
val = stack.pop()
while val != '(':
output.append(val)
# if stack:
# # 如果stack列表还有元素执行这块
# else:
# # 如果stack列表没有元素了执行这块
if stack:
val = stack.pop()
else:
break
#当表达式完全处理完之后,把栈中的运算符一一出栈,转化成后缀表达式
while stack != []:
output.append(stack.pop())
return ''.join(output)
#print('请输入运算式:')
#inp = input('')
#expr = postfix(inp)
#print(expr)
2.打印真值表(前面一部分):
此处打印真值表采用的是bin()函数。通过对此函数的使用,可以较为简洁的列出所有变元的所有情况。(这时还不包括最后的值,仅仅只是变元的所有情况)
代码如下:
var = list()
#找出变元且不能重复
for item in expr:
if item not in operators and \
item not in var and \
item not in ('(',')'):
var.append(item)
lt = []
vlen = len(var)
n = 2 ** vlen
for i in range(0, n):
tlt = list(bin(i))
tlt.pop(0)
tlt.pop(0)
tlen = len(tlt)
for j in range(0, vlen - tlen):
tlt.insert(0, '0')
print(tlt)
lt.append(tlt)
# print(lt)
除此之外,打印真值表还可以采用枚举法,也就是对变元(需要将所有变元找出来)的T、F的枚举。相当于未知阶的嵌套循环,对此应该用递归解决。
3.再考虑命题的计算,分别写出几种运算(非、析取、合取、单条件、双条件)的计算方式
代码实现如下:
def logica10p(tmp):
idx = 0 #当前命题元素的位置
while len(tmp)>1: #当最后命题仅为真值后,退出循环
if tmp[idx] in operators:
if tmp[idx] == '!': #非运算
#这里把命题变元进行转换,根据后缀表达式,一定满足idx的前一位或前2位是真值而不是运算符
tmp[idx - 1] = 1 if int(tmp[idx - 1]) == 0 else 0
tmp[idx:idx + 1] = [] #子命题结果对原命题的覆盖
#每次从头开始对命题处理
idx = 0
continue
elif tmp[idx] == '&': #合取运算
tmp[idx] = 1 if int(tmp[idx - 1]) == 1 and int(tmp[idx - 2]) == 1 else 0
tmp[idx - 2:idx] = []
idx = 0
continue
elif tmp[idx] == '|': #析取运算
tmp[idx] = 0 if int(tmp[idx - 1]) == 0 and int(tmp[idx - 2]) == 0 else 1
tmp[idx - 2:idx] = []
idx = 0
continue
elif tmp[idx] == '*': #单条件
tmp[idx] = 0 if int(tmp[idx - 2]) == 1 and int(tmp[idx - 1]) == 0 else 1
tmp[idx - 2:idx] = []
idx = 0
continue
elif tmp[idx] == '+': #双条件
tmp[idx] = 1 if int(tmp[idx - 2]) == int(tmp[idx - 1]) else 0
tmp[idx - 2:idx] = []
idx = 0
continue
idx += 1
# print(tmp[0])
return tmp[0]
4.使用上述函数logical0p()打印命题各种情况的结果
代码如下:
result = []
for i in lt:
tmp1 = str(expr)
for j in range(0, vlen):
# print(tmp,var[j],i[j])
tmp1 = tmp1.replace(var[j], i[j]) # 将每个变量的位置用对应的真值组合中的0或1代替
# print(tmp1)
tmp = list(tmp1)
# print(tmp)
a = logica10p(tmp)
result.append(a)
print(result)
5.最后,由于上述的结果均为一个列表,需要在将其转换一下:
# 开始输出真值表
k = 0
print("\n真值表>>>")
# print('\t'.join(var),end='\t') #结果为 p q r s
for i in var:
print(i, "\t", end='')
print(inp, "")
for i in lt:
for j in range(0, vlen):
print(i[j], "\t", end='')
print(result[k])
k = k + 1
idx = 0
for nl in range(0,n):
if result[idx] == 1:
ornl.append(nl)
else:
andnl.append(nl)
idx += 1
print('主析取范式:')
print('∑', ornl)
print('主合取范式:')
print('∏', andnl)
完整代码:
# !:非(单命题变元)
# &:合取
# |:析取
# *:单条件(则)
# +:双条件(当且仅当)
operators = ['!','&','|','*','+']#按照优先级从高到低的顺序
#pop 函数删除栈顶的元素,top 函数查看栈顶元素。
#找到命题包含的变元
#中缀表达式转后缀表达式
def postfix(elements): #postfix “后缀的意思”
global operators
stack = list()#用于存放运算符
output = list()#用于保存输出结果
for ele in elements:
# ele是运算数,直接append到output
if ele not in operators and ele not in ('(',')'):
output.append(ele)
#若ele是左括号,直接将其push进stack
elif ele == '(':#小括号的优先级定为最低
stack.append(ele)
# 若ele是运算符,先判断它与stack栈顶元素的运算优先级。若:ele的优先级小于等于栈顶元素的优先级,
# 则先从stack中pop出栈顶元素并append到output,再将ele push进stack;
# 否则直接将ele push进stack
elif ele in ('!', '&', '|', '*', '+'):
if len(stack) == 0:
stack.append(ele)
continue
while (ele == '!' and stack[-1] == '!') or \
(ele == '&' and stack[-1] in ('!', '&')) or \
(ele == '|' and stack[-1] in ('!', '&', '|')) or \
(ele == '*' and stack[-1] in ('!', '&', '|', '*')) or \
(ele == '+' and stack[-1] in ('!', '&', '|', '*', '+')):
val = stack.pop()
output.append(val)
if not stack:
break
stack.append(ele)
#若ele是右括号,依次pop出stack中的元素并依次append到output,
#直到遇到左括号,将左括号继续pop出(但不append到output)
elif ele == ')':
val = stack.pop()
while val != '(':
output.append(val)
# if stack:
# # 如果stack列表还有元素执行这块
# else:
# # 如果stack列表没有元素了执行这块
if stack:
val = stack.pop()
else:
break
#当表达式完全处理完之后,把栈中的运算符一一出栈,转化成后缀表达式
while stack != []:
output.append(stack.pop())
return ''.join(output)
def logica10p(tmp):
idx = 0 #当前命题元素的位置
while len(tmp)>1: #当最后命题仅为真值后,退出循环
if tmp[idx] in operators:
if tmp[idx] == '!': #非运算
#这里把命题变元进行转换,根据后缀表达式,一定满足idx的前一位或前2位是真值而不是运算符
tmp[idx - 1] = 1 if int(tmp[idx - 1]) == 0 else 0
tmp[idx:idx + 1] = [] #子命题结果对原命题的覆盖
#每次从头开始对命题处理
idx = 0
continue
elif tmp[idx] == '&': #合取运算
tmp[idx] = 1 if int(tmp[idx - 1]) == 1 and int(tmp[idx - 2]) == 1 else 0
tmp[idx - 2:idx] = []
idx = 0
continue
elif tmp[idx] == '|': #析取运算
tmp[idx] = 0 if int(tmp[idx - 1]) == 0 and int(tmp[idx - 2]) == 0 else 1
tmp[idx - 2:idx] = []
idx = 0
continue
elif tmp[idx] == '*': #单条件
tmp[idx] = 0 if int(tmp[idx - 2]) == 1 and int(tmp[idx - 1]) == 0 else 1
tmp[idx - 2:idx] = []
idx = 0
continue
elif tmp[idx] == '+': #双条件
tmp[idx] = 1 if int(tmp[idx - 2]) == int(tmp[idx - 1]) else 0
tmp[idx - 2:idx] = []
idx = 0
continue
idx += 1
# print(tmp[0])
return tmp[0]
print('请输入运算式:')
inp = input('') #例如:p&q|r*q&!s|r
expr = postfix(inp) #pq&r|qs!&r|*
ornl = []
andnl = []
var = list()
#找出变元且不能重复
for item in expr:
if item not in operators and \
item not in var and \
item not in ('(',')'):
var.append(item)
lt = []
vlen = len(var)
n = 2 ** vlen
for i in range(0, n):
tlt = list(bin(i))
tlt.pop(0)
tlt.pop(0)
tlen = len(tlt)
for j in range(0, vlen - tlen):
tlt.insert(0, '0')
print(tlt)
lt.append(tlt)
# print(lt)
result = []
for i in lt:
tmp1 = str(expr)
for j in range(0, vlen):
# print(tmp,var[j],i[j])
tmp1 = tmp1.replace(var[j], i[j]) # 将每个变量的位置用对应的真值组合中的0或1代替
# print(tmp1)
tmp = list(tmp1)
# print(tmp)
a = logica10p(tmp)
result.append(a)
print(result)
# 开始输出真值表
k = 0
print("\n真值表>>>")
# print('\t'.join(var),end='\t') #结果为 p q r s
for i in var:
print(i, "\t", end='')
print(inp, "")
for i in lt:
for j in range(0, vlen):
print(i[j], "\t", end='')
print(result[k])
k = k + 1
idx = 0
for nl in range(0,n):
if result[idx] == 1:
ornl.append(nl)
else:
andnl.append(nl)
idx += 1
print('主析取范式:')
print('∑', ornl)
print('主合取范式:')
print('∏', andnl)
参考:https://mbd.baidu.com/ma/s/LJcQ0Efm