通过先序和中序数组生成后续数组

通过先序和中序数组生成后续数组

问题

已知一棵二叉树所有的节点值都不同,给定先序和中序序列,不重建二叉树,生成后序序列。如:
preorder: 1 2 4 5 3 6 7
inorder: 4 2 5 1 6 3 7
=>
postorder: 4 5 2 6 7 3 1

思路

preorder: 1 2 4 5 3 6 7
inorder: 4 2 5 1 6 3 7
先序序列的第一个值肯定是根节点,从中序序列找到这个值(二叉树所有节点值不相同为前提),则中序序列中,根节点左边的4 2 5是左子树,右边的6 3 7是右子树。递归求解即可

def pre_order_in_order_to_post_order1(preorder, inorder):
    def get_post_order(preorder, inorder):
        if not preorder or not inorder:
            return []

        root = preorder[0]
        index = inorder.index(root)

        left = get_post_order(preorder[1:index+1], inorder[:index])
        right = get_post_order(preorder[index+1:], inorder[index+1:])
        return left + right + [root]

    if len(preorder) != len(inorder):
        raise Exception('Error')

    return get_post_order(preorder, inorder)

优化:加快查找根节点在中序序列中位置,可以用字典记录

def pre_order_in_order_to_post_order2(preorder, inorder):
    def get_post_order(pre_beg, pre_end, in_beg, in_end):
        if pre_beg >= pre_end or in_beg >= in_end:
            return []

        root = preorder[pre_beg]
        index = index_of_inorder[root]

        left = get_post_order(pre_beg+1, pre_beg+index-in_beg+1, in_beg, index)
        right = get_post_order(pre_beg+index-in_beg+1, pre_end,
                               index+1, in_end)
        return left + right + [root]

    if len(preorder) != len(inorder):
        return None

    index_of_inorder = {v: k for k, v in enumerate(inorder)}
    return get_post_order(0, len(preorder), 0, len(inorder))

剩下一个值时可以结束递归:

def pre_order_in_order_to_post_order3(preorder, inorder):
    def get_post_order(pre_beg, pre_end, in_beg, in_end):
        if pre_end - pre_beg != in_end - in_beg:
            raise Exception('Error index')

        if pre_beg >= pre_end:
            return []

        if pre_end - pre_beg == 1:
            return [preorder[pre_beg]]

        root = preorder[pre_beg]
        index = index_of_inorder[root]

        left = get_post_order(pre_beg+1, pre_beg+index-in_beg+1, in_beg, index)
        right = get_post_order(pre_beg+index-in_beg+1, pre_end,
                               index+1, in_end)
        return left + right + [root]

    if len(preorder) != len(inorder):
        return None

    index_of_inorder = {v: k for k, v in enumerate(inorder)}
    return get_post_order(0, len(preorder), 0, len(inorder))

测试方法

借用之前的二叉搜索树,随机生成一棵二叉搜索树,然后遍历得到先序、中序、后序序列,然后对照求出的后序序列跟遍历的后序序列。

测试用例

Binary Search Tree

class TreeNode():
    def __init__(self, key, val):
        self.key = key
        self.val = val
        self.left = None
        self.right = None


class BinarySearchTree():
    def __init__(self):
        self.root = None

    def __eq__(self, rhs):
        def recursive(lhs, rhs):
            if lhs is None:
                return rhs is None

            if rhs is None:
                return lhs is None

            if lhs.key != rhs.key or lhs.val != rhs.val:
                return False

            left_eq = recursive(lhs.left, rhs.left)
            right_eq = recursive(lhs.right, rhs.right)
            return left_eq and right_eq

        return recursive(self.root, rhs.root)

    def insert_recursive(self, key, val):
        def recursive(node, key, val):
            if not node:
                return TreeNode(key, val)

            if key < node.key:
                node.left = recursive(node.left, key, val)
            elif key > node.key:
                node.right = recursive(node.right, key, val)

            return node

        self.root = recursive(self.root, key, val)

    def insert_non_recursive(self, key, val):
        node = TreeNode(key, val)
        if not self.root:
            self.root = node
            return

        parent = None
        cur = self.root
        while cur:
            parent = cur
            if key < cur.key:
                cur = cur.left
            elif key > cur.key:
                cur = cur.right
            else:
                cur.val = val
                return

        if key < parent.key:
            parent.left = node
        else:
            parent.right = node

    def inorder_traversal_recursive(self):
        def recursive(node):
            if node:
                recursive(node.left)
                result.append(node.key)
                recursive(node.right)

        result = []
        recursive(self.root)
        return result

    def inorder_traversal_non_recursive(self):
        result = []
        if not self.root:
            return result

        node = self.root
        stack = []
        while stack or node:
            if node:
                stack.append(node)
                node = node.left
            else:
                node = stack.pop()
                result.append(node.key)
                node = node.right

        return result

    def preorder_traversal_recursive(self):
        def recursive(node):
            if node:
                result.append(node.key)
                recursive(node.left)
                recursive(node.right)

        result = []
        recursive(self.root)
        return result

    def preorder_traversal_non_recursive(self):
        result = []
        if not self.root:
            return result

        stack = [self.root]
        while stack:
            node = stack.pop()
            result.append(node.key)
            if node.right:
                stack.append(node.right)
            if node.left:
                stack.append(node.left)

        return result

    def postorder_traversal_recursive(self):
        def recursive(node):
            if node:
                recursive(node.left)
                recursive(node.right)
                result.append(node.key)

        result = []
        recursive(self.root)
        return result

    def postorder_traversal_non_recursive1(self):
        result = []
        if not self.root:
            return result

        stack1 = [self.root]
        stack2 = []
        while stack1:
            node = stack1.pop()
            stack2.append(node)

            if node.left:
                stack1.append(node.left)
            if node.right:
                stack1.append(node.right)

        while stack2:
            result.append(stack2.pop().key)

        return result

    def postorder_traversal_non_recursive2(self):
        result = []
        if not self.root:
            return result

        stack = [self.root]
        flag = self.root
        while stack:
            node = stack[-1]
            if node.left and node.left != flag and node.right != flag:
                stack.append(node.left)
            elif node.right and node.right != flag:
                stack.append(node.right)
            else:
                result.append(stack.pop().key)
                flag = node

        return result

Unit Test

import unittest
import random
import operator
import binary_search_tree
import pre_and_in_order_to_post_order as order


def make_random_bst(count, maxkey):
    ret = binary_search_tree.BinarySearchTree()
    keys = []
    for _ in range(count):
        k = random.randint(0, maxkey)
        v = k
        keys.append(k)
        ret.insert_recursive(k, v)
    return ret


class PreOrderInOrderToPostOrderTestCase(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_simple(self):
        preorder = [1, 2, 4, 5, 3, 6, 7]
        inorder = [4, 2, 5, 1, 6, 3, 7]
        postorder = [4, 5, 2, 6, 7, 3, 1]

        ret = order.pre_order_in_order_to_post_order3(preorder, inorder)
        self.assertTrue(operator.eq(postorder, ret))

    def test_by_make_bst_10_100(self):
        for _ in range(100):
            tree = make_random_bst(10, 100)
            preorder = tree.preorder_traversal_recursive()
            inorder = tree.inorder_traversal_recursive()
            postorder = tree.postorder_traversal_recursive()

            ret1 = order.pre_order_in_order_to_post_order1(preorder, inorder)
            ret2 = order.pre_order_in_order_to_post_order2(preorder, inorder)
            ret3 = order.pre_order_in_order_to_post_order3(preorder, inorder)

            self.assertTrue(operator.eq(postorder, ret1))
            self.assertTrue(operator.eq(postorder, ret2))
            self.assertTrue(operator.eq(postorder, ret3))

    def test_by_make_bst_100_1000(self):
        for _ in range(100):
            tree = make_random_bst(100, 1000)
            preorder = tree.preorder_traversal_recursive()
            inorder = tree.inorder_traversal_recursive()
            postorder = tree.postorder_traversal_recursive()

            ret1 = order.pre_order_in_order_to_post_order1(preorder, inorder)
            ret2 = order.pre_order_in_order_to_post_order2(preorder, inorder)
            ret3 = order.pre_order_in_order_to_post_order3(preorder, inorder)

            self.assertTrue(operator.eq(postorder, ret1))
            self.assertTrue(operator.eq(postorder, ret2))
            self.assertTrue(operator.eq(postorder, ret3))

结果

➜  22_pre_and_in_order_to_post_order git:(master) ✗ python -m unittest test_pre_and_in_order_to_post_order.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.065s

OK

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值