分治算法,即分治法,是一种将复杂问题分解为多个较小的子问题来解决的算法。它的基本思想是将原问题分解为若干个规模较小、相互独立且与原问题类型相同的子问题,递归地解决这些子问题,然后将子问题的解合并得到原问题的解。
一、基本概念
- 分解
将原问题分解为若干个规模较小、相互独立且与原问题类型相同的子问题。例如,将一个大规模的数组排序问题分解为两个较小规模的数组排序问题。
- 解决
对子问题进行求解。如果子问题足够小,则直接求解;否则,继续将子问题分解,直到达到可以直接求解的规模。例如,当数组的规模为 1 时,可以认为是已经排好序的。
- 合并
将子问题的解合并成原问题的解。例如,将两个已经排好序的较小规模的数组合并成一个排好序的大规模数组。
二、分治算法的应用示例
- 归并排序
归并排序是分治算法的经典应用之一,它通过将数组分成两半,分别排序,然后将排序后的两半合并来实现整个数组的排序。
算法步骤
- 分解 :将数组分成两半,直到每个子数组只有一个元素。
- 解决 :当子数组只有一个元素时,认为已经排好序。
- 合并 :将两个已经排好序的子数组合并成一个排好序的数组。
示例代码(C/C++)
cpp
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& arr, int left, int mid, int right) {
vector<int> temp;
int i = left, j = mid + 1;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp.push_back(arr[i]);
i++;
} else {
temp.push_back(arr[j]);
j++;
}
}
while (i <= mid) {
temp.push_back(arr[i]);
i++;
}
while (j <= right) {
temp.push_back(arr[j]);
j++;
}
for (int k = left; k <= right; k++) {
arr[k] = temp[k - left];
}
}
void mergeSort(vector<int>& arr, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
int main() {
vector<int> arr = {12, 11, 13, 5, 6, 7};
cout << "Original array: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
mergeSort(arr, 0, arr.size() - 1);
cout << "Sorted array: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
return 0;
}
代码解释
- merge 函数 :用于合并两个已经排好序的子数组。创建一个临时数组 temp,用于存储合并后的结果。然后比较两个子数组的元素,依次将较小的元素放入 temp 中。最后将 temp 中的元素复制回原数组 arr 的相应位置。
- mergeSort 函数 :用于递归地对数组进行分治排序。当 left 小于 right 时,计算中间位置 mid,将数组分为两部分,分别对左右两部分进行 mergeSort 递归排序,最后将排好序的两部分通过 merge 函数合并。
- 快速排序
快速排序也是一种分治排序算法,它通过选择一个基准元素,将数组分为两个部分,一部分小于等于基准元素,另一部分大于基准元素,然后递归地对这两部分进行快速排序。
算法步骤
- 分解 :选择一个基准元素,将数组分为两个部分,左边部分小于等于基准元素,右边部分大于基准元素。
- 解决 :递归地对左右两部分进行快速排序。
- 合并 :由于左右两部分已经排好序,所以整个数组也就排好序了,不需要额外的合并操作。
示例代码(C/C++)
cpp
#include <iostream>
#include <vector>
using namespace std;
int partition(vector<int>& arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return i + 1;
}
void quickSort(vector<int>& arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
int main() {
vector<int> arr = {10, 7, 8, 9, 1, 5};
int n = arr.size();
cout << "Original array: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
quickSort(arr, 0, n - 1);
cout << "Sorted array: ";
for (int num : arr) {
cout << num << " ";
}
cout << endl;
return 0;
}
代码解释
- partition 函数 :用于选择基准元素并划分数组。选择最后一个元素作为基准元素 pivot,初始化 i 为 low - 1。然后从 low 到 high - 1 遍历数组,将小于等于 pivot 的元素交换到左边部分。最后将 pivot 放置到正确的位置,并返回 pivot 的索引。
- quickSort 函数 :用于递归地对数组进行快速排序。当 low 小于 high 时,调用 partition 函数划分数组,得到 pivot 的索引 pi。然后递归地对左半部分(low 到 pi - 1)和右半部分(pi + 1 到 high)进行 quickSort 排序。
- 大整数乘法
大整数乘法是分治算法在数学计算中的应用。传统的长乘法算法时间复杂度较高,分治算法可以降低时间复杂度,提高计算效率。
算法步骤
- 分解 :将大整数 x 和 y 分解为两个部分,例如,将 x 分解为 a 和 b,y 分解为 c 和 d。
- 解决 :递归地计算 a × c、a × d、b × c 和 b × d 四个子问题。
- 合并 :将四个子问题的解组合起来,得到最终的乘积。
示例代码(C/C++)
cpp
#include <iostream>
#include <string>
using namespace std;
string multiply(string num1, string num2) {
int m = num1.size();
int n = num2.size();
vector<int> result(m + n, 0);
for (int i = m - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
int mul = (num1[i] - '0') * (num2[j] - '0');
int sum = mul + result[i + j + 1];
result[i + j + 1] = sum % 10;
result[i + j] += sum / 10;
}
}
string product;
for (int digit : result) {
if (!(product.empty() && digit == 0)) {
product.push_back(digit + '0');
}
}
return product.empty() ? "0" : product;
}
int main() {
string num1 = "123456789";
string num2 = "987654321";
cout << "Multiplication of " << num1 << " and " << num2 << " is: " << multiply(num1, num2) << endl;
return 0;
}
代码解释
- 分解 :将两个大整数 num1 和 num2 分解为单个数字进行相乘。
- 解决 :通过嵌套循环,计算每个数字对的乘积,并将结果存储在 result 向量中。
- 合并 :处理进位后,将结果转换为字符串形式输出。
三、总结
分治算法是一种强大的算法设计技术,适用于解决具有分治性质的问题。通过将问题分解为较小的子问题,递归地求解子问题,然后合并子问题的解,可以高效地解决问题。在程序设计竞赛中,分治算法有广泛的应用,如排序、查找、数学计算等领域。
以上介绍了分治算法的基本概念、步骤以及在归并排序、快速排序和大整数乘法中的应用,并提供了相应的 C/C++ 示例代码,希望对大家有所帮助。