1. 概述

在本篇文章中,我们将讨论如何从一个有序列表中构建一个平衡二叉搜索树(Balanced Binary Search Tree, BST)。我们会介绍两种常见方法:自顶向下(Top-Down)自底向上(Bottom-Up) 方法,并对它们进行比较。

2. 什么是平衡二叉搜索树

一个平衡二叉树是指其高度为 O(log n) 的二叉树,其中 n 是树中节点的总数。对于树中的每个节点,其左右子树的高度差不能超过 1。

二叉搜索树的定义是:对于每个节点,其左子树的所有节点值都小于该节点值,右子树的所有节点值都大于该节点值。

下面是一个平衡二叉搜索树的示例:

Balanced BST

如图所示,节点 4 的左子树包含 23,都小于 4;右子树包含 5, 6, 7, 8, 9,都大于 4。这种结构在整棵树中保持,使得它既是 BST,又是平衡的。

3. 构建平衡 BST 的思路

要构建一个平衡 BST,核心思想是:

将中间值作为根节点,左边的值构建左子树,右边的值构建右子树

这样可以保证树的高度尽可能小,从而保持平衡。

根据输入数据的结构不同,主要有两种实现方式:

  • Top-Down Approach:适用于数组结构,可以随机访问
  • Bottom-Up Approach:适用于链表结构,只能顺序访问

4. 自顶向下方法(Top-Down Approach)

适用于有序数组,实现简单直观。

✅ 实现步骤

  1. 取数组中间元素作为当前节点(根)
  2. 递归构建左子树(左半部分)
  3. 递归构建右子树(右半部分)

✅ 示例代码(Java)

class TreeNode {
    int val;
    TreeNode left, right;

    TreeNode(int val) {
        this.val = val;
    }
}

public class BalancedBST {
    public static TreeNode sortedArrayToBST(int[] nums) {
        return build(nums, 0, nums.length - 1);
    }

    private static TreeNode build(int[] nums, int left, int right) {
        if (left > right) return null;

        int mid = (left + right) / 2;

        TreeNode root = new TreeNode(nums[mid]);
        root.left = build(nums, left, mid - 1);
        root.right = build(nums, mid + 1, right);

        return root;
    }
}

⚠️ 时间复杂度

  • **时间复杂度:O(n)**,每个节点仅被访问一次
  • **空间复杂度:O(log n)**,递归栈深度

5. 自底向上方法(Bottom-Up Approach)

适用于有序链表,实现稍复杂,但避免了链表随机访问的限制。

✅ 实现思路

  1. 先递归构建左子树
  2. 当前节点取链表当前指针指向的节点
  3. 移动指针到下一个节点
  4. 递归构建右子树

✅ 示例代码(Java)

class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
    }
}

class TreeNode {
    int val;
    TreeNode left, right;

    TreeNode(int val) {
        this.val = val;
    }
}

public class BalancedBSTFromList {
    private static ListNode current;

    public static TreeNode sortedListToBST(ListNode head) {
        int n = countNodes(head);
        current = head;
        return build(n);
    }

    private static int countNodes(ListNode head) {
        int count = 0;
        while (head != null) {
            count++;
            head = head.next;
        }
        return count;
    }

    private static TreeNode build(int n) {
        if (n <= 0) return null;

        TreeNode left = build(n / 2);
        TreeNode root = new TreeNode(current.val);
        current = current.next;
        TreeNode right = build(n - n / 2 - 1);

        root.left = left;
        root.right = right;

        return root;
    }
}

⚠️ 时间复杂度

  • **时间复杂度:O(n)**,每个节点仅被访问一次
  • **空间复杂度:O(log n)**,递归栈深度

6. 两种方法对比

特性 自顶向下(Top-Down) 自底向上(Bottom-Up)
数据结构 数组 链表
思路 先选根节点,再递归构建左右子树 先递归到底部构建左子树,再构建当前节点
实现难度 简单 稍复杂
时间复杂度 O(n) O(n)
适用场景 输入为数组 输入为链表

Top-Down 更适合数组,实现简单直观
Bottom-Up 更适合链表,避免了链表无法随机访问的问题

7. 总结

本文介绍了两种从有序列表构建平衡 BST 的方法:

  • Top-Down Approach:适合数组结构,实现简单
  • Bottom-Up Approach:适合链表结构,避免随机访问限制

两种方法都具有线性时间复杂度 O(n),但在不同数据结构下各有优势。

📌 踩坑提醒

  • 使用 Bottom-Up 时要注意链表指针的移动逻辑,避免重复访问或漏掉节点
  • Top-Down 虽然简单,但不能直接用于链表,否则会重复遍历导致效率下降

在实际开发中,应根据输入数据的存储结构选择合适的方法。


原始标题:Create Balanced Binary Search Tree From Sorted List