归并排序
归并本质是一种分治算法,所谓分支,即是分而治之,即将一个数据规模很大的问题分解成若干个数据规模较小的相同的子问题,分别解决。
分治思想解题思维
1.分解
将要解决的问题分解成若干个规模较小的相同形式的子问题。
2.治理
求解各个子问题,由于子问题的数据规模较小,因此可以用相对简单的方法求解。
3.合并
按照问题的要求,将子问题的解逐层合并构成原问题的解。
归并排序
归并排序的基本思想是把待排序的元素分解成两个规模大致相等的子序列。如果不易分解,将得到的子序列继续分解,直到子序列中包含的元素个数为1。因为单个元素的序列本身就是有序的,此时便可以进行合并,从而得到一个完整的有序序列。
步骤
1.将待排序的元素分成大小大致一样的两个子序列。
2.再将子序列分成两个大小大致相同的两个子序列。
3.如此下去,直到分解成一个元素为止,这时含有一个元素的子序列都是有序的。
4.进行合并操作,将两个有序的子序列合并成一个有序的子序列。如此下去,直到所有元素都合并成一个有序序列。
代码实现
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, j, k;
for (i=0; i<n1; i++){
L[i] = a[p+i];
}
for (j=0; j<n2; j++){
R[j] = a[q+j+1];
}
L[n1] = 10000000;
R[n2] = 10000000;
for (i=0, j=0, k=p; k<=r; k++)
{
if (L[i]<=R[j])
{
a[k] = L[i];
i++;
}else{
a[k] = R[j];
j++;
}
}
delete []L;
delete []R;
}
void MergeSort1(int *a, int p, int r)
{
if (p<r)
{
int q = (p+r)/2;
MergeSort1(a, p, q);
MergeSort1(a, q+1, r);
Merge(a, p, q, r);
}
}
虽然归并排序的时间复杂度为O(nlogn),而插入排序的时间复杂度为O(n2),但插入排序中的常数因子使得它在n较小的时候,运行的更快因此,在归并排序算法中,当子问题足够小的时候,采用插入排序就比较合适了。
void MergeSort2(int *a, int p, int r)
{
if ((r-p)>=50) // 小于50个数据的数组进行插入排序
{
int q = (p+r)/2;
MergeSort2(a, p, q);
MergeSort2(a, q+1, r);
Merge(a, p, q, r);
}else
{
InsertionSort(a+p, r-p+1);
}
}