python - 根据表达式打印真值表
? 輸入邏輯表達式,輸出真值表,支持六個基本邏輯運算
最終效果:
? ? 輸入合適公式(沒有考慮優先級,只根據括號優先),輸出時會提取其中的元素(比如這里有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):#得到表達式Strself.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]] = 0self.__Count(i+1)self.Dic[self.Lis[i]] = 1self.__Count(i+1)? ? 二,再來處理計算 __Sum(self, Str)
? ? 計算的思路很簡單,我們分別設置三個值:
? ? ? ? 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 + 1s0 = 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 = s0s0 = -1elif operat != 0 and s0 != -1:s1 = ss = self.__Add(operat, s, s0)operat = 0s0 = -1i = i + 1return s #配對左右括號 def __Pei(self, cur, Str):kflag = 1 # 左括號的數目while not kflag == 0:cur = cur + 1if Str[cur] == '(':kflag = kflag + 1elif Str[cur] == ')':kflag = kflag - 1return cur #運算操作 def __Add(self, operator, a, b = -1):#b默認為-1時,表示是單操作符號' ! 'if operator == '!':boo = not aelif operator == '&':boo = a and belif operator == '|':boo = a or belif operator == '#':boo = ((not a) or (not b)) and (a or b)elif operator == '>':boo = (not a) or belif operator == '=':boo = ((not a) and (not b)) or (a and b)else:print("there is no such operator")if boo:return 1else:return 0完整代碼:?
# -*- coding: utf-8 -*- ''' 否.......... ! 合取........ & 可兼或...... | 不可兼或.... # 由...可得... > 當且僅當.... = ''' class FindTruth:def __init__(self):#存儲字母及其真值self.Dic = {}self.Lis = []#輸入表達式self.__In()#輸出真值表self.__Out()#輸入def __In(self):#得到表達式Strself.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 + 1s0 = 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 = s0s0 = -1elif operat != 0 and s0 != -1:s1 = ss = self.__Add(operat, s, s0)operat = 0s0 = -1i = i + 1return s#配對左右括號def __Pei(self, cur, Str):kflag = 1 # 左括號的數目while not kflag == 0:cur = cur + 1if Str[cur] == '(':kflag = kflag + 1elif Str[cur] == ')':kflag = kflag - 1return cur #運算操作def __Add(self, operator, a, b = -1):#b默認為-1時,表示是單操作符號' ! 'if operator == '!':boo = not aelif operator == '&':boo = a and belif operator == '|':boo = a or belif operator == '#':boo = ((not a) or (not b)) and (a or b)elif operator == '>':boo = (not a) or belif operator == '=':boo = ((not a) and (not b)) or (a and b)else:print("there is no such operator")if boo:return 1else:return 0#輸出def __Out(self):#將字母放入dict和ListS = ''for c in self.Set:self.Dic[c] = 0self.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]] = 0self.__Count(i+1)self.Dic[self.Lis[i]] = 1self.__Count(i+1)if __name__ == '__main__':F = FindTruth()?
總結
以上是生活随笔為你收集整理的python - 根据表达式打印真值表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 区块链对未来金融的重要影响
- 下一篇: 百度地图李东旻:中国地图行业最终只会剩下