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