数据结构与算法|【算法】——归并排序的解析

目录

1.归并排序的思想
2.归并排序的分析
3.内排序和外排序
1.归并排序的思想

归并是将两个或两个以上的有序表组合成一个新的有序表,假设初始序列含有n个记录,则可看成是n个子序列,每个子序列的长度为1,然后两两归并,得到[ n/2 ]个长度为2或为1的有序的子序列;在两两归并... ... ,如此重复,直到得到一个长度为n的有序序列为止。如下:
数据结构与算法|【算法】——归并排序的解析
文章图片

2.归并排序的分析 我们先来对两个序列合成新的有序序列进行分析; 我们以上面的第三趟排序作为例子
数据结构与算法|【算法】——归并排序的解析
文章图片

这就完成了两个序列合并的算法,代码如下。

void _MergeSortNonR(int* a,int* tmp,int begin1,int end1, int begin2, int end2) { int cur1 = begin1; //cur1是子序列1的指针指向位置 int cur2 = begin2; //cur2是子序列2的指针指向位置 int cur3 = begin1; //临时数组指向的位置 //将子序列1和子序列2进行比较,然后将较小的值 //插入到临时数组中 while (cur1 <= end1 && cur2 <= end2) { if (a[cur1] < a[cur2]) { tmp[cur3] = a[cur1]; cur1++; } else { tmp[cur3] = a[cur2]; cur2++; } cur3++; } //将剩下的子序列的值插入到 //临时数组中 while (cur1 <= end1) { tmp[cur3++] = a[cur1++]; } while (cur2 <= end2) { tmp[cur3++] = a[cur2++]; } //将临时数组中的数组拷贝给原来的数组 for (int i = begin1; i <= end2; i++) { a[i] = tmp[i]; } }

其中a是为原数组,tmp是临时数组。begin1和end1为序列1的区间,begin2和end2为序列2的区间。
当然完成两个序列合并只是其中的一部分,要完成归并排序的算法,我们还要继续往下分析:
数据结构与算法|【算法】——归并排序的解析
文章图片

起初begin1为指向4的位置为0,则endl为begin1+gap-1,begin2为begin1+gap,end2为begin1+2gap-1,其中gap为子序列的间隔,此时的gap为2.
当上面的子序列排完序后,则跳到下一组序列进行排序。则begin1为指向1的位置,其中的begin1由上一个being1+=2gap跳过来的。如果按照上面计算的话,我们在每一趟中的后面需要在判断end2和end1,如果end2大于n-1时,则表示end2比数组最后一个数据的地址要大,所以令end2等于n,如果end1大于n-1时,则表示end1比数组最后一个数据的地址要大,这时候最后一个就只有一个子序列,所以不用在比较了,直接跳出循环循环即可.
数据结构与算法|【算法】——归并排序的解析
文章图片

当每趟归并排序完成最后一组排序时,则begin1>n,则代表这一趟的归并排序结束,再将gap乘以2倍,进行下一趟的归并排序,当最后一趟排序结束时,其中的gap>=n/2,所以当gap>n时就完成排序.
void MergeSort(int* a, int n) { //创建一个临时数组 int* tmp = (int*)malloc(sizeof(int) * n); if (tmp == NULL) { printf("malloc申请失败\n"); exit(); } int gap = 1; //第一趟排序的gap为1 while ( gap <= n) { //设i为每两个序列中begin1的值 for (int i = 0; i < n; i += 2 * gap) { int begin1 = i, end1 = i + gap - 1; int begin2 = i + gap, end2 = i + 2 * gap - 1; //end2大于n-1,则end2改为n-1 if (n-1 < end2) { end2 =n-1; } //如果end1大于n-1,则这一趟就不需要在排序了 if (n-1 < end1) { break; } //两个序列合成为一个新的序列 _MergeSortNonR(a, tmp, begin1, end1, begin2, end2); } gap *= 2; } //释放临时数组 free(tmp); tmp = NULL; }

归并排序的时间复杂度:每一趟归并排序都得遍历一次数组,时间复杂度为O(n),从第一趟都到最后一趟的归并排序总共要进行log2n趟排序,所以归并排序的时间复杂度为O(nlogn).
归并排序的空间复杂度:归并排序需要创建与原来序列一样的临时序列,所以归并排序的空间复杂度为O(N).
3.内排序和外排序
内排序:数据数量少,内存中放的下,直接在内存中排序即可,
外排序:数据数量多,内存放不下,数据都放在磁盘中,但不能直接通过内存对它们排序,得在内存中进行一部分排序后,然后在磁盘中完成排序。
外排序的思想:
假设文件A中有5个亿的整数,要对它们进行排序,需要进行怎样排序呢?
(5个亿的整数大约为2个g,内存大概有512个g)
显然这文件A中的数据不能直接放到内存中进行排序,所以就得要使用外排序来对我们的数据进行排序。
数据结构与算法|【算法】——归并排序的解析
文章图片

数据结构与算法|【算法】——归并排序的解析
文章图片


数据结构与算法|【算法】——归并排序的解析
文章图片

好啦,今天的内容就分享到这里了,如果你觉得这篇文章对你有帮助的话,麻烦你给个三连,谢谢!!!



【数据结构与算法|【算法】——归并排序的解析】

    推荐阅读