归并排序 从归并两个字眼可以感觉出 里面有递归
确实有递归 从标题也可以看出来 对于递归如果理解不是太好 就只能在纸上画图 这也是没有办法的办法 总不能不解决这个问题吧 我也是这样过来的 希望你能坚持下去 看着下面的图痛苦下去吧
这个图对递归的理解还是很重要的
![](https://img-blog.csdnimg.cn/img_convert/a3860f9f57d4ec0a43ea4c5041ffbe66.png)
从上图可以看出 归并排序 是将原数组通过不断分解 直到拆分为单个元素为止
再对单个元素进行两两比较 然后按照顺序考回数组中(不理解先看上面的图)
然后再对数组大小为二的数组进行合并 以此类推 直到合并为原数组 就有序了
这个排序理解起来确实不是很好理解 毕竟是和递归扯上关系的 上面也说了你应该怎样去理解他
不然你之后遇到递归就只能绕道而行
咱们先不管什么递归不递归 (递归不就是分 不断地分直到不能分为止)
先考虑 分完之后如何合并两个数组
void _MergeSort(int* a, int left, int right, int* tmp)
{
int mid = (left + right) / 2;
// [left, mid] [mid+1, right] 有序
//就这样先将原数组分为两个子数组
int begin1 = left, end1 = mid;//[left, mid]
int begin2 = mid+1, end2 = right;//[mid+1, right]
int i = left;//定位两个区间段比较之后在tmp数组中的开头位置
//上文说过 你是将分完的数组排序后再考回原数组
//根据上面的图 下半部分 处理时
//笨点的办法就是 自己排一个区间段 自己再开辟一个对应大小数组 不断合并不断开辟 最后将开辟的数组 考回原数组
//太麻烦了!!!
//那就直接干脆 搞一个和原数组大小相同的数组tmp
//将排序之后的数组放到tmp对应的区间段
//你既然要考回tmp数组 那就要有个位置 不然就乱套了
//将原本数组该区间段的元素进行排序 (区间段先小后大)
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++];
}
// tmp 数组拷贝回a
for (int j = left; j <= right; ++j)
{
a[j] = tmp[j];
}
}
再啰嗦一下上面的实现思路
将数组层层拆分 拆成单个的数字 再将他们比较排序放入tmp数组中 对应的区间段
那咱们讲讲递归部分
进入第一个函数递归之后 先完成第一个函数 再完成第二个函数的递归
因为你只能先完成一个函数的调用再进行下一个函数的调用
这个调用的实现逻辑其实是先完成一个分支再完成下一个分支
也就是先将10 和 6 排序之后 再调用下一个函数 进行排序 7 和1 如此反复
不是一上来就是上面的图 他有个先后顺序 从左到右依次进行 区间段由小到大 逐渐增大
你可以有次序的画一画 这个递归思路 我认为上图可以让你理解清楚
如果不清楚 可能是你递归思路有点乱 理理你的思路 一步一步按照代码去画 应该会很好理解
void _MergeSort(int* a, int left, int right, int* tmp)
{
//递归 肯定不能死循环下去 需要条件让它停止
if (left >= right)
{
return;
}
//int mid = (left + right) / 2;
int mid = left + (right - left)/2;防止溢出 int 有最大值
// [left, mid] [mid+1, right] 有序
_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;//定位两个区间段比较之后在tmp数组中的开头位置
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++];
}
// tmp 数组拷贝回a
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);
tmp = NULL;
}
以上就是归并排序 这块需要你去在纸上画画理解理解递归 如果不能理解 你可以试试理解非递归版本 ~
如有不懂 留言私信~