输入合适公式(没有考虑优先级,只根据括号优先),输出时会提取其中的元素(比如这里有A B C),并打印真值表。
求值的一般顺序是:带入每个元素的值,求出式子的真值,所以可以分为两块:1.枚举元素值(枚举) 2.根据元素值求式子值(计算)
我认为这个的难点在于枚举,我们既要想办法提取出每一个元素,又要为其赋值(0和1)
我们先约定好六个运算符
'''
否.......... !(非)
合取........ &(与)
可兼或...... |(或)
不可兼或.... #
由...可得... >
当且仅当.... =
'''
并封装好这个真值表打印器
class FindTruth:
'''构造函数'''
def __init__(self):
'''输入'''
def __In(self):
'''枚举'''
def __Count(self, i):
'''计算公式结果'''
def __Sum(self, Str):
'''配对左右括号'''
def __Pei(self, cur, Str):
'''运算操作符'''
def __Add(self, w, a, b = -1):
'''输出'''
def __Out(self):
对于提取元素:涉及到字符串的处理以及查重,python提供了便捷的set集合来处理
对于赋值:比如式子A|B|C,提取出ABC后,一共有从000 到 111,2^3种情况,而N个元素就有2^N种情况,显然是不能用简单的循环是实现的,这里可以用递归来处理
a.利用set提取元素
set(字符串)能把字符串里每个字符提取出来,构成一个集合,而集合是不存在相同字符的,所以这里完成了筛选重复字符的工作。
如set('A|B&C') = {'A', 'B', 'C', '|', '&'}
seta.difference(setb)能让seta留下于setb集合中不同的元素。
所以第二句生成了一个筛选掉运算符的元素集合,完成了元素的提取
def __In(self):
#得到表达式Str
self.Str = input("input your expression: \n")
#筛出字母集合
self.Set = set(self.Str).difference(set("()!&|>=#"))
b.利用递归枚举赋值
如何递归呢,这里假如有三个元素A,B,C
递归函数有一个参数 i ,用来指定此次因该枚举哪一个元素的值,比如 i = 0, 则枚举A的值。
首先初始化一个字典用来存储元素的值:self.dict = {'A':0, 'B':0, 'C': 0}
第一次:{'A':0, 'B':0, 'C': 0},i = 1,所以先分别给A赋值0和赋值1,并把 i 加一,再调用枚举函数(也就是递归调用自己)。因为要调用自己两次,这里就产生了1*2 = 2个分支:
分支1:{'A':0, 'B':0, 'C': 0},i = 1
分支2:{'A':1, 'B':0, 'C': 0},i = 1
第二次,i = 1,分别给B赋值0和1,在第一次的两个分支的基础上产生了2*2 = 4个分支
分支1:{'A':0, 'B':0, 'C': 0},i = 1
分支11:{'A':0, 'B':0, 'C': 0},i = 2
分支12:{'A':0, 'B':1, 'C': 0},i = 2
分支2:{'A':1, 'B':0, 'C': 0},i = 1
分支21:{'A':1, 'B':0, 'C': 0},i = 2
分支22:{'A':1, 'B':1, 'C': 0},i = 2
第三次,同理,给C赋值的时候,会产生总共4*2 = 8个分支,这时候递归枚举也结束了,我们也得到了八个枚举的结果
A B C
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
实现代码:
def __Count(self, i):
'''结束条件:若最后一个元素也完成了枚举,则 打印 + 运算 '''
if i == len(self.Lis):
S = ''
for l in self.Lis:
S = S + str(self.Dic[l]) + ' '
print(S,self.__Sum(self.Str))#调用self__Sum()函数进行运算
return
'''不是结尾,则赋值并调用自己,产生两个分支'''
self.Dic[self.Lis[i]] = 0
self.__Count(i+1)
self.Dic[self.Lis[i]] = 1
self.__Count(i+1)
计算的思路很简单,我们分别设置三个值:
s :用来存储当前的终值,初始值设置为-1
s0 :用来存储当前式子或元素的值
operater :用来存储目前的操作符
然后一个字符一个字符地循环遍历表达式:
例:str = 'A | (A & B) & C' 调用 __sum(self, str):
循环1:字符 = 'A",则s = A的值
循环2:字符 = '|',则operater = '|'
循环3:字符 = '(',则s0 = __sum(self, ’括号内的那坨表达式‘),(这样便可利用递归简单地完成括号的处理)
s = (s operator s0),s0 = -1(更新s的值)
.......
到最后一个字符结束后,式子的值已经存储于s中了。
实现代码:
#求公式结果
def __Sum(self, Str):
i = 0 #字符位置
s = -1#式子真值
while i < len(Str):
c = Str[i]
#单操作符'!'要做特殊的分类处理
if c == "!":
#右边是字母
if Str[i+1] in self.Set:
c = Str[i+1]
i = i + 1
s0 = self.__Add('!',self.Dic[c])
#右边是左括号
else:
end = self.__Pei(i+1, Str)
s0 = self.__Add('!', self.__Sum(Str[i+1:end+1]))
i = end
#字母
elif c in self.Set:
s0 = self.Dic[c]
#其它运算符
elif c in set("&|>=#"):
operat = c
#左括号
elif c == '(':
end = self.__Pei(i, Str)
s0 = self.__Sum(Str[i+1:end])
i = end
#运算结果
if s == -1:
s = s0
s0 = -1
elif operat != 0 and s0 != -1:
s1 = s
s = self.__Add(operat, s, s0)
operat = 0
s0 = -1
i = i + 1
return s
#配对左右括号
def __Pei(self, cur, Str):
kflag = 1 # 左括号的数目
while not kflag == 0:
cur = cur + 1
if Str[cur] == '(':
kflag = kflag + 1
elif Str[cur] == ')':
kflag = kflag - 1
return cur
#运算操作
def __Add(self, operator, a, b = -1):#b默认为-1时,表示是单操作符号' ! '
if operator == '!':
boo = not a
elif operator == '&':
boo = a and b
elif operator == '|':
boo = a or b
elif operator == '#':
boo = ((not a) or (not b)) and (a or b)
elif operator == '>':
boo = (not a) or b
elif operator == '=':
boo = ((not a) and (not b)) or (a and b)
else:
print("there is no such operator")
if boo:
return 1
else:
return 0
# -*- coding: utf-8 -*-
'''
否.......... !
合取........ &
可兼或...... |
不可兼或.... #
由...可得... >
当且仅当.... =
'''
class FindTruth:
def __init__(self):
#存储字母及其真值
self.Dic = {}
self.Lis = []
#输入表达式
self.__In()
#输出真值表
self.__Out()
#输入
def __In(self):
#得到表达式Str
self.Str = input("input your expression: \n")
#筛出字母集合
self.Set = set(self.Str).difference(set("()!&|>=#"))
#求公式结果
def __Sum(self, Str):
i = 0 #字符位置
s = -1#式子真值
while i < len(Str):
c = Str[i]
#单操作符'!'要做特殊的分类处理
if c == "!":
#右边是字母
if Str[i+1] in self.Set:
c = Str[i+1]
i = i + 1
s0 = self.__Add('!',self.Dic[c])
#右边是左括号
else:
end = self.__Pei(i+1, Str)
s0 = self.__Add('!', self.__Sum(Str[i+1:end+1]))
i = end
#字母
elif c in self.Set:
s0 = self.Dic[c]
#其它运算符
elif c in set("&|>=#"):
operat = c
#左括号
elif c == '(':
end = self.__Pei(i, Str)
s0 = self.__Sum(Str[i+1:end])
i = end
#运算结果
if s == -1:
s = s0
s0 = -1
elif operat != 0 and s0 != -1:
s1 = s
s = self.__Add(operat, s, s0)
operat = 0
s0 = -1
i = i + 1
return s
#配对左右括号
def __Pei(self, cur, Str):
kflag = 1 # 左括号的数目
while not kflag == 0:
cur = cur + 1
if Str[cur] == '(':
kflag = kflag + 1
elif Str[cur] == ')':
kflag = kflag - 1
return cur
#运算操作
def __Add(self, operator, a, b = -1):#b默认为-1时,表示是单操作符号' ! '
if operator == '!':
boo = not a
elif operator == '&':
boo = a and b
elif operator == '|':
boo = a or b
elif operator == '#':
boo = ((not a) or (not b)) and (a or b)
elif operator == '>':
boo = (not a) or b
elif operator == '=':
boo = ((not a) and (not b)) or (a and b)
else:
print("there is no such operator")
if boo:
return 1
else:
return 0
#输出
def __Out(self):
#将字母放入dict和List
S = ''
for c in self.Set:
self.Dic[c] = 0
self.Lis.append(c)
S = S + c + ' '
print(S, self.Str)
self.__Count(0)
#构造2^n的序列
def __Count(self, i):
#是结尾,打印 + 运算
if i == len(self.Lis):
S = ''
for l in self.Lis:
S = S + str(self.Dic[l]) + ' '
print(S,self.__Sum(self.Str))
return
#不是结尾,递归赋值
self.Dic[self.Lis[i]] = 0
self.__Count(i+1)
self.Dic[self.Lis[i]] = 1
self.__Count(i+1)
if __name__ == '__main__':
F = FindTruth()