首先必须要理解一下前中序遍历的结果的呈现规律。
前序遍历是按照根,左子树,右子树的顺序来遍历的,那么考虑最简单的情况,只有三个节点的二叉树,他们它最后展示的结果是DLR,
因为LR都是子树,也具备这样的递归流程,那么对于前序遍历来说,D之后为L子树的遍历结果,然后才是R子树遍历结果。但很明显,如果从前序遍历列表头部持续不断的弹出,总是能得到一个head节点,另外大的层面来说,L子树的节点总是出现在R子树的节点之前
后序遍历和前序遍历有点相似,考虑最简单的情况,它最后展示的结果是LRD,
按照我们从后向前弹出的顺序来看,也总是优先弹出一个head节点,但稍有点不同的是,它总是优先弹出R子树那边的head,即R子树的节点总是出现在L子树节点的前面。
中序遍历的结果比较有意思,因为它是一个对称序,找到D的时候一般而言,左半边就是它的左子树,右半边就是它的右子树,这样推导来看,无论是前序或者后序都能很快找到一个树的D,而中序遍历恰好提供了D的左半边和右半边,递归地看,只需要不停获取D,就能在小范围的中序遍历里面找到左右子树并进行连接;另一方面,这种遍历的结果也就导致了前序和后序遍历无法确定一个唯一的二叉树,因为它没法区分左半边和右半边。
按照上一节说过的二叉树进行复原,当然了,首先得写一个校验服务,校验复原操作是否成功而不需要一个个检查
1 #-*- coding:utf-8 -*- 2 3 4 class BinaryTree(object): 5 6 @staticmethod 7 def check_same(t1, t2): 8 if t1 is None and t2 is None: 9 return True 10 if t1 and t2 and t1.val == t2.val and BinaryTree.check_same(t1.left, t2.left) and \ 11 BinaryTree.check_same(t1.right, t2.right): 12 return True 13 return False 14 15 16 if __name__ == '__main__': 17 tree_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', '#', 'H', '#', 'I', 'J', 'K'] 18 bt = BinaryTree(tree_list) 19 bt2 = BinaryTree(tree_list) 20 bt2.bt.left = None 21 print bt.check_same(bt.bt, bt2.bt)
首先分别给出三个遍历的结果,然后分别以前序+中序,后序+中序遍历的进行复原操作:
1 #-*- coding:utf-8 -*- 2 3 4 class TreeNode(object): 5 def __init__(self, val=None, l=None, r=None): 6 self.val = val 7 self.left = l 8 self.right = r 9 10 11 class BinaryTree(object): 12 13 def __init__(self, tree_list): 14 self.bt = self.build_tree(tree_list, 0) 15 16 def build_tree(self, tree_list, i): 17 if i < len(tree_list): 18 if tree_list[i] == '#': 19 return None 20 t = TreeNode(tree_list[i]) 21 t.left = self.build_tree(tree_list, 2 * i + 1) 22 t.right = self.build_tree(tree_list, 2 * i + 2) 23 return t 24 return None 25 26 @staticmethod 27 def check_same(t1, t2): 28 if t1 is None and t2 is None: 29 return True 30 if t1 and t2 and t1.val == t2.val and BinaryTree.check_same(t1.left, t2.left) and \ 31 BinaryTree.check_same(t1.right, t2.right): 32 return True 33 return False 34 35 @staticmethod 36 def recover_bt_from_pre_and_in(pre_order, in_order): 37 in_order_map = {} 38 for i, ch in enumerate(in_order): 39 in_order_map[ch] = i 40 41 def helper(start, end): 42 if start > end: 43 return 44 root_val = pre_order.pop(0) 45 root = TreeNode(root_val) 46 root_idx = in_order_map[root_val] 47 root.left = helper(start, root_idx - 1) 48 root.right = helper(root_idx + 1, end) 49 return root 50 return helper(0, len(pre_order) - 1) 51 52 @staticmethod 53 def recover_bt_from_post_and_in(post_order, in_order): 54 in_order_map = {} 55 for i, ch in enumerate(in_order): 56 in_order_map[ch] = i 57 58 def helper(start, end): 59 if start > end: 60 return 61 root_val = post_order.pop() 62 root = TreeNode(root_val) 63 root_idx = in_order_map[root_val] 64 root.right = helper(root_idx + 1, end) 65 root.left = helper(start, root_idx - 1) 66 return root 67 return helper(0, len(post_order) - 1) 68 69 70 if __name__ == '__main__': 71 tree_list = ['A', 'B', 'C', 'D', 'E', 'F', 'G', '#', 'H', '#', 'I', 'J', 'K'] 72 bt = BinaryTree(tree_list) 73 pre_order = ["A", "B", "D", "H", "E", "I", "C", "F", "J", "K", "G"] 74 in_order = ["D", "H", "B", "E", "I", "A", "J", "F", "K", "C", "G"] 75 post_order = ["H", "D", "I", "E", "B", "J", "K", "F", "G", "C", "A"] 76 bt2 = bt.recover_bt_from_pre_and_in(pre_order, in_order) 77 bt3 = bt.recover_bt_from_post_and_in(post_order, in_order) 78 # bt2 = BinaryTree(tree_list) 79 # bt2.bt.left = None 80 print bt.check_same(bt.bt, bt2) 81 print bt.check_same(bt.bt, bt3)
结果是:
1 /Users/kielchan/PycharmProjects/untitled1/venv/bin/python /Users/kielchan/PycharmProjects/untitled1/venv/binarytree.py 2 True 3 True 4 5 Process finished with exit code 0
前序+中序的复原过程如之前描述,实际上中序遍历提供了左右子树的划分,前序遍历返回了左子树的head部,所以在递归过程中,要先求出root.left,因为pre_order在不停的pop()过程中,总是优先pop出左半边,也就是说,递归复原过程中,左子树的复原快于右子树。
同理后序+中序遍历也是如此,在后序序列pop过程中,总是先得到右子树的head,按照这个递归顺序,优先复原右子树才能正确得到复原结果。
check_same函数用于判断两棵树是否一致,结果表明,复原操作是成功的