最近工作中要用到排序,当然要选择O(nlgn)时间复杂度的算法,还要求是稳定的,周末就温习了一下排序算法,归并排序刚好能满足。自己也想练练手,就先实现了简单的对递归版本,之后实现了非递归的版本。它的空间复杂度为O(n)。 因为递归版本会使用函数堆栈,深度受到栈内存的限制,所以数据量不能太大,需要注意下。
//【归并排序--递归版本】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
void merge(int a[], int m, int n)
{
int *b = (int*)malloc(sizeof(int)*n);
assert(b != NULL);
memcpy(b, a, sizeof(int)*n);
int i = 0, j = m, k = 0;
while(i < m && j < n)
{
if (b[i] <= b[j])
{
a[k++] = b[i];
i++;
}
else
{
a[k++] = b[j];
j++;
}
}
if (i < m)
{
while (i < m) a[k++] = b[i++];
}
else
{
while (j < n) a[k++] = b[j++];
}
}
void mergeSort(int a[], int n)
{
if (n <= 1) return;
if (n == 2)
{
if (a[0] > a[1])
swap(a+0, a+1);
return;
}
int m = n/2;
mergeSort(a, m);
mergeSort(a + m, n - m);
merge(a, m, n);
}
void setRandData(int a[], int n)
{
srand(time(NULL));
for (int i = 0; i < n; i++)
{
a[i] = rand();
}
}
int main()
{
const int N = 10000000;
int *a = (int*)malloc(sizeof(int) * N);
assert(a != NULL);
setRandData(a, N);
//for (int i = 0; i < N; i++)
//{
// printf("%d\t", a[i]);
//}
printf("\n");
clock_t t0 = clock();
mergeSort(a, N);
clock_t t1 = clock();
printf("Take time %d ms\n", t1 - t0);
for (int i = N/2; i < N && i < (N/2 + 200); i++)
{
printf("%d ", a[i]);
}
system("pause");
return 0;
}
//【归并排序--非递归版本】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
inline int min(int a, int b)
{
return a < b ? a : b;
}
void setRandData(int a[], int n)
{
srand(time(NULL));
for (int i = 0; i < n; i++)
{
a[i] = rand() * rand();
}
}
void mergeSort(int a[], int n)
{
int i, j, t, start1, end1, start2, end2, len;
int *b = (int*)malloc(sizeof(int) * n);
assert(b != NULL);
len = 1; //len为每次分块的大小,即按照1,2,4,6,8,...,n增长
while (len < n)
{
t = 0;
i = 0;
j = i + len;
while (j != n)
{
//start1,end1,start2,end2用于表示进行比较的两个数据块下标,
//坐标范围分别为[start1,end1),[start2,end2)。
start1 = min(n, i);
end1 = min(n, i + len);
start2 = min(n, i + len);
end2 = min(n, i + len + len);
i = start1;
j = start2;
while (i < end1 && j < end2)
{
if (a[i] <= a[j])
{
b[t++] = a[i++];
}
else
{
b[t++] = a[j++];
}
}
if (i < end1)
{
while (i < end1)
b[t++] = a[i++];
}
else
{
while (j < end2)
b[t++] = a[j++];
}
//assert(i == end1 && j == end2 && t == end2);
i = t;
}
len = min(n, len * 2);
memcpy(a, b, sizeof(int) * n);
}
free(b);
}
int main()
{
const int N = 100000000;
int *a = (int*)malloc(sizeof(int) * N);
assert(a != NULL);
setRandData(a, N);
//for (int i = 0; i < N; i++)
//{
// printf("%d\t", a[i]);
//}
printf("\n");
clock_t t0 = clock();
mergeSort(a, N);
clock_t t1 = clock();
printf("Take time %d ms\n", t1 - t0);
for (int i = N/2; i < N && i < (N/2 + 100); i++)
{
printf("%d \n", a[i]);
}
system("pause");
return 0;
}
【归并排序-使用模板】
mergesort.h
#ifndef __MERGESORT_H
#define __MERGESORT_H
namespace MyNamespace
{
typedef int (*Comparer)(const void *a, const void *b);
template <typename T>
int defaultCompare(T *a, T *b)
{
if (*a == *b) return 0;
return *a < *b ? -1 : 1;
}
template <typename T>
void arrayCopy(T *a, const T *b, int n)
{
while (--n >= 0) a[n] = b[n];
}
inline int minIndex(int a, int b)
{
return a < b ? a : b;
}
template <typename T>
int mergeSort(T a[], int n, Comparer comparer)
{
T *b = NULL;
int i, j, t, start1, end1, start2, end2, len;
int cmpResult;
b = new T[n];
if (b == NULL) return -1;
//len为每次分块的大小,即按照1,2,4,6,8,...,n增长
len = 1;
while (len < n)
{
t = 0;
i = 0;
j = i + len;
while (j != n)
{
//start1,end1,start2,end2用于表示进行比较的两个数据块下标,
//两个分块的下标范围为[start1,end1),[start2,end2)。
start1 = minIndex(n, i);
end1 = minIndex(n, i + len);
start2 = minIndex(n, i + len);
end2 = minIndex(n, i + len + len);
//i,j分别表示当前进行比较的两个元素的下标
i = start1;
j = start2;
while (i < end1 && j < end2)
{
if (comparer != NULL)
cmpResult = comparer(a+i, a+j);
else
cmpResult = defaultCompare(a+i, a+j);
b[t++] = (cmpResult <= 0) ? a[i++] : a[j++];
}
if (i < end1)
{
while (i < end1)
b[t++] = a[i++];
}
else
{
while (j < end2)
b[t++] = a[j++];
}
//assert(i == end1 && j == end2 && t == end2);
i = t;
}
len = minIndex(n, len * 2);
arrayCopy(a, b, n);
}
delete []b;
b = NULL;
return 0;
}
template <typename T>
int mergeSort(T a[], int n)
{
return mergeSort(a, n, NULL);
}
};
#endif //__MERGESORT_H
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "mergesort.h"
using namespace std;
int myComparer(const int *a, const int *b)
{
if (*a == *b) return 0;
return *a < *b ? -1 : 1;
}
int myComparer2(const void *a, const void *b)
{
if (*(int*)a == *(int*)b) return 0;
return *(int*)a < *(int*)b ? -1 : 1;
}
struct S
{
int a;
string str;
bool operator== (const S &o)
{
return (a == o.a) && (str == o.str);
}
bool operator< (const S &o)
{
if (a != o.a) return a < o.a;
return str < o.str;
}
};
int main()
{
S ss[] = {
{2, "ok"},
{1, "hi"},
{4, "aa"}
};
int a[] = {3,2,7,9,8};
//MyNamespace::mergeSort(a, 5, (MyNamespace::Comparer)myComparer);
MyNamespace::mergeSort(a, 5, myComparer2);
printf("%d %d %d %d %d\n", a[0], a[1], a[2], a[3], a[4]);
//
//a[1] = 100;
//MyNamespace::mergeSort(a, 5);
//printf("%d %d %d %d %d\n", a[0], a[1], a[2], a[3], a[4]);
MyNamespace::mergeSort(ss, 3);
printf("%d,%s %d,%s\n", ss[0].a, ss[0].str.c_str(), ss[1].a, ss[1].str.c_str());
system("pause");
return 0;
}
输出:
2 3 7 8 9
1,hi 2,ok
请按任意键继续. . .