归并排序

归并排序

余生颓废 提交于 2019-11-28 09:45:48
归并排序用的是分治的思想。分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。 这里的归并排序就是将一个序列分成多个序列,可分成每个序列只有一个元素,然后将挨着的两个区间的元素进行对比,然后排序。 我们可以用递归来完成这个分区间的步骤,直至每个区间只有一个元素,将左右区间的每个元素进行比较,较小的存放进辅助数组。 大致步骤:(记作左区间的指针为i,右区间的指针为) 1:建立辅助数组。 2:分区间(递归完成) 3:比较左右区间的的第一个值,如果左区间的较小,存入辅助数组,i++,如果右区间的数较小,存入辅助数组,j++,直到i=mid或者j=end。 4:将左区间或者右区间剩余的数存入到辅助数组中去(由于到了i=mid||j=mid的时候我们就不在比较了,所以会存在左区间的数或者右区间的数没有全部存入辅助数组中去。) 5:将辅助数组中的数存入原数组中去。 图解: 由图我们可以看到起始数组为:{80,30,60,40,20,10,,50,70}, 经过分解之后我们分成了8个数组:{80},{30},{60},{40},{20},{10},{50},{70}。 分解之后自然要合并: 第一步我们可以看到都是单个元素在比较大小,小的先存入到辅助数组。

Java 简单易理解的归并排序

蹲街弑〆低调 提交于 2019-11-28 08:12:49
/* * 归并排序: 想:**归并(Merge)排序法**是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列 **1.两路归并排序算法思路** ①把 n 个记录看成 n 个长度为1的有序子表 ②进行两两归并使记录关键字有序,得到 n/2 个长度为 2 的有序子表 ③重复第②步直到所有记录归并成一个长度为 n 的有序表为止 ![归并图集](\Users\Administrator\Desktop\排序\归并图集.jpg) 直白的所就是分为两个步骤 现将数组中的元素拆分成一个一个的子集,使用合并将子集变成有序 拆分是很简单的操作,每次都按照原有的数组元素进行一半拆分 开始元素的位置+最后一个元素的位置/2 如何将将二个有序数列合并。只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。 (1)稳定性  归并排序是一种稳定的排序。 (2)存储结构要求  可用顺序存储结构。也易于在链表上实现。 (3)时间复杂度  对长度为n的文件,需进行趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。 (4)空间复杂度   需要一个辅助向量来暂存两有序子文件归并的结果

求两个有序数组合并后的中位数,最透讲解| 腾讯面试编程50题(三)

流过昼夜 提交于 2019-11-28 06:12:29
本文是我的第303篇原创 摘要 本文是腾讯50道常考编程题之一:求解两个有序数组合并后的中位数,属于 "Hard" 难度,在校招中难倒一大波校招生。本文提供一种基本解法:基于归并排序。并对归并排序可能不是很了解的同学,提供了图解归并排序的讲解。 题目 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。 示例 1: nums1 = [1, 3] nums2 = [2] 则中位数是 2.0 示例 2: nums1 = [1, 2] nums2 = [3, 4] 则中位数是 (2 + 3)/2 = 2.5 分析 熟悉「归并排序」的同学( 对于不熟悉的下面也会图文阐述下 ), 应该很快就能想出这个题目的解题思路,这个方法我认为也是这道题最直接的一种解法,并且也能满足求解时间复杂度的要求 O(m+n),只不过需要占用O(m+n)的空间,但是题目未作要求。 完整代码 下文是我在2017年10月31日编写的,那时公众号还叫 算法channel, 那时关注我的人只有几十个,可能现在大部分同学都没看到。现在经过整理后,附录到这里,希望能对不熟悉归并排序的同学有所帮助。 归并排序 图文讲解 归并思想 归并排序,英文名称是MERGE-SORT。

排序算法之归并排序

江枫思渺然 提交于 2019-11-28 05:32:40
基本思想:    归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。 首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。 //将有序数组a[]和b[]合并到c[]中 public void MemeryArray(int a[], int n, int b[], int m, int c[]){ int i, j, k; i = j = k = 0; while (i < n && j < m){ if (a[i] < b[j]) c[k++] = a[i++]; else c[k++] = b[j++]; } while (i < n) c[k++] = a[i++]; while (j < m) c[k++] = b[j++]; }  解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成2组A,B,如果这2组组内的数据都是有序的,那么就可以很方便的将这2组数据进行排序。如何让这2组组内数据有序了? 可以将A,B组各自再分成2组。依次类推,当分出来的小组只有1个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的2个小组就可以了。这样通过 先递归的分解数列 , 再合并数列

C++版 归并排序

戏子无情 提交于 2019-11-28 05:23:29
在原作者基础上加入注释 原作者:https://www.cnblogs.com/agui521/p/6918229.html 归并排序:归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为O(n log n)。1945年由 约翰·冯·诺伊曼 首次提出。该算法是采用 分治法 (Divide and Conquer)的一个非常典型的应用,且各层分治 递归 可以同时进行。 归并排序的核心思想是将两个有序的数列合并成一个大的有序的序列。通过递归,层层合并,即为归并。 如图,从下到上,每一步都需要将两个已经有序的子数组合并成一个大的有序数组,如下是实现合并的具体代码,请读者细细体会 void merge(int arr[],int l,int mid,int r) { int aux[r-l+1];//开辟一个新的数组,将原数组映射进去 for(int m=l;m<=r;m++) { aux[m-l]=arr[m]; } int i=l,j=mid+1;//i和j分别指向两个子数组开头部分 for(int k=l;k<=r;k++) {              //分四种情况判断:   //i>mid 把大于mid的数据并入;j>r 把i-mid的数据并入; //aux[i-l]<aux[j-l],把小的数据即aux[i-l]并入

归并排序

回眸只為那壹抹淺笑 提交于 2019-11-28 00:44:40
算法思想 归并排序使用了分治的套路,先将待排序元素划分为个数均等的两部分,然后在对已经划分的两个部分在进行均等 划分,如此递归的划分下去,直到区间无法在划分时停止,然后合并这些子区间即可;合并时每次从两个子区间内选 出最大(降序排序)或者最小(升序排序)的元素放入辅助空间内,直到某个子区间为空,然后在将另一个子区间剩余 的元素全部追加到辅助空间内,然后在将辅助空间的元素覆盖到原来两个子区间即可 归并排序的主要代码是合并,例如:{1,13,24,26},{2,15,27,38}这两个已经有序的子区间进行合并,其过程如下: 从上图可以看出:此时i指向的元素1比j指向的元素2小,所以将1放入辅助空间: 从上图可以看出:此时i指向的元素13比j指向的元2大,所以将2放入辅助空间: 从上图可以看出:此时i指向的元素13比j指向的元15小,所以将13放入辅助空间: 从上图可以看出:此时i指向的元素24比j指向的元15大,所以将15放入辅助空间: 从上图可以看出:此时i指向的元素24比j指向的元27小,所以将24放入辅助空间: 从上图可以看出:此时i指向的元素26比j指向的元27小,所以将26放入辅助空间: 此时这一对区间的左侧区间已经复制到辅助空间中,在将右侧区间的剩余元素追加到辅助空间尾部: 至此来两个区间合并暂未完成!!!,还得把辅助空间中的元素覆盖到这对区间中,才算完成 例:对38,27

1035 插入与归并

久未见 提交于 2019-11-27 22:06:02
/** * 1.解题思路: * * 2.参考博客: */ #include <iostream> #include <algorithm> using namespace std; int main() { int n, a[100], b[100], i, j; cin >> n; for (int i = 0; i < n; i++) cin >> a[i]; for (int i = 0; i < n; i++) cin >> b[i]; //将i指向中间序列中满足从左到右是从小到大顺序的最后一个下标 for (i = 0; i < n - 1 && b[i] <= b[i + 1]; i++); //将j指向从i+1开始,第一个不满足a[j] == b[j]的下标 //如果j顺利到达了下标n,说明是插入排序 for (j = i + 1; a[j] == b[j] && j < n; j++); if (j == n) { cout << "Insertion Sort" << endl; //下一次的序列是sort(a, a+i+2) sort(a, a + i + 2); } else { //模拟归并 cout << "Merge Sort" << endl; int k = 1, flag = 1; while(flag) { //找到与中间归并过程相同的序列状态

【Python实现归并排序】

孤人 提交于 2019-11-27 19:25:38
原文: http://blog.gqylpy.com/gqy/347 "首先,归并排序使用了二分法,归根到底的思想还是分而治之。拿到一个长数组,将其不停的分为左边和右边两份,然后以此递归分下去。然后再将它们按照两个有序数组的样子合并起来。这样说起来可能很难理解,所以 图就来了: 归并排序将数组以中间的值进行拆分,最后分到最细之后再将其使用对两个有序数组进行排序的方法对其进行排序。 两个有序数组排序的方法则非常简单,同时对两个数组的第一个位置进行比大小,将小的放入一个空数组,然后将放入空数组的那个位置的指针往后移一个,然后继续和另外一个数组的上一个位置进行比较,以此类推。到最后任何一个数组先出栈完,就将另外一个数组里的所有元素追加到新数组后面。 递归拆分的时间复杂度是logN,进行两个有序数组排序的方法复杂度是N,所以该算法的时间复杂度是N*logN,即NlogN。 Python代码示例: lst = [2, 5, 7, 8, 9, 1, 3, 4, 6] def merge_sort(lst, low, high): # 不断递归调用自己,直至拆分成单个元素的时候返回这个元素,不再拆分 if low < high: # 取拆分的中间位置 mid = (low + high) // 2 merge_sort(lst, low, mid) # 左 merge_sort(lst, mid

链表归并排序

允我心安 提交于 2019-11-27 19:18:55
class Solution { public ListNode sortList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode slow = head, fast = head, prev = head; while (fast != null && fast.next != null) { prev = slow; slow = slow.next; fast = fast.next.next; } prev.next = null; ListNode list1 = sortList(head); ListNode list2 = sortList(slow); return merge(list1, list2); } public ListNode merge(ListNode list1, ListNode list2) { ListNode dummy = new ListNode(-1), curr = dummy; while (list1 != null && list2 != null) { if (list1.val < list2.val) { curr.next = list1; list1 = list1.next; } else {

常见的排序算法(四):归并排序

有些话、适合烂在心里 提交于 2019-11-27 16:27:18
归并排序 ( 英语: Merge sort,或 mergesort),是创建在归并操作上的一种有效的 排序算法 , 效率 为 O(n·log n)。该算法是采用 分治法 (Divide and Conquer)的一个非常典型的应用,且各层 分治递归 可以同时进行。 采用 分治法: 分割:递归地把当前序列平均分割成两半。集成:在保持元素顺序的同时将上一步得到的子序列集成到一起(归并)。 归并操作 (merge),也叫归并算法,指的是将两个 已经排序 的序列 合并 成一个序列的操作。归并排序算法 依赖 归并操作。 归并排序 代码如下: 1 static void merge_sort_recursive(int[] arr, int[] result, int start, int end) { 2 if(start>=end) 3 return; 4 int len = end - start, mid = (len >> 1) + start; //二进制位运算法`>>`,mid是指 5 int start1 = start, end1 = mid; 6 int start2 = mid + 1, end2 = end; 7 8 merge_sort_recursive(arr, result, start1, end1);//先拆左边 9 merge_sort_recursive