目录
前言
数据结构,树,递归是其核心;
题解代码
对于该题的解答,给出python代码如下(后续补充Java和C):
文件名为:for_preorder.py
res = []
def preorder_from_in_and_post(inorder, postorder):
if len(inorder) == len(postorder) == 1:
res.append(inorder[0])
if len(inorder) == len(postorder) == 2:
res.append(postorder[-1])
res.append(postorder[0])
if len(inorder) == len(postorder) >= 3:
head = postorder[-1]
idx = inorder.index(head)
res.append(head)
preorder_from_in_and_post(inorder[0:idx], postorder[0:idx])
preorder_from_in_and_post(inorder[idx + 1:], postorder[idx:-1])
# preorder_from_in_and_post(
# [200, 323, 990, 463, 154, 673, 927, 703, 873, 174, 473, 997, 983, 460, 85, 513, 56, 416, 981, 563],
# [200, 323, 463, 154, 990, 673, 703, 174, 873, 983, 997, 473, 85, 513, 416, 563, 981, 56, 460, 927])
# print('{} {}'.format('先序:', res))
# 中序:200, 323, 990, 463, 154, 673, 927, 703, 873, 174, 473, 997, 983, 460, 85, 513, 56, 416, 981, 563
# 后序:200, 323, 463, 154, 990, 673, 703, 174, 873, 983, 997, 473, 85, 513, 416, 563, 981, 56, 460, 927
# 先序:927, 673, 990, 323, 200, 154, 463, 460, 473, 873, 703, 174, 997, 983, 56, 513, 85, 981, 416, 563
核心点解析
1.后序遍历的最后一个数字,是整棵树的头节点head;
2.以head切割中序遍历,head左边序列必定为左子树,head右边序列必定为右子树;
3.先序遍历顺序:头 -> 左 -> 右;
4.递归含义/函数含义:找出当前序列的头节点;
5.将目标序列(中序,后序)传进递归函数,目标序列将被分成2个子序列,即左子树和右子树
此时,将左子树先传进递归函数,再将右子树传进递归函数;
变成了,求2个子树序列的头节点;
大规模问题,借由递归,变成一个个子问题,子问题的解决变得越来越简单;
6.由于左子树先进入递归函数,右子树后进入递归函数,并且递归前,已经获取当前头节点;
所以天然符合,头 -> 左 -> 右的顺序;即先序;
此时,无论是直接打印,还是先存入列表,最后都可以得到目标序列的先序遍历;
验证
接下来是验证:
1.对数器验证:
此处使用的对数器逻辑是:用代码构造二叉树(构造的树可能是完全二叉树,也可能不是),利用正常的递归逻辑获取中序/后序/先序遍历;
将上一个步骤的中序/后序遍历传入解答代码中,得出先序遍历,并和上一步骤的先序遍历,进行对比;
2.二叉树构造代码(文件名为:create_tree.py):
import random
class TreeNode:
def __init__(self):
self.data = None
self.left = None
self.right = None
# 树生成伪代码:
# init head
# insert head into stack: target
# candidates = new stack: target
# while length(node_data) > 0:
# while stack: target.length > 0:
# node = stack: target.pop()
# node.data = node_data.pop()
# node.left = new TreeNode
# node.right = new TreeNode
# insert node.left into candidates
# insert node.right into candidates
# stack: target = candidates #随机取candidates中的元素
# candidates = new stack: target
# 构造对数器
def createTree(head):
node_data = random.sample(list(range(1, 1001)), 20)
target = [head]
candidates = []
while len(node_data) > 0:
while len(target) > 0:
node = target.pop()
node.data = node_data.pop()
if len(node_data) == 0:
break
node.left = TreeNode()
node.right = TreeNode()
candidates.append(node.left)
candidates.append(node.right)
target = random.sample(candidates, round(random.uniform(0.75, 1) * len(candidates)))
candidates.clear()
inorder = []
postorder = []
preorder = []
def get_inorder(head):
if head and head.left:
get_inorder(head.left)
if head and head.data:
inorder.append(head.data)
if head and head.right:
get_inorder(head.right)
def get_postorder(head):
if head and head.left:
get_postorder(head.left)
if head and head.right:
get_postorder(head.right)
if head and head.data:
postorder.append(head.data)
def get_preorder(head):
if head and head.data:
preorder.append(head.data)
if head and head.left:
get_preorder(head.left)
if head and head.right:
get_preorder(head.right)
# init_head = TreeNode()
# createTree(init_head)
# get_inorder(init_head)
# get_postorder(init_head)
# get_preorder(init_head)
# print('{} {}'.format('中序:', inorder))
# print('{} {}'.format('后序:', postorder))
# print('{} {}'.format('先序:', preorder))
3.测试(文件名为main_test.py):
进行10万次测试,发现每一次对比结果,都是一致的,确认算法正确性;
from create_tree import *
from for_preorder import *
flag = True
for i in range(100000):
init_h = TreeNode()
createTree(init_h)
get_inorder(init_h)
get_postorder(init_h)
get_preorder(init_h)
preorder_from_in_and_post(inorder, postorder)
if res != preorder:
print("false!!!")
flag = False
res.clear()
inorder.clear()
postorder.clear()
preorder.clear()
if flag:
print("finish!!!")
执行结果如下:
总结
构造对数器,进行验证;理解树的递归,活用树的递归。