因为遇到了这个问题,但是并没有找到相关的资料参考,所以写了这篇文章,给有这个问题的小伙伴提供参考
原理类似于中缀表达式转二叉树,把运算符的优先级换掉就可以了
但是谓词表达式要注意三个运算符﹁,∃x,∀x,因为它们三都是只有一个运算数的,需要单独处理
主要思想:输入中缀一阶谓词表达式,先将中缀表达式转后缀表达式,再将后缀表达式构建二叉树,最后打印二叉树
放上代码,有兴趣的同学可以看一下,还不太完善,有什么好的改进方法欢迎交流
可以加一个字符串的切分函数,以及错误判断
#####一阶谓词表达式转二叉树######
# coding:UTF8
import networkx as nx
import matplotlib.pyplot as plt
from collections import defaultdict
class TNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 判断是否是运算符
def isOper(self, ch):
'''if ch in ['+', '-', '*', '/', '^', '(', ')']:
return True
return False'''
if ch in ['!', '%x', '&x', '<', '>', '->', '(', ')', '%y', '&y']:
return True
return False
# 获取运算符所对应的优先级别
def getOperOrder(self, ch):
if ch == '(':
return 1
if ch in ['!', '%x', '&x', '%y', '&y']:
return 2
if ch in ['<', '>']:
return 3
if ch == ['->','<->']:
return 4
if ch == '^':
return 5
return 0
# 中序遍历表达式二叉树
def InorderTree(self, pNode):
if not pNode:
return
if pNode.left:
# 如果左子树是符号,且优先级低于父节点的优先级则需要加括号
if self.isOper(pNode.left.val) and self.getOperOrder(pNode.left.val) < self.getOperOrder(pNode.val):
res.append('(')
self.InorderTree(pNode.left)
res.append(')')
else:
self.InorderTree(pNode.left)
res.append(pNode.val)
if pNode.right:
# 如果有子树是符号且优先级低于父节点的优先级,则需要加括号
if self.isOper(pNode.right.val) and self.getOperOrder(pNode.right.val) <= self.getOperOrder(pNode.val):
res.append('(')
self.InorderTree(pNode.right)
res.append(')')
else:
self.InorderTree(pNode.right)
# 创建二叉树
def createTree(self, data):
if not data:
return
ch = data.pop(0)
if ch == '#':
return None
else:
root = TNode(ch)
root.left = self.createTree(data)
root.right = self.createTree(data)
return root
# 后缀表达式生成二叉树
def PostExpTree(self, data):
if not data:
return
re = []
while data:
tmp = data.pop(0)
if not self.isOper(tmp):
re.append(TNode(tmp))
elif tmp in ['!', '%x', '&x', '%y', '&y']: ##单独处理只有一个运算数的运算符
p = TNode(tmp)
p.right = re.pop()
re.append(p)
else:
p = TNode(tmp)
p.right = re.pop()
p.left = re.pop()
re.append(p)
return re.pop()
# 中缀表达式生成二叉树
def InExpTree(self, data):
re = []
op = []
while data:
tmp = data.pop(0)
if not self.isOper(tmp): #判断是否是运算符
re.append(tmp)
else:
if tmp == '(':
op.append('(')
elif tmp == ')':
while op[-1] != '(':
re.append(op.pop())
op.pop()
elif tmp in ['!', '%x', '&x', '<', '>', '->','<->', '%y', '&y']:
while op and op[-1] != '(' and self.getOperOrder(op[-1]) > self.getOperOrder(tmp):
re.append(op.pop())
op.append(tmp)
if op:
re = re + op[::-1]
#print(re)
return self.PostExpTree(re) #后缀表达式生成二叉树
def draw(node): # 以某个节点为根画图
saw = defaultdict(int)
def create_graph(G, node, p_name, pos={}, x=0, y=0, layer=1):
if not node:
return
name = str(node.val )
saw[name] += 1
if name in saw.keys():
name += ' ' * saw[name]
if layer != 1:
G.add_edge(p_name, name)
pos[name] = (x, y)
l_x, l_y = x - 2 / 3 ** layer, y - 1
l_layer = layer + 1
create_graph(G, node.left, name, x=l_x, y=l_y, pos=pos, layer=l_layer)
r_x, r_y = x + 2 / 3 ** layer, y - 1
r_layer = layer + 1
create_graph(G, node.right, name, x=r_x, y=r_y, pos=pos, layer=r_layer)
return (G, pos)
graph = nx.DiGraph()
graph, pos = create_graph(graph, node, " ")
pos[" "] = (0, 0)
fig, ax = plt.subplots(figsize=(8, 10)) # 比例可以根据树的深度适当调节
nx.draw_networkx(graph, pos, ax=ax, node_size=1000)
plt.show()
#data = ['&x', '(', 'd', '->', 'a', ')']
data = ['&x', '(', 'd', '->', '!', 'a', ')']
#data = ['(', '(', 'd', '->', 'a', ')', '->', 'c', ')']
#data = sys.stdin.readline().strip()
data = raw_input("input:")
data = data.strip().split() #将输入按空格分隔,放入list中
#print(type(data))
#print(data)
s = Solution()
res = []
#s.InorderTree(t1)
tree = s.InExpTree(data) # 中缀表达式生成二叉树
s.InorderTree(tree)
res = map(str, res)
print(''.join(res))
draw(tree)
有什么问题可以在评论区交流
结束!!!
————————————更新啦———————————————
给这个程序添加了字符串分割函数和检查谓词表达式错误的函数
字符串分割函数
def SplitString(data):
yub = list()
#这个只能一位一位的处理
i = 0
while(i < (len(data))):
if ord(data[i]) >= 65 and ord(data[i]) <= 90:
#记录跟着谓词符号后面的部分有多长
#要找第(函数个数+1)个右括号
j = i+1
length = 0#记录谓词符号后面部分的长度
count = 0#记录谓词符号内部函数的个数
num = 0#记录这是当前第几个右括号
while (data[j-1]==')' and num==count+1)!=True:
if ord(data[j])>=97 and ord(data[j])<=122 and data[j+1]=='(':
count = count+1
elif data[j]==')':
num = num+1
j = j+1
length = length+1
print('length ',length)
temp = ''
for k in range(length+1):
temp = temp + data[i+k]
print('temp', temp)
yub.append(temp)
i = i + length +1
elif (data[i] == '&') or (data[i] == '%') or (data[i] == '-'):
yub.append(data[i] + data[i+1])
i = i+2
else: #(data[i] == '(') or (data[i] == ')') or (data[i] == '&') or (data[i] == '|') or (data[i] == '!'):
yub.append(data[i])
i = i+1
return yub