思路:把待排序序列分成相同大小的两个部分,依次对这两部分进行归并排序,完毕之后再按照顺序进行合并。具体思路请参考算法导论,以下实现按算法导论中思路来写的。
性能:稳定的排序算法,时间复杂度最差、平均、最好都是O(nlogn),空间复杂度为O(n)。
实现1:递归实现
#include <iostream>
using namespace std;
void mergeSort(int a[], int p, int r);
void merge(int a[], int p, int q, int r);
void mergeSort(int a[], int p, int r)
{
int q;
q = (p+r)/2; //分成两部分
if(p < r){
mergeSort(a, p, q);
mergeSort(a, q+1, r);
merge(a, p, q, r);
}
}
void merge(int a[], int p, int q, int r)
{
int n1 = q-p+1; //左边元素个数
int n2 = r-q; //右边元素个数
int i, j, k;
int L[n1], R[n2];
for(i = 0; i < n1; i++)
L[i] = a[p+i]; //左边元素拷贝到L中
for(j = 0; j < n2; j++)
R[j] = a[q+1+j]; //右边元素运拷贝到R中
i = j = 0;
k = p;
while(i < n1 && j < n2){
if(L[i] <= R[j])
a[k] = L[i++];
else
a[k] = R[j++];
k++;
}
while(i < n1)
a[k++] = L[i++];
while(j < n2)
a[k++] = R[j++];
}
int main()
{
int a[8] = {1002, 6, 5, 4, 1, 10, 11, 6};
mergeSort(a, 0, 7);
for(int i = 0; i < sizeof(a)/sizeof(int); i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
实现2:循环实现
思路:给定数组{23, 10, 8, 5, 7, 21, 18},首先步长为2,分成段23 10、8 5、7 21、18四段,最后一段只有一个元素。首先分段归并10 23、5 8、7 21、18等,再次步长为4,分成10 23 5 8、7 21 18两段,注意第二段只有3个元素,3 > step/2,因为上次的循环步长为step/2,最后一段中的前step/2个元素一定有序的,后面几个不一定了。因此最后段归并时,注意找好这个点进行归并。再最后一次步长为8,进行归并。
#include <iostream>
using namespace std;
void merge(int a[], int p, int q, int r);
/* 归并排序算法循环实现 */
void mergeSort(int a[], int n)
{
if(a == NULL || n <= 0)
return;
for(int step = 2; step/2 < n; step *= 2){ //步长:2,4,8,16...,结束条件是步长
for(int i = 0; i < n; i += step){ //每一段
int start = i; //段首
int end = i + step - 1; //段尾
if(i + step < n){ //最后一段可能出现元素不够的情况
int mid = (start + end) / 2;
merge(a, start, mid, end);
}
else{ //如果最后一次,元素个数不够够一整段
if(i + step/2 -1 >= n-1) //如果够一半,这一半一定是有序的
break;
merge(a, i, i + step/2 - 1, n - 1);
}
}
}
}
/* 合并两个数组 */
void merge(int a[], int p, int q, int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int *c1 = new int[n1];
int *c2 = new int[n2];
for(int i = 0; i < n1; i++)
c1[i] = a[p + i];
for(int i = 0; i < n2; i++)
c2[i] = a[q + 1 + i];
int i = 0, j = 0, k = p;
while(i < n1 && j < n2){
if(c1[i] <= c2[j])
a[k++] = c1[i++];
else
a[k++] = c2[j++];
}
if(i < n1){
while(i < n1)
a[k++] = c1[i++];
}
if(j < n2){
while(j < n2)
a[k++] = c2[j++];
}
delete c1, c2;
}
int main()
{
// int a[] = {23}; // 1
// int a[] = {2, 10};
// int a[] = {10, 2};
// int a[] = {10, 2, 11};
// int a[] = {11, 10, 2};
// int a[] = {12, 10, 15, 13};
// int a[] = {12, 10, 15, 11};
// int a[] = {23, 10, 8, 5, 7};
// int a[] = {23, 10, 8, 5, 7, 21};
// int a[] = {23, 10, 8, 5, 7, 21, 100};
int a[] = {23, 10, 8, 5, 7, 21, 18, 100};
int n = sizeof(a)/sizeof(int);
mergeSort(a, n);
for(int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}