网站建设部岗位职责wordpress禁止响应
网站建设部岗位职责,wordpress禁止响应,酒类营销网站,手表电商网站归并排序
动图演示#xff1a; 基本思想#xff1a;分治思想
归并排序#xff08;MERGE-SORT#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并#xff0c;得到完全有序的序列#xff1b;即先使每个子…归并排序
动图演示 基本思想分治思想
归并排序MERGE-SORT是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并得到完全有序的序列即先使每个子序列有序再使子序列段间有序。若将两个有序表合并成一个有序表称为二路归并。
假设我们有左右两块有序区间的数组可以对它直接进行合并。此时我们需要借助第三方数组一次比较两块区间的起始位置把小的那个放到新数组随后依次比较小的就放新数组一直到结束。
但是现在存在一个问题上述条件是假设了左半区间和右半区间有序但是原先数组是无序的也就是左半区间和右半区间均无序。怎么才能达到左半区间和右半区间有序最后再归并成整体有序呢这就体现到了分治的思想了将数组一直分分到1个1个的归并成有序变成2个2个的然后归并成有序成4个4个的最后再4个4个的归并成有序最终至整体有序。
画图解析其完整的归并过程 这里我们先用代码实现其分解递归的过程并用打印法表示其结果 画图演示其部分递归分治的过程 总代码如下
void _MergeSort(int* a, int begin, int end, int* tmp)
{if (begin end)return; //区间不存在就返回int mid (begin end) / 2;//[begin, mid] [mid1, end]_MergeSort(a, begin, mid, tmp); //递归左半_MergeSort(a, mid 1, end, tmp); //递归右半//归并[begin, mid] [mid1, end]//printf(归并[%d,%d][%d,%d]\n, begin, mid, mid 1, end);int begin1 begin, end1 mid;int begin2 mid 1, end2 end;int index begin;while (begin1 end1 begin2 end2){//将较小的值放到tmp数组里头if (a[begin1] a[begin2]){tmp[index] a[begin1];}else{tmp[index] a[begin2];}}//如若begin2先走完把begin1后面的元素拷贝到新数组while (begin1 end1){tmp[index] a[begin1];}//如若begin1先走完把begin2后面的元素拷贝到新数组while (begin2 end2){tmp[index] a[begin2];}//归并结束后把tmp数组拷贝到原数组memcpy(a begin, tmp begin, (end - begin 1) * sizeof(int));
}//归并排序
void MergeSort(int* a, int n)
{//malloc一块新数组int* tmp (int*)malloc(sizeof(int) * n);assert(tmp);_MergeSort(a, 0, n - 1, tmp);free(tmp);
}归并排序非递归
思想
归并的非递归不需要借助栈直接使用循环即可。递归版中我们是对数组进行划分成最小单位这里非递归我们直接把它看成最小单位进行归并。我们可以通过控制间距gap来完成先看图 上述情况其实是在理想状态下可行的只要数组长度不是2的次方倍都会出现问题先简要看下理想状态下的伪代码并用printf打印下归并过程 再强调一遍只要数组长度不是2的次方倍都会出现问题像上述长度为8没有问题那如若长度为6呢 当长度为6不再是2的次方数时就运行出现问题了综上我们需要考虑下极端情况根据上述的区间范围我们可以总结出以下三个可能会出现越界的情况
end1越界。begin2越界。end2越界。
1、end2越界 2、begin2和end2均越界 3、end1和begin2和end2均越界 综上我们需要单独对这些极端情况处理。
//end1越界修正即可
if (end1 n)
{end1 n - 1;
}
//begin2越界第二个区间不存在
if (begin2 n)
{begin2 n;end2 n - 1;
}
//begin2 okend2越界修正下end2即可
if (begin2 n end2 n)
{end2 n - 1;
}总代码如下
//归并非递归
void MergeSortNonR(int* a, int n)
{int* tmp (int*)malloc(sizeof(int) * n);assert(tmp);int gap 1;while (gap n){//分组归并间距为gap是一组两两归并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;//end1越界修正即可if (end1 n){end1 n - 1;}//begin2越界第二个区间不存在if (begin2 n){begin2 n;end2 n - 1;}//begin2 okend2越界修正下end2即可if (begin2 n end2 n){end2 n - 1;}printf(归并[%d,%d][%d,%d]\n, begin1, end1, begin2, end2);int index i;while (begin1 end1 begin2 end2){//将较小的值放到tmp数组里头if (a[begin1] a[begin2]){tmp[index] a[begin1];}else{tmp[index] a[begin2];}}//如若begin2先走完把begin1后面的元素拷贝到新数组while (begin1 end1){tmp[index] a[begin1];}//如若begin1先走完把begin2后面的元素拷贝到新数组while (begin2 end2){tmp[index] a[begin2];}}memcpy(a, tmp, n * sizeof(int));gap * 2;}free(tmp);
}归并排序特性总结
1、归并的缺点在于需要O(N)的空间复杂度归并排序的思考更多的是解决在磁盘中的外排序问题。
2、时间复杂度O(N*logN)。
3、空间复杂度O(N)。
4、稳定性稳定 。
内排序和外排序
在排序中分为内排序和外排序简单了解下其概念
内排序数据量较少在内存中进行排序。外排序数据量很大在磁盘上进行排序。
而我们前面学习的排序中归并排序既可作为内排序也可作为外排序而其它几个排序只能是内排序这也就说明了在处理数据量很大时采用归并排序才能解决其它排序不可。
如若我要排10亿个整数就只能使用归并排序了现在来简要算下其占比大小
1G 1024MB1MB 1024KB1KB 1024Byte综上1G 102410241024Byte而10亿个整数40亿Byte所以10亿个整数占4G
现在有10亿个整数4G的文件只给你1G的运行内存请对文件中的10亿个数进行排序。
核心思想 数据量大加载不到内存。想办法控制两个有序文件两个有序文件归并成一个更大的有序文件。可以把这4G的文件分成4等份每一份1G分别读到内存进行归并排序排完后再写回到磁盘小文件。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/88390.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!