算法第二章实践作业
1.找第k小的数的分治算法描述(自然语言):
- 函数 'partition':
- 选择数组的最后一个元素 'a[right]' 作为基准值 'x' 。
- 初始化一个指针 'i' ,指向 'left - 1' 。
- 遍历从 'left'到 'right - 1' 的元素 'a[j]':
- 如果 'a[j]' 小于等于基准值 'x' ,则将 'i' 右移一位,然后交换 'a[j]' 和 'a[i]' 。这样做的目的是将小于等于基准值的元素放在左边,大于基准值的元素放在右边。
- 遍历结束后,将基准值 'a[right]' 与 'a[i + 1]' 交换,此时 'a[i + 1]' 就是基准值在排好序后的正确位置,返回 'i + 1' 。
- 函数 'find':
- 调用'partition'函数对数组 'a' 在 '[left, right]' 区间进行划分,得到基准值的位置 'x' 。
- 如果基准值的位置 'x' 恰好等于 'k',则直接返回 'a[x]',因为找到了第 'k' 小的数。
- 如果 'x' 大于 'k' ,说明第 'k' 小的数在基准值的左边,递归调用 'find' 函数在 '[left, x - 1]' 区间内寻找第 'k' 小的数。
- 如果 'x' 小于 'k' ,说明第 'k' 小的数在基准值的右边,递归调用 'find' 函数在 '[x + 1, right]' 区间内寻找第 'k' 小的数。
- 主函数 'main':
- 输入数组的大小 'n' 和要找的第 'k' 小的数的位置 'k' 。
- 输入数组的元素 'a[i]' 。
- 调用 'find'函数在数组 'a' 中寻找第 'k' 小的数并输出。
-
算法时间复杂度分析:
- 最好情况:每次划分都能将数组恰好分成两个长度相等的子数组。每次划分的时间复杂度为O(n),假设数组长度为n,递归深度为log n,所以最好时间复杂度为O(n \ log n)。这是因为每次划分后,问题规模减半,总共需要划分log n次,每次划分需要线性时间O(n)。
- 最坏情况:每次划分都将数组划分为一个长度为1和一个长度为n - 1的子数组。例如,数组已经有序,每次选择的基准值都是最大或最小的元素。此时,每次划分的时间复杂度为O(n),需要划分n - 1次,所以最坏时间复杂度为O(n^2)。
-
对分治法的体会和思考:
- 优势:分治法将一个复杂的问题分解为多个规模较小的子问题,这些子问题与原问题具有相同的结构,通过递归求解子问题并合并结果来解决原问题。它能够有效地降低问题的复杂度,在很多情况下能够提高算法的效率。例如,归并排序和快速排序都是基于分治法的思想,它们的平均时间复杂度都优于简单的排序算法。
- 适用场景:适用于问题可以分解为多个独立的子问题,且子问题的解可以合并成原问题的解的情况。像寻找第k小的数,通过划分将数组分成两部分,分别在不同部分中寻找,符合分治法的应用场景。
- 挑战:分治法通常伴随着递归调用,这可能会带来额外的空间开销,因为每次递归调用都需要在栈中保存一些信息。此外,如何合理地划分问题是分治法的关键,如果划分不合理,如在最坏情况下的快速排序,可能导致算法的时间复杂度恶化。在实际应用中,需要根据具体问题的特点来选择合适的划分策略,以达到较好的时间和空间性能。

浙公网安备 33010602011771号