分治法排序

在计算机科学中,分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

分治法所能解决的问题一般具有以下几个特征:
1) 该问题的规模缩小到一定的程度就可以容易地解决
2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
3) 利用该问题分解出的子问题的解可以合并为该问题的解;
4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

上述的第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。

下面的分治法排序的代码

#include <iostream>
using namespace std;
/**
 * @brief 比较合并
 *
 * @param[in] A 数组指针
 * @param[in] p 数组起始下标
 * @param[in] q 数组分隔下标
 * @param[in] r 数组结束下标
 */
void Merge(int* A, int p, int q, int r)
{
	int n1 = q - p + 1;
	int n2 = r - q;
	int* L = new int[n1 + 1];
	int* R = new int[n2 + 1];
	int i = 0, j = 0;
	for (i = 0; i < n1; ++i)
	{
		L[i] = A[p + i];
	}
	L[n1] = INT_MAX;
	for (j = 0; j < n2; ++j)
	{
		R[j] = A[q + j + 1];
	}
	R[n2] = INT_MAX;
	i = 0; j = 0;
	for (int k = p; k < r + 1; ++k)
	{
		if (L[i] <= R[j])
		{
			A[k] = L[i];
			++i;
		}
		else
		{
			A[k] = R[j];
			++j;
		}
	}
	delete[] L;
	delete[] R;
}
/**
 * @brief 分治
 *
 * @param[in] A 数组指针
 * @param[in] p 数组起始下标
 * @param[in] r 数组结束下标
 */
void MergeSort(int* A, int p, int r)
{
	if (p < r)
	{
		int q = (p + r) / 2;
		MergeSort(A, p, q);
		MergeSort(A, q + 1, r);

		//merge
		Merge(A, p, q, r);
	}
}

int main()
{
	int A[10] = {9,8,7,6,5,4,3,2,1,11};
	MergeSort(A, 0, 9);
	for (int i = 0; i < 10; ++i)
	{
		cout << A[i] << ", ";
	}
	cout << endl;
}

Comments are closed.