算法思想:
归并排序是分治法的典型应用,其思想是不断地将两个有序的数组合并为一个有序数组。
递归实现
#include <stdio.h>
void Merge(int a[], int left, int m, int right);
void MergeSortAux(int a[], int left, int right);
void MergeSort(int a[], int len);
int main(void) {
int len = 0;
printf("请输入待排数的个数: ");
scanf("%d", &len);
int a[len];
printf("请输入待排的数:\n");
for (int i = 0; i < len; ++i) {
scanf("%d", &a[i]);
}
MergeSort(a, len);
printf("排序后的结果为:\n");
for (int i = 0; i < len; ++i) {
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
void Merge(int a[], int left, int mid, int right) {
int arrtmp[right - left +1]; //备份数组a
int i = left, j = mid + 1; //i,j分别指向两个子数组的开头
for (int m = left; m <= right; ++m) { //将数组a中的元素映射到数组arrtmp中,以作备份
arrtmp[m - left] = a[m];
}
for (int m = left; m <= right; ++m) {
if (i > mid) {
a[m] = arrtmp[j - left];
++j;
}
else if (j > right) {
a[m] = arrtmp[i - left];
++i;
}
else {
if (arrtmp[i - left] < arrtmp[j - left]) {
a[m] = arrtmp[i - left];
++i;
}
else {
a[m] = arrtmp[j - left];
++j;
}
}
}
}
void MergeSortAux(int a[], int left, int right) {
if (left < right) {
int mid = (left + right) /2;
MergeSortAux(a, left, mid);
MergeSortAux(a, mid + 1, right);
Merge(a, left, mid, right);
}
}
void MergeSort(int a[], int len) {
MergeSortAux(a, 0, len - 1);
}
非递归实现
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
void MergeSort(int a[], int len);
void MergePass(int a[], int b[], int s, int n);
void Merge(int c[], int d[], int l, int m, int r);
void PrintArray(int a[], int len);
int main(void) {
int a[] = {1, 3, 5, 2, 4};
MergeSort(a, 5);
PrintArray(a, 5);
return 0;
}
void MergeSort(int a[], int len) {
int *b = (int *)malloc(sizeof(int) * len);
if (NULL == b) {
printf("malloc\n");
exit(-1);
}
int s = 1;
while (s < len) {
MergePass(a, b, s, len);
s += s;
MergePass(b, a, s, len);
s += s;
}
free(b);
}
void MergePass(int a[], int b[], int s, int len) {
int i = 0;
while (i <= len - 2 * s) {
Merge(a, b, i, i + s - 1, i + 2 * s - 1);
i += 2 * s;
}
if (i + s < len) {
Merge(a, b, i, i + s -1, len - 1);
}
else {
while(i < len) {
b[i] = a[i];
++i;
}
}
}
void Merge(int a[], int b[], int l, int m, int r) {
int k = l; //标记数组b
int i = l, j = m + 1; //标记数组a的两部分
while (i <= m || j <= r) {
if (i > m) {
b[k++] = a[j++];
}
else if (j > r) {
b[k++] = a[i++];
}
else if (a[i] < a[j]) {
b[k++] = a[i++];
}
else {
b[k++] = a[j++];
}
}
}
void PrintArray(int a[], int len) {
for (int i = 0; i < len; ++i) {
printf("%d ", a[i]);
}
printf("\n");
}
在实际应用中,待排序的数中,里面会存在一些已经有序的数据,在实际应用归并排序中,可以待排序的数中已经有序的数分成一组,这可以提高排序的效率。
自然归并排序
#include<iostream>
using namespace std;
#define N 100
int boundary_size;
int boundary[N];
void Merge(int c[], int d[], int l, int m, int r);
void PrintArray(int a[], int n);
void GetBPoint(int a[], int b[], int n);
void MergePass(int x[], int y[], int s, int n);
void MergeSort(int a[], int n);
int main(void) {
int n;
cin >> n;
int* a = new int [n];
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
GetBPoint(a,boundary,n);
MergeSort(a,n);
PrintArray(a,n);
return 0;
}
void GetBPoint(int a[], int b[], int n) {
int j = 0;
b[j++] = 0;
for(int i = 0;i < n-1;i++) {
if(a[i+1] < a[i])
b[j++] = i+1;
}
boundary_size = j;
}
void MergeSort(int a[], int n) {
int *b = new int [n];
if (NULL == b) {
cout << "new\n";
}
int s = 1;
while(s < boundary_size) {
MergePass(a,b,s,n);
s += s;
MergePass(b,a,s,n);
s += s;
}
delete[] b;
}
void MergePass(int x[], int y[], int s, int n) {
int i = 0;
while(i <= boundary_size - 2 * s) {
int r = ((i+2*s) < boundary_size) ? boundary[i+2*s] : n;
Merge(x, y, boundary[i], boundary[i+s]-1, r-1);
i += 2 * s;
}
if(i + s < boundary_size)
Merge(x, y, boundary[i], boundary[i+s]-1, n-1);
else
if(i < boundary_size) {
for(int j = boundary[i]; j <= n-1; j++)
y[j] = x[j];
}
}
void Merge(int c[], int d[], int l, int m, int r) {
int i = l, j = m + 1, k = r;
while((i <= m) && (j <= r)) {
if(c[i] <= c[j])
d[l++] = c[i++];
else
d[l++] = c[j++];
}
if(i>m)
for(int q = j; q <= r; q++)
d[l++] = c[q];
else
for(int p = i; p <= m; p++)
d[l++] = c[p];
}
void PrintArray(int a[], int n) {
for(int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
}
时间复杂度
归并排序排序是一种稳定的排序,时间复杂度为O(nlogn)