剑指offer 36 - 二叉搜索树和双向链表 - python

132 阅读3分钟

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

题目描述:

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

为了让您更好地理解问题,以下面的二叉搜索树为例:


在这里插入图片描述

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。


在这里插入图片描述

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。


二叉搜索树可分为根节点、左子树和右子树,在把左、右子树转换成排序的双向链表后再和根节点链接起来,整棵搜索二叉树就转换成了排序的双向链表。因此这个过程可以分为两个阶段:

  • 将左、右子树转换为双向排序链表
  • 将左、右子树的转换链表和其对应的根节点链接

整个过程通过可以递归进行。


在这里插入图片描述

中序遍历法:从上图转换后得到得双向链表可以看出,链表中元素得排列就是二叉树中序遍历后得结果。因此,当得到中序遍历后的结果,我们只需要做的是从第一个节点( i = 1 i = 1 i=1)开始,将第 i + 1 i + 1 i+1个结点作为第 i i i个结点的left,将第i个结点作为第 i + 1 i+1 i+1个结点的right,不断操作直到最后 i i i。

class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
    
        if not root: return
        flag = False
        self.r = []
        head, cur = None, None
        def helper(root):
            if not root: return 

            helper(root.left)
            self.r.append(root.val)
            helper(root.right)

        helper(root)
        for i in self.r:
            node = Node(i)
            if flag == False:
                head = node
                flag = True 
                cur = node 
            else:
                cur.right = node
                node.left = cur
                cur = node
        
        cur.right, head.left = head, cur
        return head

但上述的方法是先使用中序遍历获取树中节点的值,然后再构建双向循环链表,这样做分为了两步完成,而且还使用了额外的存储空间。如果想要实现就地转换,可以借助上面方法的思想完成,代码如下:

class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
    
        if not root: return
        self.flag = False
        self.head, self.pre = None, None

        def helper(root):
            if not root: return
            # 左
            helper(root.left)
            # 根
            if not self.flag:
            	# 如果是链表的第一个节点
                self.head = root
                self.flag = True
            else:
                self.pre.right = root
                root.left = self.pre
            self.pre = root
            # 右
            helper(root.right)
        
        helper(root)
        self.head.left = self.pre
        self.pre.right =  self.head
        return self.head