归并排序是通过递归的思想实现的排序算法。
什么是递归呢:
递归就是需要我们转变思想,思考将一个大事转变为一个个与原问题相似的小事。
而我们需要对一个整型数组排序,应该怎样将排序整个数组这么大的规模转变为排序两个数这么小的规模呢。
假设我们需要排序的整型数组储存的数据为:6 7 4 1 2 5 3 8
那么我们可以这样想,可不可以将它的左半部分排序,再将它的右半部分排序,然后再合并左半部分和右半部分呢。
当然可以,我们将排序6 7 4 1 2 5 3 8这个任务变为排序6 7 4 1和 2 5 3 8后再合并
同样排序6 7 4 1这个任务可以变为排序6 7和4 1后再合并,而排序2 5 3 8这个任务可以变为排序2 5和 3 8后再合并
排序6 7可以变为排序6和7后再合并, 排序4 1可以变为排序4和1后再合并,排序2 5可以变为排序2和5后再合并,排序3 8可以变为排序3和8后再合并
而6, 7, 4 ,1 ,2 ,5 ,3, 8都只有一位数已经有序了就不需要排序了
因此我们现在可以假设我们已经有了合并左半部分和右半部分的函数(做递归就是要耍无赖,哎我没写但我就觉得我有),我们就可以写出下面的递归:
void Sort(int arr[],int left,int right) //将数组arr上下标从left到right的数据排序
{
if (left == right)
{
return;
}
int mid;
mid = left + (right - left) / 2;
Sort(arr, left, mid); //将左半部分排好序
Sort(arr,mid + 1, right); //将右半部分排好序
merge(arr, left, mid, right); //将有序的左半部分和右半部分合并
}
注意我们在写递归的时候一定要想清楚并先写递归停止的条件(递归条件考虑不好就很容易导致栈溢出),我们的这个递归操作什么时候停止呢,当然是在排序只有一位数时便可以停止了,此时left和right指向的数据相同,则我们在left == right时要结束递归行为.
此时我们就需要考虑将有序的左半部分和右半部分合并的函数了(毕竟不能真不写嘛),首先在上面看到的merge函数有4个参数,我们为什么要传这4个参数呢
因为首先传入数组arr是毋庸置疑的因为要排序它的左半部分和右半部分嘛
其次我们要想知道数组要排序的左半部分和右半部分范围,我们就必须要知道左边,中间和右边的位置,所以要传入left, mid, right。
先奉上合并的merge()函数的实现:
void merge(int arr[], int left, int mid, int right)
{
int help[MAXSIZE]; //辅助数组help
int p1 = left, p2 = mid + 1,i=0;
while (p1 <= mid && p2 <= right) //当前部分和后部分有序部分都没溢出的情况
{
if (arr[p1] <= arr[p2])
{
help[i++] = arr[p1++];
}
else
{
help[i++] = arr[p2++];
}
}
while (p1 <= mid) //前部分没有溢出后部分溢出的情况
{
help[i++] = arr[p1++];
}
while (p2 <= right) //后部分没有溢出前部分溢出的情况
{
help[i++] = arr[p2++];
}
for (int i = left,j=0; i <= right; i++,j++) //用help数组中的有序数据覆盖掉arr数组中的数据
{
arr[i] = help[j];
}
}
merge()函数主要就是建立了一个辅助数组help【】,我们定义3个指针,分别指向左半部分的首位整数,右半部分的首位整数和help数组
然后比较指针指向的左半部分的整数和右半部分的整数谁小,小的就放入help数组中,直到左,右部分其中的一部分溢出为止(左右部分必有一部分溢出),若左部分溢出即p1>mid,说明就可以将右半部分剩下的数全部输入help数组。
arr数组中的所有数遍历完后,help数组中储存的便是有序的数据,将数据原封不动复制进arr数组便完成了merge()函数的实现。
主函数:
int main()
{
int n;
int arr[MAXSIZE];
printf("输入多少数据?");
scanf("%d", &n);
int num;
for (int i = 0; i < n; i++)
{
scanf("%d", &num);
arr[i] = num;
}
Sort(arr, 0, n - 1);
for (int i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
所有递归都可以写为迭代的形式,各位可以想一下怎么写