1. 分治算法(Divide and Conquer)
分治算法的核心思想是将一个大问题分解为多个小问题,分别解决这些小问题,然后将小问题的解合并起来得到大问题的解。
2. 算法步骤
分治算法通常包含以下三个步骤:
分解(Divide):将原问题分解为若干个规模较小、相互独立、与原问题形式相同的子问题。例如,在归并排序中,将一个待排序的数组从中间分成两个子数组。
解决(Conquer):若子问题规模较小而容易被解决则直接求解,否则递归地解各个子问题。比如,对于归并排序中的子数组,如果子数组只有一个元素,就无需再排序;若子数组元素个数大于 1,则继续对其进行分解。
合并(Combine):将各个子问题的解合并为原问题的解。在归并排序里,就是将两个已排序的子数组合并成一个有序的数组。
3. 适用问题
分治算法适用于满足以下几个特征的问题:
- 问题可分解:原问题可以分解为多个规模较小的子问题,且这些子问题的结构与原问题相似。
- 子问题相互独立:子问题之间没有依赖关系,可以独立求解。例如,在计算多个矩阵的乘积时,每个矩阵的计算过程互不影响。
- 子问题的解可合并:子问题的解能够以某种方式合并,得到原问题的解。像在归并排序中,将已排序的子数组合并成一个完整的有序数组。
4. 复杂度分析
分治算法的时间复杂度通常可以通过递归方程来分析。以常见的分治算法为例,假设原问题的规模为 (n),分解成 (a) 个子问题,每个子问题的规模为 (n/b),分解和合并步骤的时间复杂度为 (f(n)),则分治算法的时间复杂度 (T(n)) 满足递归方程:(T(n)=aT(n/b)+f(n))。
常见的复杂度情况有:
- 归并排序:将数组分成两个子数组((a = 2)),每个子数组规模为 (n/2)((b = 2)),分解和合并步骤的时间复杂度为 (O(n)),通过主定理可分析出归并排序的时间复杂度为 (O(n log n))。
- 快速排序:平均情况下,快速排序也将数组大致分成两个子数组((a = 2),(b = 2)),平均时间复杂度为 (O(n log n));但在最坏情况下(如数组已经有序),时间复杂度会退化为 (O(n^2))。
5. 经典案例
5.1 案例描述
编写一个程序,该程序能够接收一个整数数组作为输入,分别使用归并排序和快速排序对数组进行排序,并输出排序后的数组。
输入
第一行包含一个整数 n n n( 1 ≤ n ≤ 1000 1 \leq n \leq 1000 1≤n≤1000),表示数组的长度。
第二行包含 n n n 个整数 a 1 , a 2 , ⋯ , a n a_1, a_2, \cdots, a_n a1,a2,⋯,an