面试题36.二叉搜索树与双向链表

  • 题目
  • 解题思路
  • 代码

题目

  • 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
  • 我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
  • 特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

P.S. 完整题目来源于leetcode

解题思路

由题意知,需进行中序遍历得到顺序排列的循环双向链表。
需要注意的是,head是树的最左侧元素,即中序遍历回溯的第一个元素,需要从中序遍历中得到。同时需要precur节点,在中序遍历结束时,cur只想None,而pre指向末尾元素。中序遍历时,将pre的右节点设为cur,将cur的左节点设为pre,从而形成双向链表。在中序遍历结束,使得head的左节点为prepre的右节点为head,从而得到循环链表。
Code-Structure:

DFS(cur):

  • 递归基:
  • 节点curNone,则return
  • 左递归:
  • DFS(cur.left)
  • 处理根节点(cur):
  • self.preNone时,为中序遍历达到最左侧的节点,保存为self.head
  • self.pre不为None时,更改curself.pre指针得到双向链表。
  • 更新self.pre,最后指向末节点。
  • 右递归:
  • DFS(cur.right)

Main:

  • 特判:if not root: return None
  • 初始化self.preNone
  • 中序遍历得到双向链表,self.preself.head
  • self.preself.head得到循环链表
  • 返回self.head

P.S.图解可参看这篇文章

代码

"""
# 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)#left
            #处理root:构建链表
            if self.pre:#pre节点是否已经记录,不为None时修改指针得到双向链表
                self.pre.right = cur 
                cur.left = self.pre
            else:#pre节点为None,记录头结点(为得到循环链表)
                self.head = cur
            self.pre = cur#依次处理下个节点
            DFS(cur.right)#right
        
        if not root: return None#递归基
        self.pre = None
        DFS(root)#中序遍历
        self.head.left = self.pre#得到循环链表
        self.pre.right = self.head
        return self.head