最近在刷剑指offer上面的习题,但是发现好像目前网上用python写的比较详细的教程不多。所以写下这篇文章供大家参考,特别适用于新手。如有好的提议,欢迎提出。对了,转载请注明作者出处,我叫米行老板,谢谢。
# 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历
和中序遍历的结果中都不含重复的数字。
# 例如:前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},
# 重建出上图所示的二叉树并输出它的头结点。
class Node:
def __init__(self, value):
self.value = value # 当前节点的值
self.left = None # 左子节点
self.right = None # 右子节点
class Solution:
def rebuild(self, pre_, in_):
"""
重建二叉树
:param pre_: 前序遍历序列
:param in_: 中序遍历序列
:return: 建好后的二叉树的头节点
"""
# 如果递归到最后,数组为空,则说明该子树为空
if len(pre_) == 0:
return None
# 如果递归到最后,数组中只剩一个元素,则返回该元素
elif len(pre_) == 1:
return Node(pre_[0])
# 如果还未迭代到只剩一个元素或空数组,则进行递归
else:
# 构建目标二叉树的根节点(前序遍历次序:中,左,右)
cur = Node(pre_[0])
# 获取前序序列中的第一个元素值,该值为目标二叉树的根节点的值
root = pre_[0]
# 从中序序列中获取目标二叉树的根节点的索引,作为二叉树的分割点
pivot = in_.index(root)
# [1, 2, 4, 7, 3, 5, 6, 8]
# ↑
# 根节点的值
# [4, 7, 2, 1, 5, 3, 8, 6]
# ↑
# 根节点的值
# 左边为左子树的值,右边为右子树的值
# 如上方示例所示
# 从第【二】个元素到根节点的下标位置,为【前序序列】的【左子树】部分
pre_left = pre_[1:pivot + 1]
# 从第【一】个元素到根节点的下标位置,为【中序序列】的【左子树】部分
in_left = in_[:pivot]
# 左子树开始递归,递归返回值记录为【左子节点】
cur.left = self.rebuild(pre_left, in_left)
# 从【根节点】的下标位置到数组结尾,为【前序序列】的【右子树】部分
pre_right = pre_[pivot + 1:]
# 从根节点的下标位置到数组结尾,为【中序序列】的【右子树】部分
in_right = in_[pivot + 1:]
# 右子树开始递归,递归返回值记录为【右子节点】
cur.right = self.rebuild(pre_right, in_right)
return cur
def traverse(self, root):
"""
层序遍历
:param root: 二叉树的根节点
:return:
"""
# 将根节点存入队列
queue = [root]
# 如果根节点中仍有元素
while queue:
# 取出队列中第一个元组
cur = queue.pop(0)
# 打印当前值
print(cur.value, end=' ')
# 如果存在左子树,则将左子树加入队列
if cur.left:
queue.append(cur.left)
# 如果存在右子树,则将右子树加入队列
if cur.right:
queue.append(cur.right)
def pre_order(self, root):
"""
先序遍历(打印顺序:根节点 → 左子树 → 右子树)
:param root: 二叉树的根节点
:return:
"""
# 如果根节点不为空
if root:
# 先打印根节点的值
print(root.value, end=' ')
# 如果左子节点存在,则左子节点进入递归,成为下一级的根节点
if root.left:
self.pre_order(root.left)
# 如果右子节点存在,则右子节点进入递归,成为下一级的根节点
if root.right:
self.pre_order(root.right)
def in_order(self, root):
"""
中序遍历(打印顺序:左子树 → 根节点 → 右子树)
:param root: 二叉树的根节点
:return:
"""
# 如果根节点不为空
if root:
# 如果左子节点存在,则左子节点进入递归,成为下一级的根节点
if root.left:
self.in_order(root.left)
# 当前节点的值,作为根节点被打印
print(root.value, end=' ')
# 如果右子节点存在,则右子节点进入递归,成为下一级的根节点
if root.right:
self.in_order(root.right)
def post_order(self, root):
"""
后序遍历(打印顺序:左子树 → 右子树 → 根节点)
:param root: 二叉树的根节点
:return:
"""
# 如果根节点不为空
if root:
# 如果左子节点存在,则左子节点进入递归,成为下一级的根节点
if root.left:
self.post_order(root.left)
# 如果右子节点存在,则右子节点进入递归,成为下一级的根节点
if root.right:
self.post_order(root.right)
# 当前节点的值,作为根节点被打印
print(root.value, end=' ')
def examine(solution, result):
"""
检验函数
:param solution: 测试类对象
:param result: 被测试的二叉树
:return:
"""
# 层序遍历
print("Traverse:")
solution.traverse(result)
print()
# 前序遍历
print("Pre-order: ")
solution.pre_order(result)
print()
# 中序遍历
print("In-order: ")
solution.in_order(result)
print()
# 后序遍历
print("Post-order: ")
solution.post_order(result)
def main():
s = Solution()
# 前序序列
pre_list = [1, 2, 4, 7, 3, 5, 6, 8]
# 中序序列
in_list = [4, 7, 2, 1, 5, 3, 8, 6]
# 基于前序与中序序列重构二叉树
result = s.rebuild(pre_list, in_list)
# 检验结果
examine(s, result)
if __name__ == "__main__":
main()
输出结果:
traverse:
1 2 3 4 5 6 7 8
pre-order:
1 2 4 7 3 5 6 8
in-order:
4 7 2 1 5 3 8 6
post-order:
7 4 2 5 8 6 3 1