归并排序
递归算法
void _MergeSort(int * a, int left, int right, int * tmp)
{
if (left >= right)
return;
int mid = (left + right) >> 1;
_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid + 1, right, tmp);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int i = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
tmp[i++] = a[begin1++];
else
tmp[i++] = a[begin2++];
}
//拷贝回去
for (int j = left; j <= right; ++j)
{
a[j] = tmp[j];
}
}
void MergeSort(int * a, int n)
{
int * tmp = (int *)malloc(sizeof(int)*n);
if (tmp == NULL)
{
printf("malloc fail\n");
exit(-1);
}
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
}
非递归算法
//void Merge(int* a, int begin, int mid, int end, int * tmp)
//{
// int begin1 = begin;
// int end1 = mid;
// int begin2 = end1 + 1;
// int end2 = end;
// int i = begin;
// while (begin1 <= end1 && begin2 <= end2)
// {
// if (a[begin1] <= a[begin2])
// tmp[i++] = a[begin1++];
// else
// tmp[i++] = a[begin2++];
// }
// //判断是否有未合并的元素
// if (begin1 < end1)
// {
// memcpy(tmp + i, a + begin1, sizeof(int)*(end1 - begin1 + 1));
// }
// if (begin2 < end2)
// {
// memcpy(tmp + i, a + begin2, sizeof(int)*(end2 - begin2 + 1));
// }
//
// //合并后拷贝到原数组中
// memcpy(a + begin, tmp + begin, sizeof(int)*(end - begin) + 1);
//
//}
void _Merge(int* a, int* tmp, int begin1, int begin2, int end1, int end2)
{
int i = begin1;
int j = begin1;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
tmp[i++] = a[begin1++];
else
tmp[i++] = a[begin2++];
}
while (begin1 <= end1)
tmp[i++] = a[begin1++];
while (begin2 <= end2)
tmp[i++] = a[begin2++];
for (; j <= end2; ++j)
a[j] = tmp[j];
}
void MergeSortNonR(int * a, int n)
{
int * tmp = (int *)malloc(sizeof(int)*n);
if (tmp == NULL)
{
printf("malloc fail\n");
exit(-1);
}
int step = 1;
while (step < n)
{
for (int i = 0; i < n; i += 2 * step)
{
/*int begin = i;
int mid = i + step - 1;
if (mid >= n - 1)
continue;
int end = i + 2 * step - 1;
if (end >= n)
end = n - 1;
Merge(a, begin, mid, end, tmp);*/
int begin1 = i, end1 = i + step - 1, begin2 = i + step, end2 = i + 2 * step - 1;
//如果第二个小区间不存在,就不需要归并了,结束本次循环
if (begin2 >= n)
break;
//如果第二个小区间存在,但是第二个小区间不够gap个,结束位置越界了,需要修正一下
if (end2 >= n)
end2 = n - 1;
_Merge(a, tmp, begin1, begin2, end1, end2);
}
step *= 2;
}
free(tmp);
}
归并排序还分为
内排序:数据量相对少一些,可以放在内存中排序
外排序:数据量较大,内存中放不下,数据放到磁盘文件中,需要排序(把文件分为好几个文件,在进行归并排序,存入另一个文件中)