一、归并排序的基本思想
1、归并排序算法是一类不同的排序方法,归并的含义是将两个或两个以上的有序数据序列合并成一个新的有序数据序列,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 2、基本思想是假设数组A有N个元素,数组A是N个有序的子序列组成,每个子序列的长度为1,两两重复合并,得到一个长度为N的有序数据序列为止。 3、合并算法的核心操作就是将一维数组中前后相邻的两个两个有序序列合并成一个有序序列,合并算法也可以采用递归算法来实现。
归并排序的核心步骤:
二、递归实现归并
代码如下(示例):
void _MergeSort(int* a, int* tmp, int left, int right)
{
if (left >= right)
{
return;
}
int mid = left + (right - left) / 2;
_MergeSort(a, tmp, left, mid);
_MergeSort(a, tmp, mid + 1, right);
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = left;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
for (int i = left; i <= right; i++)
{
a[i] = tmp[i];
}
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int)*n);
_MergeSort(a, tmp, 0, n - 1);
}
三、非递归实现归并
非递归的实现方式,采用自底向上的思路。 对数组进行 1个一组进行拆分-排序合并; 2个一组进行拆分-排序合并; 4个一组进行拆分-排序合并; 8个一组的方式进行拆分…
代码如下(示例):
void MergeSortNonR(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int)*n);
if (!tmp)
{
printf("malloc fail\n");
exit(-1);
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
if (end1 >= n)
{
end1 = n - 1;
}
if (begin2 >= n)
{
begin2 = n - 1;
end2 = n - 1;
}
if (end2 >= n)
{
end2 = n - 1;
}
int index = i;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
}
for (int i = 0; i < n; i++)
{
a[i] = tmp[i];
}
gap *= 2;
}
}
void MergeSortNonR(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int)*n);
if (!tmp)
{
printf("malloc fail\n");
exit(-1);
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
if (end1 >= n || begin2 >= n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
int index = i;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
for (int j = i; j <= end2; j++)
{
a[j] = tmp[j];
}
}
gap *= 2;
}
}
总结
1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。 2. 时间复杂度:O(N*logN) 3. 空间复杂度:O(N) 4. 稳定性:稳定
|