归并排序
研究了这么多算法以后,小桂子颇有收获,基本自认为排序算法已经全部掌握,于是就想卖 弄一下自己的“算法内功”,另一方面为了交流推广,把这些算法传播出去,就召开一个全国算 法大赛,集思广益,征集更牛逼的算法!
在算法大赛上,有两位白发葱葱的老者提出的算法让小桂子自惭形秽,感叹良多。。。
其中一位叫归并长老的老者,提出了如下的排序方法:
当两个组数据已经有序,我们可以通过如下方式(以下简称归并大法)让两组数据快速有序
我们可以依次从两组中取最前面的那个最小元素依次有序放到新的数组中,然后再把新数组 中有序的数据拷贝到原数组中,快速完成排序
依靠这种思想,归并长老提出了如下的排序方法!
具体步骤
对于下面这一组待排序的数组
先以中间为界,把其均分为 A 和 B 两个数组(如果是奇数个,允许两组数相差一个)
如果 A 和 B 两组数据能够有序,则我们可以通过上面的方式让数组快速排好序。
此时,A 组有 4 个成员, B 组有 5 个成员, 但两个数组都无序,然后我们可以采用分治法继 续对 A 组和 B 组进行均分,以 A 组为例,又可以均分 A1 和 A2 两个组如下:
均分后,A1 组和 A2 组仍然无序,继续利用分治法细分,以 A1 组为例,A1 又可分成如下 两组
数组细分到一个元素后,这时候,我们就可以采用归并法借助一个临时数组将数组 A1 有序化! A2 同理!
依次类推,将 A1 组和 A2 组归并成有序的 A 组, B 组同理!
最后,将 A 和 B 组使用归并大法合并,就得到了完整的有序的结果!
参考:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 要先前排好序才行, 归并大法 */
void mergAdd_demo1(int arr[], int left, int mid, int right)
{
int temp[64] = { 0 };
int i = left; /* 指向左边数组最小的元素位置 */
int j = mid; /* 指向右边数组最小的元素位置 */
int k = 0; /* 临时数组的下标 */
while (i < mid && j <= right)
{
if (arr[i] < arr[j])
{
temp[k++] = arr[i++];
}
else
{
temp[k++] = arr[j++];
}
}
while (i < mid)
{
temp[k++] = arr[i++];
}
while (j <= right)
{
temp[k++] = arr[j++];
}
/* 把 temp 中的内容拷贝到arr数组中 */
memcpy(arr + left, temp, sizeof(int) * (right - left + 1));
}
void mergAdd_demo2(int arr[], int left, int mid, int right, int *temp)
{
//int temp[64] = { 0 };
int i = left; /* 指向左边数组最小的元素位置 */
int j = mid; /* 指向右边数组最小的元素位置 */
int k = left; /* 临时数组的下标 */
while (i < mid && j <= right)
{
if (arr[i] < arr[j])
{
temp[k++] = arr[i++];
}
else
{
temp[k++] = arr[j++];
}
}
while (i < mid)
{
temp[k++] = arr[i++];
}
while (j <= right)
{
temp[k++] = arr[j++];
}
/* 把 temp 中的内容拷贝到arr数组中 */
memcpy(arr + left, temp+left, sizeof(int) * (right - left + 1));
}
/* 归并排序 */
void mergesort(int arr[], int left, int right, int *temp)
{
int mid = 0;
if (left < right)
{
mid = left + (right - left) / 2; /* 找中间值 */
mergesort(arr, left, mid, temp);
mergesort(arr, mid + 1, right, temp);
mergAdd_demo2(arr, left, mid + 1, right, temp);
}
}
int main()
{
int beauties[] = { 11,13,61,17,21,41,51,23,32,454 };
int len = sizeof(beauties) / sizeof(beauties[0]);
int* temp = new int[len];
mergesort(beauties, 0, len -1, temp);
printf("执行归并大法后\n");
for (int i = 0; i < len; i++)
{
printf(" %d", beauties[i]);
}
printf("\n");
system("pause");
return 0;
}
运行环境: vs2019
运行结果:
结语:
学到的知识要, 多复习, 多总结, 多敲. 需要时间的积累, 才能引起质的改变. 自己写不出来的永远是别人的.
分享一下我的技巧: 代数法把具体的数字带进去, 看看能能能找到规律(掌握思想).
还有就是画图, 也很重要. 用笔画出来, 把数代进去, 方法虽然笨, 但真的很实用, 好记忆不如烂笔头!!! 还有多用debug(调试工具)
我是小白, C/C++功力…, 你懂得, 写的文章可能不是很好. 如果存在问题, 欢迎大神给予评判指正.
错了不可怕, 可怕的是找不出bug, 谁没错过!!!
最近学操作系统我认为, 学什么都要成本(时间), 即使它是免费的, 我个人认为要挑来学, 挑重点来学, 而不是从头到尾, 除非考试考研.
这个知识点我没有完全掌握(4/10), 革命尚未成功, 同志还需努力!!! , 我会回来反复复习的
今日是: 2020年5月15日, (由于疫情的原因)现在没有返校. 写博客,也可自己加强记忆,就当写写日记吧!!!
希望给个赞: 反正你又不亏, 顺便而已