一、定义:
二、递归思路:
✨✨首先根据定义,我们会发现和二叉树又又又联动了🤩🤩
🚗🚗发现了吗???我们好像是先从根开始的,这说明了啥???先动左子树,再动右子树,再动根,这个不就是🤔后续遍历么?
✨没错,确实就是模仿的后续遍历实现递归
👻思路是这样的:
将数组分成2部分,其实相当于2个数组,这2个数组首先得是有序的,再进行有序数组的合并;
👉递归传递的是区间,区间相等即left==right时,不就只有一个数据,根本分不了区间了,此时可以看作就是有序的哦 也就是👉画绿线的那一行
这也就是我们的结束条件:👉👉只有一个元素,递归结束,开始回推,回推的过程就开始合并2个有序数组的进行
✨✨接下来是回推的过程这一过程也就是我们实现合并2个有序数组过程; 首先我们对[0,1]这个区间二分,分成的区间都只有一个元素,可以看成有序,进行比较合并合并 ,回到上一层函数后,进入右边对[2,3]这个区间二分,同理,直接比较合并击即可🐸
🧑🎓🧑🎓🤔后续遍历是左、右子树然后是根节点,不就是回到10 6 7 1的这一层么,此时这里应该是如下所示的样子,然后对这个区间进行二分,分成的2个区间已然是有序的,进行2个数组合并即可,放到tmp中
放到tmp数组中之后,我们可以通过memcpy函数将tmp拷贝回原数组[0,3]这个区间;回推的过程依次类推
三、非递归:
将递归变成迭代的思想
🧑🎓之前用栈是因为我们来模拟递归,但是这里进行排序是在回推的时候进行的,在这里栈已经不行了 🧑🎓
那就试试直接用循环写呗,还记得之前插入排序的gap嘛???
🤔这里我们用gap记录元素个数,一开始gap=1 ,一组里面一个元素
区间不就是👉👉这样的
然后第就是2个数归并
四四归,但是我们的最右边凑不出来四组,怎么办🤔🤔仔细看,不归并也行呢??这个是有序数组,左边的归并后就是有序数组了,最后就是👉
左边 和 右边 归并
✨✨核心在于gap组的控制:gap 2倍2倍的长,但是不能超过数组长度,区间二分嘛,2个区间
begin1,en1 begin2和end2 就是二分的2区间,将这2个区间进行归并
✨ 这里的数据是偶数,如果是奇数了???先别急🤗这个写法会发生越界访问,出不了结果的
👉看看我打印的区间:第一行正常,第二行正常,第三行,[12,15]越界了,第四行[8,15]一部分越界了
说明需要修改,卡看越界的特点,我们是【begin1,end1】和 【begin2,end2】2个区间归并
第三行越界的区间正好是begin2 是不是可以去处理一下这个区间,当begin2>=n时候,打破循环,前面【8,11】在上一层下来的时候已经归并好了的
最后一层越界的是 end2,这里处理起来应该是要去修正,因为最后一行,要将[0,7][8,11]归并起来所以可以进行修正end2 = n-1
四、代码:
递归:
//子函数:实现递归
void _MergeSort(int* tmp, int* a, int left, int right)
{
if (left >= right)
{
return;
}
//防止栈溢出的写法,当然直接写(right+left)/2也行
int mid = ((right-left)>>1)+left;
_MergeSort(tmp, a, left, mid);
_MergeSort(tmp, a, mid + 1,right);
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right;
int i = 0;
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++];
}
memcpy(a + left, tmp, (right - left + 1)*sizeof(int));
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
_MergeSort(tmp, a, 0, n-1);
free(tmp);
tmp = NULL;
}
非递归:
//非递归归并
void MergeSortNonR(int* a, int n)
{
//额外创造一个空间
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i+=2*gap)
{
int begin1 = i;
int end1 = i + gap - 1;
int begin2 = i + gap;
int end2 = i + 2 * gap-1;
int j = i;
if (begin2>=n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
printf("[%d,%d][%d,%d]", begin1, end1, begin2, end2);
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[j++] = a[begin1++];
}
else
{
tmp[j++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[j++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[j++] = a[begin2++];
}
memcpy(a + i, tmp+i, sizeof(int)*(end2 - i + 1));
}
putchar('\n');
gap *= 2;
}
free(tmp);
tmp = NULL;
}
✨期待你的关注