根据任意两种遍历(前序、中序、后序)构造完整二叉树

#! /usr/bin/env python
# -*- coding: utf-8 -*-

'''
遍历推算
根据前序+中序/前序+后序/中序+后序重建二叉树
'''

import operator

pre_list_result = []
inorder_list_result = []
postorder_list_result = []


class Node:
    def __init__(self, data, left, right):
        self.data = data
        self.left = left
        self.right = right


def pre_travel(Node):
    if Node:
        # print(Node.data, end=',')
        pre_list_result.append(Node.data)
        pre_travel(Node.left)
        pre_travel(Node.right)


def inorder_travel(Node):
    if Node:
        inorder_travel(Node.left)
        # print(Node.data, end=',')
        inorder_list_result.append(Node.data)
        inorder_travel(Node.right)


def postorder_travel(Node):
    if Node:
        postorder_travel(Node.left)
        postorder_travel(Node.right)
        # print(Node.data, end=',')
        postorder_list_result.append(Node.data)


def construct_tree(order_one, order_two, travel_type):
    # 参数合法性判断
    if len(order_one) == 0 | len(order_two) == 0:
        return None
    # 参数为前序和中序, 用来求后序
    if "postorder" == travel_type:
        # 前序遍历的第一个结点一定是根结点
        root_data = order_one[0]
        L = order_two.index(root_data)
        # 递归构造左子树和右子树
        left = construct_tree(order_one[1: 1 + L], order_two[:L], "postorder")
        right = construct_tree(order_one[1 + L:], order_two[L + 1:], "postorder")
        return Node(root_data, left, right)
    # 参数为前序和后序, 用来求中序
    elif "inorder_travel" == travel_type:
        if not order_one:
            return None
        root_data = order_one[0]
        if len(order_one) == 1:
            return Node(root_data, None, None)
        L = order_two.index(order_one[1]) + 1
        # 递归构造左子树和右子树
        left = construct_tree(order_one[1: 1 + L], order_two[:L], "inorder_travel")
        right = construct_tree(order_one[1 + L:], order_two[L:-1], "inorder_travel")
        if (L == 1):
            if None != left and left.data > root_data:
                right = Node(left.data, None, None)
                left = None
            if None != right and right.data < root_data:
                left = Node(right.data, None, None)
                right = None
        return Node(root_data, left, right)
    # 参数为中序和后序, 用来求前序
    elif "pre_travel" == travel_type:
        root_data = order_two[-1]
        L = order_one.index(root_data)
        # 递归构造左子树和右子树
        left = construct_tree(order_one[:L], order_two[:L], "pre_travel")
        right = construct_tree(order_one[L + 1:], order_two[L:-1], "pre_travel")

        return Node(root_data, left, right)
    else:
        print("参数错误")


if __name__ == '__main__':
    pre_list = [2169, 1049, 832, 56, 620, 974, 947, 1474, 1473, 1714, 1969, 2552, 2454, 2440, 2510, 3133, 2734, 2885,
                3281, 3632]
    inorder_list = [56, 620, 832, 947, 974, 1049, 1473, 1474, 1714, 1969, 2169, 2440, 2454, 2510, 2552, 2734, 2885,
                    3133, 3281, 3632]
    postorder_list = [620, 56, 947, 974, 832, 1473, 1969, 1714, 1474, 1049, 2440, 2510, 2454, 2885, 2734, 3632, 3281,
                      3133, 2552, 2169]
    # root = construct_tree(pre_list, inorder_list, "postorder")
    # postorder_travel(root)
    # print(postorder_list_result)
    # print(operator.eq(postorder_list,postorder_list_result))

    root = construct_tree(pre_list, postorder_list, "inorder_travel")
    inorder_travel(root)
    print(inorder_list_result)
    print(operator.eq(inorder_list, inorder_list_result))

    # root = construct_tree(inorder_list, postorder_list, "pre_travel")
    # pre_travel(root)
    # print(pre_list_result)
    # print(operator.eq(pre_list, pre_list_result))

原理为前序的第一个节点即为根节点, 然后去中序遍历中找到根节点, 根节点的左边即为左子树的中序遍历, 右边即为右子树的中序遍历, 获取左子树的长度, 用它再去前序遍历中得到左子树和右子树的前序遍历。后序遍历和中序遍历同样如此,唯一的区别在于根节点在后序遍历中是最后一个元素。

与上述不同,略显复杂的为前序遍历和后序遍历构造二叉树,我们已知前序遍历的第一个节点为根节点,第二个节点为左子树的根节点,在后序遍历里获取左子树根节点的位置, 即可得到左子树的长度, 再依次递归即可,需要注意的是当子树的高度为1时,需要按照节点值判断, 是否需要进行左右子树互换,不然默认下单节点树的节点永远都是左儿子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值