思路:把待排序序列分成相同大小的兩個部分,依次對這兩部分進行歸併排序,完畢之後再按照順序進行合併。具體思路請參考算法導論,以下實現按算法導論中思路來寫的。
性能:穩定的排序算法,時間複雜度最差、平均、最好都是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;
}