【数据结构】排序算法---归并排序(动图演示)

【数据结构】排序算法---归并排序(动图演示)
在这里插入图片描述

文章目录

1. 定义

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并

作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  • 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
  • 自下而上的迭代;

2. 算法步骤

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。
在这里插入图片描述

3. 动图演示

在这里插入图片描述

4. 性质

稳定性

归并排序是高效的基于比较的稳定排序算法。

空间复杂度

归并排序可以只使用 O ( 1 ) O(1) O(1)大小的辅助空间,但为便捷通常使用与原数组等长的辅助数组。所以通常情况下空间复杂度为 O ( n ) O(n) O(n)

时间复杂度

归并排序基于分治思想将数组分段排序后合并,时间复杂度在最优、最坏与平均情况下均为 O ( n l o g n ) O(nlogn) O(nlogn)。

5. 算法分析

和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O ( n l o g n ) O(nlogn) O(nlogn)的时间复杂度。代价是需要额外的内存空间

6. 代码实现

C语言——迭代版

intmin(int x,int y){return x < y ? x : y;}voidmerge_sort(int arr[],int len){int*a = arr;int*b =(int*)malloc(len *sizeof(int));int seg, start;for(seg =1; seg < len; seg += seg){for(start =0; start < len; start += seg *2){int low = start, mid =min(start + seg, len), high =min(start + seg *2, len);int k = low;int start1 = low, end1 = mid;int start2 = mid, end2 = high;while(start1 < end1 && start2 < end2) b[k++]= a[start1]< a[start2]? a[start1++]: a[start2++];while(start1 < end1) b[k++]= a[start1++];while(start2 < end2) b[k++]= a[start2++];}int*temp = a; a = b; b = temp;}if(a != arr){int i;for(i =0; i < len; i++) b[i]= a[i]; b = a;}free(b);}

C语言——递归版

voidmerge_sort_recursive(int arr[],int reg[],int start,int end){if(start >= end)return;int len = end - start, mid =(len >>1)+ start;int start1 = start, end1 = mid;int start2 = mid +1, end2 = end;merge_sort_recursive(arr, reg, start1, end1);merge_sort_recursive(arr, reg, start2, end2);int k = start;while(start1 <= end1 && start2 <= end2) reg[k++]= arr[start1]< arr[start2]? arr[start1++]: arr[start2++];while(start1 <= end1) reg[k++]= arr[start1++];while(start2 <= end2) reg[k++]= arr[start2++];for(k = start; k <= end; k++) arr[k]= reg[k];}voidmerge_sort(int arr[],constint len){int reg[len];merge_sort_recursive(arr, reg,0, len -1);}

Python

defmergeSort(arr):import math if(len(arr)<2):return arr middle = math.floor(len(arr)/2) left, right = arr[0:middle], arr[middle:]return merge(mergeSort(left), mergeSort(right))defmerge(left,right): result =[]while left and right:if left[0]<= right[0]: result.append(left.pop(0))else: result.append(right.pop(0));while left: result.append(left.pop(0))while right: result.append(right.pop(0));return result 

Java

publicclassMergeSortimplementsIArraySort{@Overridepublicint[]sort(int[] sourceArray)throwsException{// 对 arr 进行拷贝,不改变参数内容int[] arr =Arrays.copyOf(sourceArray, sourceArray.length);if(arr.length <2){return arr;}int middle =(int)Math.floor(arr.length /2);int[] left =Arrays.copyOfRange(arr,0, middle);int[] right =Arrays.copyOfRange(arr, middle, arr.length);returnmerge(sort(left),sort(right));}protectedint[]merge(int[] left,int[] right){int[] result =newint[left.length + right.length];int i =0;while(left.length >0&& right.length >0){if(left[0]<= right[0]){ result[i++]= left[0]; left =Arrays.copyOfRange(left,1, left.length);}else{ result[i++]= right[0]; right =Arrays.copyOfRange(right,1, right.length);}}while(left.length >0){ result[i++]= left[0]; left =Arrays.copyOfRange(left,1, left.length);}while(right.length >0){ result[i++]= right[0]; right =Arrays.copyOfRange(right,1, right.length);}return result;}}

C++——迭代版

template<typename T>// 整数或浮点数皆可使用,若要使用物件(class)时必须设定"小与"(<)的运算子功能voidmerge_sort(T arr[],int len){ T *a = arr; T *b = new T[len];for(int seg =1; seg < len; seg += seg){for(int start =0; start < len; start += seg + seg){int low = start, mid =min(start + seg, len), high =min(start + seg + seg, len);int k = low;int start1 = low, end1 = mid;int start2 = mid, end2 = high;while(start1 < end1 && start2 < end2) b[k++]= a[start1]< a[start2]? a[start1++]: a[start2++];while(start1 < end1) b[k++]= a[start1++];while(start2 < end2) b[k++]= a[start2++];} T *temp = a; a = b; b = temp;}if(a != arr){for(int i =0; i < len; i++) b[i]= a[i]; b = a;} delete[] b;}

C++——递归版

voidMerge(vector<int>&Array,int front,int mid,int end){// preconditions:// Array[front...mid] is sorted// Array[mid+1 ... end] is sorted// Copy Array[front ... mid] to LeftSubArray// Copy Array[mid+1 ... end] to RightSubArray vector<int>LeftSubArray(Array.begin()+ front, Array.begin()+ mid +1); vector<int>RightSubArray(Array.begin()+ mid +1, Array.begin()+ end +1);int idxLeft =0, idxRight =0; LeftSubArray.insert(LeftSubArray.end(), numeric_limits<int>::max()); RightSubArray.insert(RightSubArray.end(), numeric_limits<int>::max());// Pick min of LeftSubArray[idxLeft] and RightSubArray[idxRight], and put into Array[i]for(int i = front; i <= end; i++){if(LeftSubArray[idxLeft]< RightSubArray[idxRight]){ Array[i]= LeftSubArray[idxLeft]; idxLeft++;}else{ Array[i]= RightSubArray[idxRight]; idxRight++;}}}voidMergeSort(vector<int>&Array,int front,int end){if(front >= end)return;int mid =(front + end)/2;MergeSort(Array, front, mid);MergeSort(Array, mid +1, end);Merge(Array, front, mid, end);}

Go

funcmergeSort(arr []int)[]int{ length :=len(arr)if length <2{return arr } middle := length /2 left := arr[0:middle] right := arr[middle:]returnmerge(mergeSort(left),mergeSort(right))}funcmerge(left []int, right []int)[]int{var result []intforlen(left)!=0&&len(right)!=0{if left[0]<= right[0]{ result =append(result, left[0]) left = left[1:]}else{ result =append(result, right[0]) right = right[1:]}}forlen(left)!=0{ result =append(result, left[0]) left = left[1:]}forlen(right)!=0{ result =append(result, right[0]) right = right[1:]}return result }

结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。

也可以点点关注,避免以后找不到我哦!

Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

带你初步了解排序算法:https://blog.ZEEKLOG.net/2301_80191662/article/details/142211265
直接插入排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142300973
希尔排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142302553
直接选择排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142312028
堆排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142312338
冒泡排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142324131
快速排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142324307
归并排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142350640
计数排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142350741
桶排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142375338
基数排序:https://blog.ZEEKLOG.net/2301_80191662/article/details/142375592
十大经典排序算法总结与分析:https://blog.ZEEKLOG.net/2301_80191662/article/details/142211564
在这里插入图片描述

Read more

【c++】算法设计与分析(保姆级!题目解析+答案)

【c++】算法设计与分析(保姆级!题目解析+答案)

算法类型 一. 分治法 可使用分治法求解的一些经典问题,可以在目录里看自己要哪些,都是先给代码,在说解析。 (1)二分搜索 (2)大整数乘法 (3)Strassen矩阵乘法 (4)棋盘覆盖 (5)归并排序 (6)快速排序 (7)线性时间选择 (8)最接近点对问题 (9)循环赛日程表 (10)汉诺塔 1. 二分搜索(太简单了,所以一定要会) #include<iostream>usingnamespace std;#defineMAX10int a[MAX]={0,22,23,33,36,55,56,58,89,94}

By Ne0inhk
C++学习之旅【实战全面解析C++二叉搜索树】

C++学习之旅【实战全面解析C++二叉搜索树】

🔥承渊政道:个人主页 ❄️个人专栏: 《C语言基础语法知识》《数据结构与算法》 《C++知识内容》《Linux系统知识》 ✨逆境不吐心中苦,顺境不忘来时路!🎬 博主简介: 引言:前篇文章,小编已经介绍了关于C++中多态概念指南与核心内容介绍!相信大家应该有所收获!接下来我将带领大家继续深入学习C++的相关内容!本篇文章着重介绍关于实战全面解析C++二叉搜索树,那么这里面到底有哪些知识需要我们去学习的呢?废话不多说,带着这些疑问,下面跟着小编的节奏🎵一起学习吧! 目录 * 1.⼆叉搜索树的概念 * 2.⼆叉搜索树的性能分析 * 3.⼆叉搜索树的插⼊ * 4.⼆叉搜索树的查找 * 5.⼆叉搜索树的删除 * 6.⼆叉搜索树的实现代码 * 7.⼆叉搜索树key和key/value使⽤场景 * 7.1key搜索场景 * 7.2key/value搜索场景 * 7.3key/value⼆

By Ne0inhk
【C++】第二十六节—C++11(中) | 右值引用和移动语义(续集)+lambda

【C++】第二十六节—C++11(中) | 右值引用和移动语义(续集)+lambda

Hi,我是云边有个稻草人,C++领域博主与你分享专业知识(*^▽^*) 《C++》本篇文章所属专栏—持续更新中—欢迎订阅~ 目录 上节总览,详情见—>【C++】第二十五节—C++11 (上) | 详解列表初始化+右值引用和移动语义 本节总览 (4)右值引用和移动语义在传参中的提效 6. 类型分类 7. 引用折叠 8. 完美转发 四、lambda 1. lambda表达式语法 2. lambda的应用 3. 捕捉列表 4. lambda的原理 接着上节,正文开始—— (4)右值引用和移动语义在传参中的提效 * 查看STL文档我们发现C++11以后容器的push和insert系列的接口否增加的右值引用版本 * 当实参是一个左值时,容器内部继续调用拷贝构造进行拷贝,将对象拷贝到容器空间中的对象 * 当实参是一个右值,容器内部则调用移动构造,右值对象的资源到容器空间的对象上

By Ne0inhk
新手必看!VSCode&PyCharm 配置 OpenCV 超详细教程(支持 Python 和 C++ 双语言)

新手必看!VSCode&PyCharm 配置 OpenCV 超详细教程(支持 Python 和 C++ 双语言)

新手必看!VSCode&PyCharm 配置 OpenCV 超详细教程(支持 Python 和 C++ 双语言) 适用对象:初学者,希望在 VSCode 与 PyCharm 两款常用 IDE 中,学会配置并使用 OpenCV,分别实现 Python 与 C++ 环境的快速上手。 适用平台:Windows 10/11(本文以 Windows 为主要示范,Linux 或 macOS 用户可参照各自系统的包管理细节进行适当调整)。 摘要 本文为新手用户提供了最全的 VSCode & PyCharm 配置 OpenCV 教程,涵盖 Python 与

By Ne0inhk