归并排序

几种常见排序算法

不问归期 提交于 2019-12-05 06:32:46
几种常见排序算法 标签: algorithms [TOC] 本文介绍几种常见排序算法(选择排序,插入排序,希尔排序,归并排序,快速排序,堆排序),对算法的思路、性质、特点、具体步骤、java实现以及trace图解进行了全面的说明。最后对几种排序算法进行了比较和总结。 写在前面 本文所有图片均截图自coursera上普林斯顿的课程 《Algorithms, Part I》 中的Slides 相关命题的证明可参考 《算法(第4版)》 源码可在 官网 下载,也可以在我的github仓库 algorithms-learning 下载,已经使用maven构建 仓库下载: git clone git@github.com:brianway/algorithms-learning.git 基础介绍 java: Interface Comparable<T> Java中很多类已经实现了 Comparable<T> 接口,用户也可自定义类型实现该接口 total order: Antisymmetry(反对称性): if v ≤ w and w ≤ v, then v = w. Transitivity(传递性): if v ≤ w and w ≤ x, then v ≤ x. Totality: either v ≤ w or w ≤ v or both. 注意: The <= operator

模板 - 算法基础 - 归并排序

不羁的心 提交于 2019-12-05 00:39:45
归并排序求逆序数,注意逆序数可能有n^2级别。按照惯例,所有的自写函数均为 闭区间 。 ll MergeSort(int *a, int l, int r) { if(l == r) return 0; int m = l + r >> 1; ll res = 0; res += MergeSort(a, l, m); res += MergeSort(a, m + 1, r); int i = l, j = m + 1, k = 0; while(i <= m || j <= r) { if(i > m) tmp[++k] = a[j++]; else if(j > r) tmp[++k] = a[i++]; else if(a[i] < a[j]) tmp[++k] = a[i++]; else { res += m - i + 1; tmp[++k] = a[j++]; } } for(int i = 1; i <= k; ++i) a[l + i - 1] = tmp[i]; return res; } 来源: https://www.cnblogs.com/KisekiPurin2019/p/11892009.html

数据结构与算法之美学习笔记:第十四讲

我只是一个虾纸丫 提交于 2019-12-05 00:30:27
一、课前问题 几乎所有的编程语言都会提供排序函数,比如C语言中qsort(),C++ STL中的sort()、stable_sort(),还有Java语言中的Collections.sort()。 在平时的开发中,我们也都是直接使用这些现成的函数来实现业务逻辑中的排序功能。那你知道这些排序函数是如何实现的吗?底层都利用了哪种排序算法呢? 基于这些问题,今天我们就来看排序这部分的最后一块内容:如何实现一个通用的、高性能的排序函数? 二、如何选择合适的排序算法 如果要实现一个通用的、高效率的排序函数,我们应该选择哪种排序算法?我们先回顾一下前面讲过的一种排序算法。 我们前面讲过,线性排序算法的时间复杂度比较低,适用场景比较特殊。所以如果要写一个通用的排序函数,不能选择线性排序算法。 如果对小规模数据进行排序,可以选择时间复杂度是O(n )的算法; 如果对大规模数据进⾏排序,时间复杂度是O(nlogn)的算法更加高效。 所以,为了兼顾任意规模数据的排序,一般都会首选时间复杂度是O(nlogn)的排序算法来实现排序函数。 时间复杂度是O(nlogn)的排序算法不止一个,我们已经讲过的有归并排序、快速排序,后面讲堆的时候我们还会讲到堆排序。堆排序和快速排序都有比较多的应用,比如Java语言采用堆排序实现排序函数,C语言使用快速排序实现排序函数。 不知道你有没有发现,

算法 - 归并排序 - 小和问题 | 逆序对问题

可紊 提交于 2019-12-04 20:36:11
小和问题 在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和称为小和问题。 input: [2,4,5,1,7,3] 2 左侧比 2 小的数,没有; 4 左侧比 4 小的数,2; 5 左侧比 5 小的数,2,4; 1 左侧比 1 小的数,没有; 7 左侧比 7 小的数,2,4,5,1; 3 左侧比 3 小的数,2,1。 output: 2+2+4+2+4+5+1+2+1=23 此处使用归并排序,在 merge 时,由于左右两部分都已经有序,可以确定一侧的数都大于正在比较的数,例如: 归并 2 4 5 | 1 3 7 两个部分时,2 比 3 小,此时可以确定后面的数都大于 2,此时便可以一次性计算小和 2 * 2(两个数大于 2),而不用一个个遍历。 总结:使用归并排序算法的快速之处在于,归并的两个部分对内都是有序的,如 2 4 5 | 1 3 7 两个部分。因此在比较大小的时候,可以迅速确定整批的数据大小,而不用重复遍历计算。 又由于每一次 merge 的数据都是新的,此前没有重复算过,因此不会多次计算或漏算。 逆序对问题 在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对。 这个问题也适合使用归并排序的方法进行批量计算,例如 仍然以 2 4 5 | 1 3 7 数据举例,因为 2 4 5 | 1 3 7 ↑ ↑ 此时 (2,1)

java七大排序——7_归并排序

故事扮演 提交于 2019-12-04 18:08:52
归并排序: 将数组分为2块,再到每一小块再分为两块,直到最后一个元素为一块,然后进行有序数组合并,最终合并为一个有序数组 代码实现 public static void mergeSorts ( int[] array){ mergeSortsInternal(array,0,array.length) //mergeSortsInternalNoR(array); } /** * 归并排序:递归内部排序 */ public static void mergeSortInternal ( int[] array, int low, int high){ if (low + 1 >= high) {//[low,high) return; } int mid = (low + high) / 2; mergeSortInternal(array, low, mid); mergeSortInternal(array, mid, high); merge(array, low, mid, high); } private static void merge ( int[] array, int low, int mid, int high){ int length = high - low; int[] extral = new int[length]; //[low,mid] //

经典面试题分析之归并排序的实现(js实现)

自作多情 提交于 2019-12-04 00:59:46
题目: 有两个已经排好序的数组,如何将这两个数组合并且合并后的数组仍然是有序的? 试题分析: 这一道题目是一位同学和大家分享的他去百度面试web前端开发的职位时面试官问道的一道算法题目。看起来貌似和我们的题目没有关系,但是如果你知道归并排序的核心实现你应该能立马反应过来。如果你不知道也没有关系,在我们下面的一番分析之后你应该就能明白了。 其实解决一些算法问题的途径有很多,分治法就是其中的一种。分治法从语义即可知道,就是“分而治之”,把原来的一个大问题分解成一个个的很小的小问题,然后分别去解决小问题之后再把答案合并起来,组成大问题的解,各个击破,循序渐进,最后把问题顺利成章的解决掉。 如果一个比较大的问题能够分解成许多比较小的问题,而且这些小问题的结构、解法与大问题相类似,这个时候我们可以利用递归这一神器巧妙地来解决问题。递归的优点很明显,结构条理清晰,能够有效地减少代码量,但缺点是在数据量较大的时候效率不高,会占用额外的内存。 归并排序就是利用了分而治之、递归解决问题的思路。如果两个数组都是有序的,那么我们可以定义一个新的数组,然后两个数组都从0开始依次分别比较两个数组中值得大小,较小的放进新数组中并将位置后移一位,知道最后把两个数组所有的值都放进新数组中。这样算法的时间复杂度是O(m+n)的,即为两个数组的长度之和。 这个问题其实是很简单的。那么它究竟和归并排序有毛关系呢

AcWing 787. 归并排序

情到浓时终转凉″ 提交于 2019-12-03 23:30:00
给定你一个长度为n的整数数列。 请你使用归并排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。 输入格式 输入共两行,第一行包含整数 n。 第二行包含 n 个整数(所有整数均在1~ 10 9 109范围内),表示整个数列。 输出格式 输出共一行,包含 n 个整数,表示排好序的数列。 数据范围 1 ≤ n ≤ 100000 1≤n≤100000 输入样例: 5 3 1 2 4 5 输出样例: 1 2 3 4 5 #include<iostream> using namespace std; const int N = 1e5; int q[N],n,temp[N]; void merge(int q[],int l,int r){ if(l >= r) return; int mid = l + r >> 1; merge(q,l,mid); merge(q,mid + 1,r); int k = 0;//表示当前已经合并了几个数了 int i = l,j = mid + 1;//指针指向左右两边起点 while(i <= mid && j <= r){ if(q[i] < q[j]) temp[k++] = q[i++]; else temp[k++] = q[j ++]; } while(i <= mid) temp[k++]=q[i++]; while(j <=

leetcode-链表排序

百般思念 提交于 2019-12-03 21:14:45
问题描述: 排序链表 在 O ( n log n ) 时间复杂度和常数级空间复杂度下,对链表进行排序。 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: 输入: -1->5->3->4->0 输出: -1->0->3->4->5此问题思路使用归并排序,先贴上归并排序go语言解法: func merge(arrl []int,arrr []int) []int { fmt.Println("merge arr",arrl,arrr) i,j := 0,0 tmp := make([]int,0) for i<len(arrl) && j<len(arrr){ if (arrl[i]>arrr[j]){ tmp = append(tmp,arrr[j]) j++ }else{ tmp = append(tmp,arrl[i]) i++ } } tmp = append(tmp,arrl[i:]...) tmp = append(tmp,arrr[j:]...) return tmp } func MergeSort(arr []int) []int{ l := len(arr) if (l<2){ return arr } key := l/2 fmt.Println("before left") left := MergeSort(arr[0:key

归并排序

巧了我就是萌 提交于 2019-12-03 15:03:40
归并排序大致上可以理解为把所有数拆分到最小单位,在每个小单位时进行排序,依次把这个小单位变大,然后再排序。一直到所有数。 上图中SR为函数形参时传入的数组,TR为临时数组。在本代码中,num数组为传入数组,t为临时数组。left在最左边,mid为上图的m,right在最右边。 1 #include<stdio.h> 2 3 void Merge(int num[],int t[],int left,int mid,int right){ 4 5 int i = left; //i在左边 6 int j = mid + 1; //j在右边,对应上图 7 int k = i; 8 9 for(;i<=mid && j<=right;k++){ //i、j都是有界限的,k是临时数组存入的下标 10 11 if(num[i]<num[j]){ //找出较小的数依次存放到临时数组t中 12 t[k] = num[i]; //num[i]小就把这个数存入 13 i++; //然后在左边找下一个 14 } 15 else{ 16 t[k] = num[j]; //num[j]小就把这个数存入 17 j++; //然后在右边找下一个 18 } 19 } 20 21 int l; 22 if(i<=mid) //当j全部存入后就把剩余的i部分也全存入 23 for(l=0;l<=mid-i;l++)

归并排序

你。 提交于 2019-12-03 10:52:55
   归并排序是一个典型的基于分治的递归算法。它不断地将原数组分成大小相等的两个子数组(可能相差1),最终当划分的子数组大小为1时,将划分的有序子数组组合并成一个更大的有序数组。        算法分析:     分,也就是把原数组划分成两个子数组的过程。     治,它将两个有序数组合并成一个更大的有序数组。   它将数组平均分成两部分:center=(left+right)/2,当数组分的足够小时(数组中只有一个元素时),只有一个元素的数组自然而然地就可以视为是有序的,此时就可以进行合并操作了。因此,上面讲的合并两个有序的子数组,是从只有一个元素的两个字数组开始合并的。   合并后的元素个数:从1->2->4->8->...   举例:   比如初始数组为:[24,13,25,1,2,27,38,15]     1)分成了两个大小相等的子数组:[24,13,25,1],[2,27,38,15]     2)再划分成四个大小相等的子数组:[24,13],[25,1],[2,27],[38,15]     3)此时,left<right还是成立的,再分为:[24],[13],[25],[1],[2],[27],[38],[15]   此时,有8个小数组,每个数组都可以视为有序的数组!每个数组中的left=right,从递归中返回,故开始执行合并(第21行):     merge(