归并排序的核心思想:
如果有两个已经有序的数组
我们可以创建一个新的数组,然后比较大小,将两个有序数组的数据一个一个的拿下来放到新数组中。这样完成之后就是一个有序的数组。
再把值赋给原数组即可完成排序。
关键点:前提是两个有序数组
接下来实现代码框架
void _merge_sort(int* arr,int*tmp,int left,int right)
{
if (left >= right)//递归终止条件
{
return;
}
int mid = (left + right) / 2;
_merge_sort(arr,tmp, left, mid);//要排序的前提是mid左边的已经有序,因此继续递归
_merge_sort(arr,tmp, mid+1, right);//要排序的前提是mid右边已经有序,因此继续递归
//上面是递归版归并排序的思想核心。
//实现两个有序数组结合新生成一个有序数组
int a1 = left;
int a2 = mid + 1;
int i = left;
while (a1 <= mid&&a2 <= right)
{
if (arr[a1] < arr[a2])
{
tmp[i] = arr[a1];
a1++;
}
else
{
tmp[i] = arr[a2];
a2++;
}
i++;
}
while (a1 <= mid)
{
tmp[i] = arr[a1];
i++;
a1++;
}
while (a2 <= right)
{
tmp[i] = arr[a2];
i++;
a2++;
}
for ( i = left; i <=right; i++)
{
arr[i] = tmp[i];
}
}
解释:上面代码关键部分是思想核心。
我们知道,如果一个数组如果只有一个数,那么它是有序的。
那么我们就可以排序有两个数的数组(因为对半分开,两边都是有序的)
因此我们只要递归到两个数的数组即可开始排序
这样,每回退一层,两侧的数都是有序的。
从而实现排序
如果上述可以理解。
可以看下归并排序的非递归版本
模拟思路,注意边界条件即可
下面只展示代码。有疑问可以私信
void none_merge_sort(int*arr,int sz)
{
int * tmp = (int *)malloc(sizeof(int)*sz);
int left = 0;
int right = sz - 1;
int n = 1;
while (n <sz)
{
for (int i = 0; i < sz; i+=2*n)
{
int begin1 = i;
int end1 = i + n - 1;
int begin2 = i + n;
int end2 = i + 2 * n - 1;
int j = begin1;
//限定条件
if (end1 >= sz)
{
end1 = sz - 1;
}
if (begin2 >= sz)
{
begin2 = sz - 1;
}
if (end2 >= sz)
{
end2 = sz - 1;
}
while (begin1 <= end1&&begin2 <= end2)
{
if (arr[begin1] < arr[begin2])
{
tmp[j] = arr[begin1];
begin1++;
}
else
{
tmp[j] = arr[begin2];
begin2++;
}
j++;
}
while (begin1 <= end1)
{
tmp[j] = arr[begin1];
j++;
begin1++;
}
while (begin2 <= end2)
{
tmp[j] = arr[begin2];
j++;
begin2++;
}
}
for (int k = 0; k < sz; k++)
{
arr[k] = tmp[k];
}
n *= 2;
}
free(tmp);
tmp = NULL;
}