分治模式在每层递归是都有三个步骤:
分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。
解决这些子问题,递归地求解各子问题。若子问题规模足够小,则直接求解。
合并这些子问题的解成原问题的解。
归并排序算法完全遵循分治模式。
分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。
解决:使用归并排序递归地排序两个子序列。
合并:合并两个已经排好序的子序列。
归并排序算法的关键步骤是“合并”步骤中两个已经排序好的序列。通过调动MERGE(A,p,q,r)来完成合并。
其中A是一个数组,p、q和r是数组下标,满足p<=q<r。
该过程将A[p..q]和A[q+1..r]两个已经排序好的序列合并成一个已排序号的数组A[p..r]。
∞是为了方便判断L和R数组是否已经全部合并,不用每次检查是否全部合并。
MERGE算法的时间复杂度为O(n),其中n=r-p+1。
MERGE(A, p, q, r)
n1 = q - p + 1
n2 = r - q
let L[1..n1 + 1] and R[1..n2 + 1] be new arrays
for i = 1 to n1
L[i] = A[p + i - 1]
for j = 1 to n2
R[j] = A[q + j]
L[n1 + 1] = ∞
R[n2 + 1] = ∞
i = 1
j = 1
for k = p to r
if L[i] <= R[j]
A[k] = L[i]
i = i + 1
else
A[k] = R[j]
j = j + 1
有了MERGE后,MERGE-SORT(A,p,r)写可以很容易的实现。
伪代码如下:
MERGE - SORT(A, p, r)
if p < r
q = (p + r) / 2
MERGE - SORT(A, p, q)
MERGE - SORT(A, q + 1, r)
MERGE(A, p, q, r)
分析分治算法
T(n)=O(1) n<=c
T(n)=2T(n/2)+D(n)+C(n) 其他
当问题规模足够小,比如小于c,则直接求解需要常量时间。
否则,将问题分为2个子问题。分解问题需要D(n),合并需要C(n)时间。
最终T(n)=O(nlgn)
C++实现如下:
void Merge(vector<int> &A, int p, int q, int r){
int n3 = q - p + 1;
int n4 = r - q;
vector<int> L(A.begin() + p, A.begin() + q + 1);
vector<int> R(A.begin() + q + 1, A.begin() + r + 1);
int n1 = L.size();
int n2 = R.size();
L.push_back(0x7fffffff);
R.push_back(0x7fffffff);
int i, j;
i = 0;
j = 0;
for (int k = p; k <= r; ++k){
if (L[i] <= R[j]){
A[k] = L[i];
++i;
}
else
{
A[k] = R[j];
++j;
}
}
}
void MergeSort(vector<int> &A, int p, int r){
if (p < r){
int q = (p + r) / 2;
MergeSort(A, p, q);
MergeSort(A, q + 1, r);
Merge(A, p, q, r);
}
}