归并排序

排序算法

这一生的挚爱 提交于 2019-12-03 00:05:17
算法比较 稳定性 插入排序,冒泡排序,二路归并排序和基数排序是稳定的排序方法; 选择排序,希尔排序,快速排序和堆排序是不稳定的排序方法; 复杂度 排序方法 平均时间 最坏情况 辅助空间 插入排序 O(n^2) O(n^2) O(1) 希尔排序 O(nlogn) O(nlogn) O(1) 冒泡排序 O(n^2) O(n^2) O(1) 快速排序 O(nlogn) O(n^2) O(logn) 选择排序 O(n^2) O(n^2) O(1) 堆排序 O(nlogn) O(nlogn) O(1) 归并排序 O(nlogn) O(nlogn) O(n) 基数排序 O(d(n+r)) O(d(n+r)) O(r+n) 方法选择 (1) 排序数据的规模n较大,关键字元素分布比较随机,并且不要求排序稳定性时,宜选用快速排序; (2) 排序数据规模n较大,内存空间又允许,并且有排序稳定性要求,宜采用归并排序; (3) 排序数据规模n较大,元素分布可能出现升序或者逆序的情况,并且对排序的稳定性不要求,宜采用堆排序或者归并排序; (4) 排序数据规模n较小,元素基本有序,或者分布也比较随机,并且有排序稳定性要求时,宜采用插入排序; (5) 排序数据规模n较小,对排序稳定性又不做要求时,宜采用选择排序; 算法实现 插入排序 插入是个比较容易理解的排序算法,每次取下一个未排序的数

归并排序求逆序对模板(未完待续)

匿名 (未验证) 提交于 2019-12-02 23:52:01
\(1.\) POJ2299(需要该篇博文的阅读密码) \(View\) \(Code\) void msort(int l,int mid,int r) { if(l==r) return; msort(l,(l+mid)>>1,mid); msort(mid+1,(r+mid+1)>>1,r); int i=l,j=mid+1; for(register int k=l;k<=r;k++) { if(j>r||(i<=mid&&a[i]<a[j])) b[k]=a[i++]; else { ans+=mid-i+1; b[k]=a[j++]; } } for(register int k=l;k<=r;k++) a[k]=b[k]; }

非递归版归并排序

匿名 (未验证) 提交于 2019-12-02 23:43:01
2019独角兽企业重金招聘Python工程师标准>>> 非递归版的归并排序,省略了中间的栈空间,直接申请一段O(n)的地址空间即可,因此空间复杂度为O(n),时间复杂度为O(nlogn); 算法思想:   开始以间隔为1的进行归并,也就是说,第一个元素跟第二个进行归并。第三个与第四个进行归并;   然后,再以间隔为2的进行归并,1-4进行归并,5-8进行归并;   再以2*2的间隔,同理,知道2*k超过数组长度为止。 while (i< length){ Merge(arr,temp,i,length); i *= 2 ; }   当不够两组进行归并是,如果超过k个元素,仍然进行归并;如果剩余元素不超过k个元素,那么直接复制给中间数组。 while (i <= length- 2 * k){ sort(arr1,temp,i,i +k- 1 ,i+ 2 *k- 1 ); i += 2 * k; }   if (i < length-k+ 1 ) // 如过剩余个数比一个k长度还多...那么就在进行一次合并 sort(arr1,temp,i,i+k- 1 ,length- 1 ); else for (j=i;j<length;j++ ) temp[j] = arr1[j]; 主要代码: void MergeSort( int *arr, int length){ int *temp

归并排序、二路快排、三路快排python实现

匿名 (未验证) 提交于 2019-12-02 22:51:30
源代码: https://github.com/lzneu/Algrithm_python O(n*logn)级别的排序: |-归并排序 |-快速排序 |-二路快排 |-三路快排 总结: 归并排序 和 快速排序 都使用了分治算法 扩展应用: import datetime import random import numpy as np # 生成一个近乎有序的数组 def genNearlyOrderArray(n, swapTimes): arr = list(range(n)) for i in range(swapTimes): x = random.randint(0, n) y = random.randint(0, n) swap(arr, x, y) return arr def genRandomArray(n, start=0, end=10000): return np.random.randint(start, end, size=n) def aTestSort(sortName, arr, n): t_start = datetime.datetime.now() sortName(arr, n) t_end = datetime.datetime.now() # 记录函数结束时间) long = (t_end - t_start).total

链表排序之归并排序

两盒软妹~` 提交于 2019-12-02 16:37:05
链表排序之归并排序: public static ListNode mergeSortList(ListNode head){ if (null == head || null == head.next){ return head; } ListNode slow = head; ListNode fast = head; ListNode pre = head; while (null != fast && null != fast.next){ pre = slow; slow = slow.next; fast = fast.next.next; } pre.next = null; return mergeTwoSortList(mergeSortList(head), mergeSortList(slow)); } private static ListNode mergeTwoSortList(ListNode head1, ListNode head2){ if (null == head1){ return head2; } if (null == head2){ return head1; } ListNode head = new ListNode(-1); ListNode cur = head; ListNode cur1 = head1; ListNode

AcWing 787. 归并排序

霸气de小男生 提交于 2019-12-02 13:07:19
https://www.acwing.com/problem/content/789/ #include<bits/stdc++.h> using namespace std; const int N=1e6+10; int n; int q[N],tmp[N]; void merge_sort(int q[],int l,int r) { if(l>=r) return ;//如果当前区间里面只有一个数或者没有数的话,就不用排序,直接返回 int mid=l+r>>1; //取区间的中点 merge_sort(q,l,mid),merge_sort(q,mid+1,r); //递归排序左边和右边 int k=0,i=l,j=mid+1; while(i<=mid&&j<=r) if(q[i]<=q[j]) tmp[k++]=q[i++]; else tmp[k++]=q[j++]; while(i<=mid) tmp[k++]=q[i++]; //可能还有的数字没有放进去 while(j<=r) tmp[k++]=q[j++]; //归并 for(i=l,j=0;i<=r;i++,j++) q[i]=tmp[j]; //把临时数组里面的数字 放回去 } int main() { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&q

问题 A: 二路归并排序(mergesort)递归法 [2*+]

╄→гoц情女王★ 提交于 2019-12-02 12:29:05
题目描述 二路归并排序(mergesort)递归法 用递归法进行二路归并排序 输入:第一行一个数据n,表示有n个数要排序。接下来n行每行一个<=10^7的整数。 输出:n行,由小到大排序后的数据 数据规模:n<=10^5 思考:两个递归都会被执行吗? #include<bits/stdc++.h> using namespace std; void Merge(vector<int>&res, int L1, int R1, int L2, int R2) { vector<int>ans(R2-L1+10); int i = L1, j=L2, index=0; while(i<=R1 && j<=R2) { if(res[i]<res[j]) ans[index++] = res[i++]; else ans[index++] = res[j++]; } if(i<=R1) { while(i<=R1) ans[index++] = res[i++]; } if(j<=R2) { while(j<=R2) ans[index++] = res[j++]; } index = 0; for(int i=L1; i<=R2; ++i) res[i] = ans[index++]; } void mergesort(vector<int>&res, int i, int j) {

归并排序

故事扮演 提交于 2019-12-02 11:40:01
归并排序小结 # include <iostream> using namespace std ; //打印函数 void printArray ( int A [ ] , int n ) { for ( int i = 0 ; i < n ; ++ i ) cout << A [ i ] << endl ; } void MERGE ( int A [ ] , int p , int q , int r ) { int n1 = q - p + 1 ; int n2 = r - q ; int L [ n1 + 1 ] ; int R [ n2 + 1 ] ; for ( int i = 0 ; i < n1 ; i ++ ) { L [ i ] = A [ p + i ] ; } //printArray(L, n1); //cout << endl; for ( int j = 0 ; j < n2 ; j ++ ) { R [ j ] = A [ q + j + 1 ] ; } //printArray(R, n2); //cout << endl; L [ n1 ] = 1000 ; R [ n2 ] = 1000 ; int i = 0 , j = 0 ; //我第一步写成k=0,错了。 //printArray(A, 4); //cout << endl; for (

排序算法之希尔、归并、堆和基数排序

筅森魡賤 提交于 2019-12-02 11:14:09
//希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序是基于插入排序的以下两点性质而提出改进方法的 : 1. 插入排序在对几乎已经排好序的数据操作时,效率高,既可以达到线性排序的效率 2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位 希尔排序的基本思想是 : 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时, 再堆全体记录进行依次直接插入排序. 算法步骤 : 1: 选择一个增量序列t1,t2,,,tk,其中ti > tj,tk = 1; 2: 按增量序列个数k,对序列进行k趟排序. 3: 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,分别对各个表进行直接插入排序.仅增量因为为1时, 整个序列作为一个表来处理,表长度度即为整个序列的长度. package com.baidurunnable; import java.util.Arrays; public class Demo5 { //希尔排序 public static void main(String[] args) { int[] a = {1,4,3,5,2,7,6,8,9,0}; quickSork(a); System.err.println(Arrays.toString(a)

LeetCode | 148. 排序链表

淺唱寂寞╮ 提交于 2019-12-02 11:04:07
原题 ( Medium ):   在 O ( n log n ) 时间复杂度和常数级空间复杂度下,对链表进行排序。    思路:自底向上(bottom-to-up)、归并排序(Merge Sort)    题目对时间复杂度和空间复杂度做出了要求,常用的对数级别的排序方法不多,由于这里并不是双向链表,所以快排不太可能,可以使用 归并 ,但一般的归并是需要一辅助数组的,空间复杂度为O(n),自然不能按一般归并的思路。我们可以考虑自底向上的归并,而非自上而下的递归归并,就是直接从两两合并开始,然后四四合并.......直到结束。   那么怎么把链表两两分开再两两合并呢?首先使用一整型变量size记录每轮需要两两分开和归并的节点数量,就是一个每次两倍倍增的数值(1、2、4....),我们可以使用 位运算 实现两倍倍增。然后怎么分开呢?要怎样把链表每两个节点分开成左右各一个,如stpe1一样?我们需要利用这个size把链表切开(step1的size为1),从链表头开始, 走过size个节点 (包括头节点)后,把链表 断开 ,断开后左边就是左半部分,右边的size个就是右半部分,例如4->3->...,断开后就变成了4,3->....,此时4就是左半部分,3就是右半部分,怎么把右半部分在链表中确认下来?继续把链表切开,从3( 右半部分的起点 )出发, 走过size个节点 (包括出发的节点)后