剑指offer实践 ——36.二叉搜索树与双向链表(python版)



题目

二叉搜索树与双向链表
在这里插入图片描述
在这里插入图片描述


一、何为二叉搜索树?

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

先贴上树的定义:

class Binary_Tree():

    def __init__(self, root=None, left=None, right=None):
        self.root = root
        self.left = left
        self.right = right

二、思路一 中序遍历递归

根据二叉搜索树的特性,如果从最小的节点排序到最大的节点,可以看出对这颗二叉树是进行了中序遍历:左->根->右
在这里插入图片描述
贴上剑指offer的神图~
在这里插入图片描述

在进行指针变换的时候可以发现,每个根节点的左节点(双线链表中的前一个节点)指向了这个节点的左子树的最右节点:
在这里插入图片描述

在这里插入图片描述
每个根节点的右节点(双向链表中的后一个节点)指向了这个节点的右子树的最左节点:
在这里插入图片描述

在这里插入图片描述
显然这里可以采用中序遍历递归的思路:
有左子树的时候遍历左子树获得左子树的最小节点和最大节点
连接左子树和根节点:将左子树的最大节点指向根节点,根节点的前一个节点指向左子树的最大节点
有右子树的时候遍历右子树获得右子树的最小节点和最大节点
连接根节点和右子树:将根节点的下一个节点指向右子树的头节点,右子树的头节点前一个节点指向根节点

需要注意的情况是:
如果一个根节点只有右子树而没有左子树,此时应该判断是否有右子树,并将根节点与右子树连接后在返回

def tree_to_link_1(tree):

    def order(tree):
        if not tree:
            return None

		# 当前根节点有左子树,递归返回左子树的最小节点和最大节点
        if tree.left:
            head1, last1 = tree_to_link_1(tree.left)
            if head1 == last1:
                last1 = head1
        # 当前根节点没有左子树
        else:
            # 递归返回的条件:遍历到了树的最左边(左叶子节点/右叶子节点)
            # 当前根节点没有左子树但是有右子树
            if tree.right:
                # 获取右子树的双向链表的最小节点和最大节点
                head2, last2 = tree_to_link_1(tree.right)
                if head2 == last2:
                    last2 = head2
                # 处理根节点
                tree.right = head2
                head2.left = tree
                return tree, last2
            # 当前根节点没有左子树也没有右子树,叶子节点
            else:
                return tree, tree
        # 处理根节点
        last1.right = tree
        tree.left = last1
        # 当前根节点有右子树,递归返回右子树的最小节点和最大节点
        if tree.right:
            head2, last2 = tree_to_link_1(tree.right)
            if head2 == last2:
                last2 = head2
            tree.right = head2
            head2.left = tree
        else:
            last2 = tree
        return head1, last2

    head, last = order(tree)
    head.left = last
    last.right = head
    return head

这种方式,时间复杂度为O(N),牺牲了较大的空间来存储中间变量~

三、思路一_2 中序遍历递归(节省空间的方式)

借鉴了力扣大神的题解,空间复杂度O(N), 时间复杂度O(N)

"""
# Definition for a Node.
class Node:
    def __init__(self, val, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
"""
class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        def dfs(cur):
            if not cur: return
            dfs(cur.left) # 递归左子树
            if self.pre: # 修改节点引用
                self.pre.right, cur.left = cur, self.pre
            else: # 记录头节点
                self.head = cur
            self.pre = cur # 保存 cur
            dfs(cur.right) # 递归右子树
        
        if not root: return
        self.pre = None
        dfs(root)
        self.head.left, self.pre.right = self.pre, self.head
        return self.head
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值