【python数据结构与算法】二叉树的“后继节点”(二叉树的下一个节点)、二叉树的序列化和反序列化

6 篇文章 0 订阅
3 篇文章 0 订阅

 

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了
  • 二叉树如何被序列化、反序列化?
    • 前序遍历的方式进行序列化:
    • 步骤:
      • 按照前序遍历的方式,依次向字符串追加遍历到的节点的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
        

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_illusion_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值