返回

剑指 Offer 36:二叉搜索树与双向链表的深度解析

前端

一、题目

给定一个二叉搜索树,将其转化成一个双向链表。要求二叉搜索树转化后的双向链表仍旧是中序序列。

二、解题思路

解题的关键在于利用二叉搜索树的中序遍历。中序遍历的顺序是:左子树、根节点、右子树。因此,如果按照中序遍历的顺序来遍历二叉搜索树,则可以得到一个有序的序列。将该序列转换成一个双向链表即可。

1. 递归解法

一种常见的实现方法是使用递归算法。在递归函数中,首先将左子树转换成双向链表,然后将根节点连接到左子树的最后一个节点后面,最后将右子树转换成双向链表并连接到根节点后面。这样就得到了一个完整的双向链表。

2. 迭代解法

除了递归解法之外,还可以使用迭代算法来实现。迭代算法的实现方式是使用一个栈来存储当前需要处理的节点。首先将二叉搜索树的根节点压入栈中,然后依次弹出栈顶节点,将其转换成双向链表,并将其连接到已经转换好的双向链表中。这样,最终就可以得到一个完整的双向链表。

三、具体实现

1. 递归实现

def convert_bst_to_dll(root):
    if not root:
        return None

    # 将左子树转换成双向链表
    left_dll = convert_bst_to_dll(root.left)

    # 将右子树转换成双向链表
    right_dll = convert_bst_to_dll(root.right)

    # 将根节点连接到左子树的最后一个节点后面
    if left_dll:
        left_dll.right = root
        root.left = left_dll

    # 将右子树连接到根节点后面
    if right_dll:
        right_dll.left = root
        root.right = right_dll

    # 返回根节点
    return root or left_dll

2. 迭代实现

def convert_bst_to_dll(root):
    if not root:
        return None

    # 使用栈来存储需要处理的节点
    stack = [root]

    # 使用一个指针指向已经转换好的双向链表的最后一个节点
    prev = None

    # 循环处理栈中的节点
    while stack:
        # 弹出栈顶节点
        node = stack.pop()

        # 将该节点转换成双向链表
        if prev:
            prev.right = node
            node.left = prev

        # 将该节点的左子树压入栈中
        if node.left:
            stack.append(node.left)

        # 将该节点的右子树压入栈中
        if node.right:
            stack.append(node.right)

        # 更新 prev 指针
        prev = node

    # 返回已经转换好的双向链表的第一个节点
    return prev

四、时间复杂度和空间复杂度

1. 时间复杂度

递归解法和迭代解法的時間复杂度都是O(n),其中n为二叉搜索树中的节点数。这是因为这两个算法都需要遍历二叉搜索树中的所有节点。

2. 空间复杂度

递归解法的空間复杂度为O(n),因为需要使用栈来存储节点。迭代解法的空間复杂度为O(1),因为不需要使用额外的空间。

五、结语

这篇文章深入分析了剑指 Offer 36:二叉搜索树与双向链表,通过详细的讲解和示例代码,帮助读者理解如何将一个二叉搜索树转化为一个双向链表。读者可以通过这篇博客文章,进一步加深对数据结构和算法的理解。