将二叉搜索树转换成排序的双向链表:深入解析与实现 ——剑指offer - JZ36 二叉搜索树与双向链表

发布时间:2024年01月13日

目录

题目描述

知识点解析

1. 二叉搜索树(BST)

2. 双向链表

3. 中序遍历

算法实现

核心思想

具体步骤

代码实现

问题解答与讨论

尾节点的定义

尾节点的left和right属性

尾节点在二叉搜索树转换中的特性

如何找到尾节点

尾节点的应用

递归的理解

复杂度分析


题目描述

题目要求是将一个二叉搜索树转换成一个排序的双向链表,条件是不能创建任何新的节点,只能调整树中节点指针的指向。这意味着我们需要在原地进行转换,利用树的节点构建链表。

本篇题解完全参照官方,总结了一些个人感悟。

知识点解析

1. 二叉搜索树(BST)

二叉搜索树是一种特殊的二叉树,满足以下性质:每个节点的值都大于其左子树中任何节点的值,且小于其右子树中任何节点的值。这使得BST在进行中序遍历时输出的是一个有序序列。

2. 双向链表

双向链表是一种链式数据结构,其中每个节点包含数据部分和两个指向前后节点的链接。这种结构允许双向遍历:从头到尾,也可以从尾到头。

3. 中序遍历

中序遍历是一种遍历二叉树的方式,遍历顺序是左-根-右。对于BST,这种遍历方式输出的节点序列是有序的。

算法实现

核心思想

利用BST的中序遍历特性,可以按顺序访问树的所有节点。在访问每个节点时,我们将其加入到双向链表中。

具体步骤

  1. 递归遍历左子树:首先深入到最左侧节点,这是值最小的节点,也是双向链表的头部。
  2. 处理当前节点:将当前节点加入到链表中。如果前一个节点(pre)存在,则设置pre.right = current,并设置current.left = pre
  3. 递归遍历右子树:处理完当前节点后,递归地处理右子树。

代码实现

public class Solution {
    //返回的第一个指针,即为最小值,先定为null
    public TreeNode head = null;  
    //中序遍历当前值的上一位,初值为最小值,先定为null
    public TreeNode pre = null;   
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null)
            //中序递归,叶子为空则返回
            return null;     
        //首先递归到最左最小值  
        Convert(pRootOfTree.left); 
        //找到最小值,初始化head与pre
        if(pre == null){       
            head = pRootOfTree;
            pre = pRootOfTree;
        }
        //当前节点与上一节点建立连接,将pre设置为当前值
        else{       
            pre.right = pRootOfTree;
            pRootOfTree.left = pre;
            pre = pRootOfTree;
        }
        Convert(pRootOfTree.right);
        return head;
    }
}

问题解答与讨论

尾节点的定义

在双向链表中,尾节点是最后一个节点,即没有后继节点的节点。在从二叉搜索树转换成的双向链表中,尾节点是树中值最大的节点,因为二叉搜索树的特性决定了任何节点的右子树包含的值都大于该节点,所以最右侧的节点是值最大的。

尾节点的leftright属性

  • left属性:尾节点的left指向双向链表中的前一个节点。在二叉搜索树转换的上下文中,这个前一个节点是中序遍历中当前节点的前驱,即二叉树中值第二大的节点。
  • right属性:由于尾节点是链表的最后一个节点,所以它的right属性应该是null,表示没有后继节点。

尾节点在二叉搜索树转换中的特性

在将二叉搜索树转换为双向链表的过程中:

  • 尾节点是最后一个被访问的节点。在中序遍历(左-根-右)中,最后访问的总是最右侧的节点。
  • 在转换过程结束时,pre变量将指向这个尾节点。然而,这个信息在方法结束后通常不可用,因为pre不是方法的返回值。

如何找到尾节点

如果在转换完成后需要找到尾节点,可以从头节点开始遍历链表,直到到达末尾。例如:

TreeNode tail = head;
while (tail.right != null) {
    tail = tail.right;
}

在这个遍历过程结束后,tail将指向双向链表的尾节点。

尾节点的应用

尾节点在某些应用场景中非常重要,比如在需要从双向链表的末尾开始逆向遍历时。由于尾节点没有后继,这使得它成为链表逆向遍历的起点。

总之,尾节点在由二叉搜索树转换成的双向链表中扮演着链表最后一个元素的角色,其left指针指向前一个节点,而right指针为null。在实际的转换算法实现中,尾节点并没有被特别标记或返回,但可以通过遍历从头节点找到。

递归的理解

递归是此问题解决的关键。每次递归调用处理树的一小部分(一个子树),最终构建出整个链表。

复杂度分析

  • 时间复杂度:O(n),每个节点访问一次。
  • 空间复杂度:O(1),在原树上操作,不需要额外空间。

文章来源:https://blog.csdn.net/like455/article/details/135563717
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。