一阶谓词表达式转二叉树 Python

一阶谓词表达式转二叉树 Python

因为遇到了这个问题,但是并没有找到相关的资料参考,所以写了这篇文章,给有这个问题的小伙伴提供参考

原理类似于中缀表达式转二叉树,把运算符的优先级换掉就可以了

但是谓词表达式要注意三个运算符﹁,∃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
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值