二叉树
本博文仅用作个人学习的记录,包含个人学习过程的一些思考,想到啥写啥,因此有些东西阐述的很罗嗦,逻辑可能也不清晰,看不懂的且当作是作者的呓语,自行跳过即可。
二叉树是一种数据结构,和链表一样:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
遍历包括前序、中序、后序遍历三种。
前序:根->左->右 (根->左->左->左(一直到最左)…->右)
中序:左->根->右(最左->上级根->右)
后序:左->右->根(最左->右的最左(如果右存在子树)->右的最左(直到右不存在子树)…->上级根)
必须已知中序遍历和一个其他遍历,才能求出剩下的遍历。
重建二叉树
代表题型:剑指offer 第4题
-
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 -
代码
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
if not pre or not tin:
return None
# 由前序确定根节点,定位根结点在中序遍历的坐标
root = TreeNode(pre.pop(0))
index = tin.index(root.val)
# 中序遍历根结点左边是左树,右边是右树
root.left = self.reConstructBinaryTree(pre, tin[:index])
root.right = self.reConstructBinaryTree(pre, tin[index + 1:])
return root
- 解析
这是由前序和中序重构二叉树的题型,并且树中没有重复值。通过递归实现,函数只需要实现一次分类即可:
- 由前序遍历确定根结点
- 在中序遍历中找到根节点
- 中序遍历中根结点左边为左子树,右边为右子树
- 问题
如果树中存在相同值怎么办?
树的子结构
代表题型:剑指offer 第17题
-
题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) -
代码
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
if pRoot1 and pRoot2:
if self.IsSubtree(pRoot1,pRoot2):
return True
return self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)
else:
return False
def IsSubtree(self, pRoot1, pRoot2):
if pRoot1 and pRoot2:
if pRoot1.val == pRoot2.val:
return self.IsSubtree(pRoot1.left,pRoot2.left) and self.IsSubtree(pRoot1.right,pRoot2.right)
else:
return False
return True if pRoot2 == None else False
-
解析
这个问题主要拆分成两个部分,一个是将B的根结点和A的所有结点进行判断,看是否有相等的值;若相等,则判断是否所有子结点都相等。 -
小结
不知道是否有更巧妙简洁的解法,之后二刷三刷的时候再更新。
有空再学习一下Python的代码简写,短而快!emmm 程序员的追求是又短又快???!!!
镜像二叉树
代表题型:剑指offer 第18题
- 题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
二叉树的镜像定义:
源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
- 代码
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
if root and (root.left or root.right):
root.left, root.right = root.right, root.left
if root.left:
self.Mirror(root.left)
if root.right:
self.Mirror(root.right)
return root
-
解析
首先判断树是否非空,是否存在左或右子树;
交换左右子树;
若存在左(右)子树,递归左(右)子树;
返回根节点。 -
小结
这题还是比较简单的,需要注意的是题目多数时候的输入都不一定是有值的,多数都是包含边界情况,因此在写主函数前需要先确定边界问题,不然容易不知道错哪了。
从上至下打印二叉树
代表题型:剑指offer 第22题
-
题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。 -
代码
class Solution:
def PrintFromTopToBottom(self, root):
tree = []
treeroot = [root]
for item in treeroot:
if item:
tree.append(item.val)
if item.left:
treeroot.append(item.left)
if item.right:
treeroot.append(item.right)
return tree
- 解析
首先分析第一层,对于当前的根结点root,可以直接输出它的值root.val
root
/ \
left right
对于第二层,left和right就相当于两个新的root,和原先的root之间除了数量没有别的区别,因此在循环中,我们需要有一个能够灵活存放树的根节点的结构,也就是一个存放root的list。
由于list的可变性,因此判断当前根节点是否存在左(右)子树,若存在就添加在原列表末尾。
由于没有删除treeroot中的值,最后treeroot中存放的应该是由上而下,从左到右,树的所有结点。