算法第二章实践作业——分治算法求第k小元素

算法第二章实践作业
1. 找第k小的数的分治算法(快速选择算法Quickselect)
 算法思路(自然语言描述)
该算法借鉴快速排序的分治思想,不需要对整个数组完全排序,只需要定位目标元素所在区间:
1. 在当前待处理数组区间选择一个基准元素`pivot`;
2. 执行划分操作`Partition`,将区间内小于等于`pivot`的元素放到基准左侧,大于`pivot`的放到右侧,划分完成后基准元素处于它在有序数组中的正确位置;
3. 获取基准元素在当前子区间内的名次`rank`:
    若`rank == k`,基准就是第k小元素,直接返回;
    若`rank > k`,第k小元素落在左子区间,递归处理左区间;
    若`rank < k`,第k小元素落在右子区间,在右区间寻找第`k-rank`小的元素。

伪代码

//arr:数组,left、right 为当前区间左右下标,k 表示查找第 k 小(k 从 1 开始计数)
Function QuickSelect (arr, left, right, k):
if left == right:
return arr [left]
pos = Partition (arr, left, right)
rank = pos - left + 1
if rank == k:
return arr [pos]
else if rank > k:
return QuickSelect (arr, left, pos-1, k)
else:
return QuickSelect (arr, pos+1, right, k - rank)

// 划分函数 Partition
Function Partition (arr, left, right):
pivot = arr [right]
i = left - 1
for j from left to right-1:
if arr [j] <= pivot:
i = i + 1
swap arr [i], arr [j]
swap arr [i+1], arr [right]
return i+1


2. 算法时间复杂度分析
最好时间复杂度:O(n)
每次划分都将数组大致均等拆分,只需要递归处理其中一半子数组。

最坏时间复杂度:O(n^2)
每次选取的基准都是当前区间最大/最小值,划分后一侧仅1个元素,另一侧包含剩余全部元素。
> 补充:采用随机选取基准的优化方式,算法期望时间复杂度为O(n),可以极大降低最坏情况出现概率。

3. 对分治法的体会和思考
分治法核心可以概括为三步:分、治、合。
1. 分:把规模庞大的原问题,拆分成多个结构相同、规模更小的子问题;
2. 治:递归求解子问题,当子问题规模足够小时,直接求解;
3. 合:将子问题的解合并,得到原问题最终解。

结合本次快速选择算法,我有如下理解:
分治法并非一定需要合并左右两个子问题的结果。快速选择就是典型例子,划分之后我们只需要递归搜索目标所在的一侧,不用处理全部子区间,减少大量计算开销;而归并排序这类算法,则需要合并两个有序子数组。

分治算法的优势是将复杂的大规模问题简化,适合递归实现,往往可以得到优于暴力枚举的时间复杂度。但它也存在局限:递归会带来函数调用栈开销,如果划分不均匀会触发最坏性能;递归深度过大还会造成栈溢出。

分治法适合满足两个条件的问题:原问题可以拆解为互相独立的子问题,并且子问题的解能够组合成原问题的解。常见应用包括快速排序、归并排序、二分查找、寻找第k小元素、平面最近点对等。

总的来说,分治本质是降低问题规模来求解。设计分治算法的关键,就是找到合理的划分方式,尽量减少需要求解的子问题数量,同时控制合并步骤的时间开销。
posted @ 2026-10-11 00:05  王子意  阅读(3)  评论(0)    收藏  举报