Convert Sorted Array to Binary Search Tree 把一个有序数组转换成BST @LeetCode

介绍如何将一个升序数组转换成一棵高度平衡的二叉搜索树(BST)。通过递归方式选择数组中间元素作为根节点,并继续处理左右子数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

给定一个有序的数组,要求转换为BST

思路:

递归。

每次找到数组中值作为BST的root,然后递归处理左半数组和右半数组分别作为左右子树

package Level2;

import Utility.TreeNode;

/**
 * Convert Sorted Array to Binary Search Tree  
 * 
 * Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
 */
public class S108 {

	public static void main(String[] args) {
		int[] num = {1,3};
		TreeNode n = sortedArrayToBST(num);
		n.print();
	}
	
	public static TreeNode sortedArrayToBST(int[] num) {
		return sortedArrayToBSTRec(num, 0, num.length-1);
    }
	
	// 二分查找节点值,并递归创建节点
	private static TreeNode sortedArrayToBSTRec(int[] num, int low, int high){
		if(low > high){
			return null;
		}
		int mid = low + (high-low)/2;		// 找到中值
		TreeNode root = new TreeNode(num[mid]);		// 创建根节点
        root.left = sortedArrayToBSTRec(num, low, mid-1);		// 递归创建左子树和右子树
        root.right = sortedArrayToBSTRec(num, mid+1, high);
		return root;
	}

}



/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public TreeNode sortedArrayToBST(int[] num) {
        return rec(num, 0, num.length-1);
    }
    
    public TreeNode rec(int[] num, int low, int high){
        if(low > high){
            return null;
        }
        int mid = low + (high-low)/2;
        TreeNode root = new TreeNode(num[mid]);
        root.left = rec(num, low, mid-1);
        root.right = rec(num, mid+1, high);
        return root;
    }
}



<think>嗯,用户让我分析这段将有序数组转换为平衡二叉搜索树的代码。我需要先仔细理解代码的结构和工作原理。首先,代码是用C语言写的,结构体TreeNode应该包含val、left和right指针。函数sortedArrayToBST接收一个数组和大小,然后调用dfs函数递归构建树。 接下来,我得理解dfs函数的作用。参数是nums数组、left和right边界。递归终止条件是left等于right,返回NULL。这说明区间是左闭右开的,比如当left为0,right为0时没有元素。然后计算中间位置m,这里用的是left + (right - left)/2,这样可以防止整数溢出。中间节点作为当前子树的根节点,然后递归处理左半部分和右半部分。 用户提到要说明中间节点是左还是右,这里需要看中间值的计算方式。例如,当数组长度为偶数时,比如4个元素,中间位置应该是第二个元素(索引从0开始)。因为(right - left)/2在left为0,right为4时是2,所以m=2。这时候左边是0到2,右边是3到4。所以中间节点选的是靠左的位置吗?或者要看具体例子。 然后需要举例运行,分奇数和偶数情况。比如奇数情况用数组[1,2,3],偶数用[1,2,3,4]。对于奇数数组,中间是2,左右子树各一个节点。对于偶数数组,中间是第二个元素,即3的位置?或者当数组是0到3索引时,中间是1还是2?比如数组是[1,2,3,4],left=0,right=4,计算m=0 + (4-0)/2=2,所以中间是索引2的元素3?那左子树是0到2(元素1和2),右是3到4(元素4)。这时候根是3,左子树的根是1还是2?需要再仔细分析递归过程。 另外,用户的问题中提到中间节点是选择靠左还是靠右。根据代码中m的计算方式,当区间长度是偶数时,比如长度为4,中间位置是2(比如0-4区间,m=2),这时取的是中间偏右的位置吗?比如数组索引0-3的元素,中间位置是1.5,但整数除法会取1吗?或者原题中的数组可能为0到numsSize-1,而right是numsSize,所以当数组长度为偶数时,比如numsSize=4,right是4,中间是0 + (4-0)/2=2,所以索引2是第三个元素,在四个元素中是中间偏右的位置吗? 例如,数组是[1,2,3,4],索引0到3。调用dfs(0,4),m=2,元素3作为根。然后左子树处理0到2(索引0和1),即元素1和2,此时m=0+ (2-0)/2=1,所以根是2。左子树是0到1(元素1),右是1+1=2到2,返回NULL。这样形成的树结构是根3,左子树根2,左子树的左是1,右为空;右子树根4。这样整个树的高度平衡吗? 另一个例子,数组长度3,索引0-2。初始调用dfs(0,3),m=1,元素2作为根。左子树处理0到1,即元素1,右处理2到3(元素3)。这样形成的树是平衡的。 所以作者使用的是每次选取中间偏右的节点作为根?比如当数组长度为偶数时,中间位置取的是右边的那个。比如四个元素时,选第三个元素作为根。这可能是因为计算方式中的整数除法是向下取整。例如,当区间长度是4时,中间位置是2,而索引0-3中的中间位置是1.5,所以整数除法得到的是1吗?或者原代码中的区间是左闭右开,所以当left=0,right=4时,元素是0到3,四个元素,中间位置是0+4/2=2,索引2的元素是第三个元素。这时候确实中间偏右。 那在注释中需要说明,当数组长度为偶数时,中间节点选择的是中间两个中的后一个,即靠右的节点。例如,数组长度为4时,中间是第二个索引(0-based),比如数组元素1、2、3、4,中间是3? 或者需要再仔细计算一下。例如,当数组长度为4时,初始left=0,right=4。m=0 + (4-0)/2=2。那么nums[m]是第三个元素。所以当数组是升序排列时,选中间靠右的节点作为根,这样左子树的元素比根小,右子树的元素比根大,这样满足二叉搜索树的条件。 然后用户要求举例运行,奇数和偶数各一次。比如奇数例子数组是[1,2,3],中间选2,左右各一个元素。偶数例子数组是[1,2,3,4],中间选3作为根,左子树处理0到2的元素1和2,中间选2作为根,再左子树是1,右子树为空。右子树处理3到4的元素4。最终形成的树结构可能需要图示。 另外,代码中的递归函数每次都将中间元素作为根,然后递归构建左右子树,这样生成的树是高度平衡的,因为左右子树的节点数最多相差一个。 总结下来,代码的工作原理是通过递归选取中间元素作为当前子树的根,确保左右子树的高度差不超过1,从而实现平衡。当数组长度为偶数时,中间元素选取的是中间两个中的靠右的那个,即中间位置的计算方式是使用整数除法,例如长度为4时,中间索引是2。</think>### 代码分析 这段代码将一个**升序数组**转换为**高度平衡的二叉搜索树**(AVL树),核心思想是**递归选取中间元素作为根节点**,保证左右子树高度差不超过1。 --- ### 代码结构与注释 ```c // 递归构建平衡二叉搜索树 // nums: 输入数组,left: 当前区间左边界(包含),right: 当前区间右边界(不包含) struct TreeNode* dfs(int* nums, int left, int right) { if (left == right) { // 区间为空,递归终止 return NULL; } int m = left + (right - left) / 2; // 计算中间位置(向下取整) struct TreeNode* node = malloc(sizeof(struct TreeNode)); node->val = nums[m]; // 中间元素作为根节点 node->left = dfs(nums, left, m); // 递归构建左子树 node->right = dfs(nums, m + 1, right); // 递归构建右子树 return node; } // 主函数入口 struct TreeNode* sortedArrayToBST(int* nums, int numsSize) { return dfs(nums, 0, numsSize); // 初始区间为[0, numsSize) } ``` --- ### 核心逻辑 1. **中间节点选择**: 每次选取区间中点 `nums[m]` 作为根节点。 - **奇偶处理**:当区间长度为偶数时,`m` 的计算公式 `left + (right - left)/2` **向下取整**,导致中间节点偏向区间左侧。 - 例如,区间 `[0,4)`(元素为`[1,2,3,4]`)的中间索引是 `2`(值为3),而非中间两个元素的右侧。 2. **递归构建子树**: - 左子树区间为 `[left, m)`,右子树区间为 `[m+1, right)`。 - 通过左闭右开区间避免重复处理元素。 --- ### 运行示例 #### 示例1(奇数长度数组:`[1, 2, 3]`) ```text 初始调用: dfs(0, 3) 区间[0,3)的中间m=1,根节点值为2 ├── 左子树: dfs(0,1) → m=0,根节点值为1 │ ├── 左子树: dfs(0,0) → NULL │ └── 右子树: dfs(1,1) → NULL └── 右子树: dfs(2,3) → m=2,根节点值为3 ├── 左子树: dfs(2,2) → NULL └── 右子树: dfs(3,3) → NULL 最终树结构: 2 / \ 1 3 ``` #### 示例2(偶数长度数组:`[1, 2, 3, 4]`) ```text 初始调用: dfs(0,4) 区间[0,4)的中间m=2,根节点值为3 ├── 左子树: dfs(0,2) │ └── 中间m=1,根节点值为2 │ ├── 左子树: dfs(0,1) → m=0,根节点值为1 │ │ ├── 左子树: NULL │ │ └── 右子树: NULL │ └── 右子树: dfs(2,2) → NULL └── 右子树: dfs(3,4) → m=3,根节点值为4 ├── 左子树: dfs(3,3) → NULL └── 右子树: dfs(4,4) → NULL 最终树结构: 3 / \ 2 4 / 1 ``` --- ### 关键总结 - **中间节点偏向左侧**:通过 `m = left + (right - left)/2` 计算,**向下取整**导致中间节点在偶数长度区间中靠左(例如 `[1,2,3,4]` 的中间是2)。 - **平衡性保证**:每次递归将区间均分,左右子树高度差不超过1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值