二叉树——将有序数组转化为平衡二叉搜索树

首先我们先搞懂什么是平衡二叉搜索树
平衡二叉搜索树 = 二叉搜索树+左右高度差不超过1

1.先搞懂:什么是二叉搜索树BST
满足三条:

  1. 左子树所有节点<根节点
  2. 右子树所有节点>根节点
  3. 左右子树也都属二叉搜索树

2.再搞懂平衡
平衡二叉树的定义
对于树中任意一个节点,它的左子树和右子树的高度差不超过1
高度差不能超过1,树就不会歪,不会退化成链表。

3.合起来:平衡二叉搜索树(Banlanced BST)
同时满足两个条件:
1.是二叉搜索树(左小右大)
2.是平衡树(任意节点左右高度差不超过1)

4.为什么有序数组取中间就能变成平衡BST?
因为:

  • 中间元素做根->左右两边元素数量几乎相等(当数组长度为偶数时,数量最多差1,奇数数量相等
  • 递归下去每一层都这样
    ->天然左右高度差不会超过1
    ->自动平衡

平衡二叉搜索树 = 有序且不歪的二叉树,查找效率 O (log n)

题目要求:
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 平衡 二叉搜索树。

这道题的核心思路二分法+递归
因为数组是升序有序的,我们每次取中间元素作为二叉搜索树的根节点,左边子树数组构建左子树,右边子数组构建右子树,这样天然就能保证二叉树是平衡的(左右子树高度差不超过1)。

核心逻辑解释:
1.TreeNode 类:标准的二叉树节点定义,包含值、左孩子、右孩子。
2.主方法 sortedArrayToBST:

  • 调用递归方法,传入数组、初始左边界(0)、初始右边界(数组长度 - 1)。
    3.递归方法buildTree
  • 终止条件left > right说明当前区间无元素,返回null。
  • 取中间值:mid = left + (right - left) / 2,避免(left+right)整数溢出,同时保证取到中间元素。
  • 构建根节点:用中间元素创建当前子树的根。
  • 递归构建左右子树:
    左子树:区间[left, mid-1]
    右子树:区间[mid+1, right]

复杂度分析

  • 时间复杂度:O (n),每个元素仅访问一次,构建 n 个节点。
  • 空间复杂度:O (log n),递归调用栈的深度为平衡二叉树的高度(log n)。

总结

  1. 有序数组转平衡 BST,核心是二分递归,用中间元素做根保证平衡。
  2. 递归终止条件是左边界大于右边界,返回null。
  3. 中间值计算用left + (right-left)/2,避免整数溢出。

3.为什么left>right,返回null?
这段代码是递归的核心逻辑,递归的每一步都是把当前区间 [left, right] 拆成 [left, mid-1](左子树)和 [mid+1, right](右子树)。当拆分后的区间起始位置超过结束位置,就意味着这个方向上没有元素了,自然要返回 null 终止递归。

4.为什么数组长度用nums.length而不是nums.size()?

  • nums是数组→ 用 .length(属性)
  • 如果是** List(集合)** → 才用 .size()(方法)

这里 nums 是 int [] 数组不是 List,所以必须用 length。

详细区别:
1. 数组(int []、String []、Object [])

  • 固定大小的 Java 基础结构
  • 有一个公开属性叫 length
  • 用法:nums.length

2. 集合(ArrayList、LinkedList、HashSet…)

  • 是 Java 容器类
  • 提供方法 size()
  • 用法:list.size()

注意C++中求数组长度也不是用.size()

  • C++ 里原始数组:int a[] → 没有 size()!
    而是用数组内存大小除以元素内存大小:int len = sizeof(nums) / sizeof(nums[0]);
  • C++ 里容器:vector → 才有 size()
    vector 是动态数组容器,属于 STL,才有成员函数 size()

5.为什么求mid不能用mid =(left+right)/2?
这是一个非常经典、面试必问、且极其重要的细节!

因为 (left + right) 会发生整数溢出(Integer Overflow)

1.溢出是什么?
Java 的 int 最大值是:
2,147,483,647

如果left和right都很大,比如:

  • left = 2,000,000,000
  • right = 2,000,000,000

left + right = 4,000,000,000

超过了 int 上限,会变成负数
然后你再除以 2,得到的 mid 就是错误的负数,直接数组越界崩溃。

2.为什么int mid = left + (right - left) / 2安全?

  • right - left 永远不会溢出(因为 right > left,结果一定在 int 范围内)
  • 再除以 2,再加 left
  • 数学上等价,但绝对安全

一句话总结
(left + right) / 2 会溢出,left + (right - left) / 2 不会溢出,且结果相同。
所以所有二分查找、二分建树,标准写法都是后者。

posted @ 2026-04-16 16:21  AlexXuu  阅读(9)  评论(0)    收藏  举报