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

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

问题

已知一棵二叉树所有的节点值都不同,给定先序和中序序列,不重建二叉树,生成后序序列。如:
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

``` #include <stdio.h> #include <stdlib.h> /* 二叉树结点结构体定义 */ struct TreeNode { int val; // 节点存储的值 struct TreeNode *left; // 左子树指针 struct TreeNode *right; // 右子树指针 }; /** * @brief 递归创建二叉树(方式创建) * @return 返回创建完成的二叉树根节点指针 * @note 入时使用-1表示空节点 */ struct TreeNode* createTree() { int value; printf("请入节点值(-1表示空): "); scanf("%d", &value); if (value == -1) { return NULL; // 空节点 } // 创建新节点 struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode)); node->val = value; printf("创建 %d 的左子节点\n", value); node->left = createTree(); // 递归创建左子树 printf("创建 %d 的右子节点\n", value); node->right = createTree(); // 递归创建右子树 return node; } /** * @brief 递归实现中历 * @param root 当前历的二叉树节点指针 * @param res 存储历结果的数组指针 * @param resSize 记录数组当前长度的指针(需要修改外部变量故使用二级指针) */ void inorder(struct TreeNode* root, int* res, int* resSize) { if (!root) return; inorder(root->left, res, resSize); // 1.递归历左子树 res[(*resSize)++] = root->val; // 2.将当前节点值存入数组 inorder(root->right, res, resSize); // 3.递归历右子树 } /** * @brief 二叉树的中历入口函数 * @param root 二叉树根节点指针 * @param returnSize 返回数组长度的指针(通过地址修改外部变量) * @return 返回存储历结果的数组指针 */ int* inorderTraversal(struct TreeNode* root, int* returnSize) { int* res = (int*)malloc(sizeof(int) * 501); // 分配最大501元素的数组空间 *returnSize = 0; // 初始化数组长度为0 inorder(root, res, returnSize); // 执行中历 return res; } /** * @brief 释放二叉树内存(后历方式释放) * @param root 二叉树根节点指针 */ void freeTree(struct TreeNode* root) { if (!root) return; freeTree(root->left); // 递归释放左子树 freeTree(root->right); // 递归释放右子树 free(root); // 释放当前节点 } int main() { // 创建二叉树 printf("创建二叉树(示例入:1 -1 2 3 -1 -1 -1)\n"); struct TreeNode* root = createTree(); // 执行中历 int size = 0; int* result = inorderTraversal(root, &size); // 出结果 printf("\n中历结果: ["); for (int i = 0; i < size; ++i) { printf("%d", result[i]); if (i != size - 1) printf(", "); } printf("]\n"); // 释放内存 freeTree(root); free(result); return 0; }```我希望控制台中,入root数组的内容,回车就能直接出中历的结果,不需要创建这个二叉树
最新发布
04-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值