我的第二章作业学习
一、分治算法描述(快速选择找第k小)
- 自然语言描述
本算法基于快速排序的划分思想,采用分治策略实现平均O(n)复杂度查找第k小数:
-
划分(partition):在当前数组区间[left,right]选取基准元素pivot,将区间划分成两部分:左侧所有元素≤pivot,右侧所有元素≥pivot;划分完成后基准落在其有序数组的正确下标x。
-
分治判断
◦ 若基准下标x恰好等于目标下标k-1(数组从0开始,第k小对应下标k-1),基准就是答案,直接返回;
◦ 若x<k-1:第k小元素只存在于右区间[x+1,right],递归处理右区间;
◦ 若x>k-1:第k小元素只存在于左区间[left,x-1],递归处理左区间。
-
递归边界:区间仅存一个元素(left==right),该元素即为所求。
-
伪代码
// 划分函数,返回基准最终下标
partition(a[], left, right):
mid = left + (right - left) / 2
pivot = a[mid]
s = 空列表(存≤pivot)
m = 空列表(存>pivot)
for i = left to right:
if i == mid: continue
if a[i] <= pivot: s.append(a[i])
else: m.append(a[i])
// 回填数组
sh = s长度
for i = 0 to sh-1: a[left+i] = s[i]
a[left + sh] = pivot
for j = 0 to m长度-1: a[left+sh+1+j] = m[j]
return left + sh
// 分治查找函数,k_target为目标下标(第k小对应k-1)
find(a[], left, right, k_target):
if left == right:
return a[left]
x = partition(a, left, right)
if x == k_target:
return a[x]
elif x < k_target:
return find(a, x+1, right, k_target)
else:
return find(a, left, x-1, k_target)
// 主流程
输入n, k
输入数组a
res = find(a, 0, n-1, k-1)
输出res
二、时间复杂度分析
-
最好时间复杂度:O(n)
每次划分的基准恰好将区间均分,仅需递归处理一半子区间。总运算量为n + \frac{n}{2} + \frac{n}{4} + ... ≈ 2n,线性复杂度O(n)。 -
最坏时间复杂度:O(n^2)
每次选取的基准为区间最大/最小值,划分后仅剔除1个元素,递归规模仅减少1。总运算量n+(n-1)+(n-2)+... = \frac{n(n+1)}{2},平方复杂度O(n^2)。
三、对分治法的体会与思考
-
分治核心逻辑:分、治、合
分治三步为拆分大问题、递归求解子问题、合并子问题解。本题是特殊分治:无需合并,划分后只需递归求解单侧子区间,直接舍弃另一半,大幅减少计算量,这是快速选择效率优于全排序的关键。 -
划分质量决定算法效率
分治算法性能高度依赖拆分方式。本算法中基准选取直接决定复杂度:均衡划分可达线性时间,极差划分会退化到平方级;随机选取基准可大幅降低最坏情况出现概率。 -
分治的优势:避免冗余计算
若先完整排序再取第k小,复杂度为O(n\log n);而快速选择只需要定位目标元素,不需要完成全区间排序,跳过大量无关元素处理,体现分治“缩小问题规模、减少无效运算”的优势。 -
适用场景总结
分治法适合原问题可拆分为结构相同、相互独立的子问题的场景,常通过递归实现。二分查找、快速排序、归并排序、快速选择都是典型分治应用;其中仅需单侧递归的分治算法,通常时间效率更优。

浙公网安备 33010602011771号