1.二叉树的“后继节点”(二叉树的下一个节点)
剑指offer题目链接:二叉树的下一个节点
- 二叉树的后继结点定义:一棵二叉树的中序遍历中,每个节点的下一个节点称为该节点的后继结点
- 二叉树的前驱结点定义:一棵二叉树的中序遍历中,每个节点的前一个节点称为该节点的前驱结点
- 那么,如何获得一个给定节点的后继结点?注意这个节点所在的二叉树的所有节点多一条parent指针,指向自己的父节点。头结点的parent指针指向None
- 思路1(笨办法):因为给定的节点不一定是head节点,所以我们应该先通过给定节点的parent指针层层找到head节点。然后对整个二叉树进行中序遍历,从而获知给定节点的下一个节点到底是哪个节点。
- 思路2(总结的规律):
- 事实1:如果一个节点有右子树,则其后继结点就是右子树的最左节点
- 原因1:中序遍历是“左中右”顺序遍历,当遍历到当前节点,则打印的顺序应该是:该节点的全部左子树、当前节点、该节点全部右子树。所以当前节点若存在右子树,其后继结点肯定是右子树最左节点(右子树第一个被遍历到的节点)
- 例子1:1的后继结点是6;2的后继结点是5。
- 事实2:如果一个节点不存在右子树,则要寻找哪个节点的左子树以该节点结尾。寻找方法:寻找当前节点的parent指针指向的父节点。当该节点是parent指针指向的父节点的左子节点时,下一个应该打印的就是这个父节点。
- 原因2:还是因为中序遍历的“左中右”的遍历顺序:当一个节点不存在右子树,则说明这一小轮的“左中右”已经打印完,现在应将整个这一部分当做一个更高的父节点的左子树,这样,下一个打印的节点就是那个更高的父节点,这样依旧按照“左中右”顺序遍历。
- 方法2:申请两个变量:双指针cur(当前节点)parent(父节点)。当cur没有右节点,判断:cur父节点非空且cur不是parent的左子节点时:cur = cur.parent, parent = cur.parent,即cur、parent两节点都往上跳一层,继续这个循环判断,直到cur时parent的左子节点为止。最后,返回parent(parent为None,也就返回None,就说明当前节点不存在后继结点了)
- 例子2:4的后继结点是2,5的后继结点是1,7没有后继结点
- 如何获得一个节点的前驱节点?这个自己想想吧
- code见下
# -*- coding:utf-8 -*-
# class TreeLinkNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
# self.next = None
class Solution:
def GetNext(self, pNode):
# write code here
if pNode is None:
return None
if pNode.right:
pNode = pNode.right
while pNode.left:
pNode = pNode.left
return pNode
else:
parent = pNode.next
while parent and pNode != parent.left:
pNode = parent
parent = pNode.next
return parent
2.二叉树的序列化和反序列化
剑指offer题目链接:序列化二叉树
- 解释:
- 序列化:持久化,也就是说,用文件的形式,将内存中的树结构记录下来。其实也就是说,如何将一棵二叉树变成一个string
- 反序列化:将存储的文件还原成原内存中的一棵二叉树
- 举例子:
- 哈希表(dict)是如何被序列化的?
- 很简单,将dict中的key-value对一组一组记录到文件中去。反序列化的时候按顺序再放回dict中就OK了
- 哈希表(dict)是如何被序列化的?
- 二叉树如何被序列化、反序列化?
- 前序遍历的方式进行序列化:
- 步骤:
- 按照前序遍历的方式,依次向字符串追加遍历到的节点的value值和一个特殊符号(如"_")。当遇到左子节点或右子节点不存在的时候,追加#作为空占位符。
- 举例子:上面那张图中的二叉树,空为#,特殊间隔符_,序列化结果为:
- 1_2_4_#_#_5_#_#_3_#_#_6_7_#_#_
- 使用间隔符的意义:为了将每个node中的value有效分开,如1_23 vs 12_3,若无间隔符,则都变成了123;
- 使用#作为空位符的意义:当每个node的value值一样时,两棵node总数一样的结构不同的二叉树的前序遍历结果相同。此时应该用空位符来区分这两种不同的二叉树
- 前序遍历如何被反序列化?
- 步骤:
- 拿到序列化得到的字符串
- 如果遇到"#",返回None;如果没有遇到"#",将这个值
- code:
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def Serialize(self, root):
# write code here
if root is None:
return '#_'
s = str(root.val) + '_'
s += self.Serialize(root.left)
s += self.Serialize(root.right)
return s
def Deserialize(self, ss):
# write code here
ss = ss.split('_')
return self.generateTree(ss)
def generateTree(self,ss):
item = ss.pop(0)
if item == '#':
return None
node = TreeNode(int(item))
node.left = self.generateTree(ss)
node.right = self.generateTree(ss)
return node