归并排序

【排序】归并类排序—归并排序(逆序数问题)

血红的双手。 提交于 2020-01-23 23:21:13
文章目录 前言 归并排序(merge sort) 逆序数 结语 微信公众号: bigsai 数据结构与算法专栏 前言 在排序中,我们可能大部分更熟悉冒泡排序、快排之类。对归并排序可能比较陌生。然而事实上归并排序也是一种稳定的排序,时间复杂度为O(nlogn). 归并排序是基于分治进行归并的,有 二路归并 和多路归并.我们这里只讲二路归并并且日常用的基本是二路归并。并且 归并排序的实现方式 有 递归形式 和 非递归形式 。要注意其中的区分(思想上没有大的区别,只是划分上会有区分后面会对比)。 并且归并排序很重要的一个应用是求序列中的逆序数个数。当然 逆序数也可以用树状数组 完成,这里就不介绍了。 归并排序(merge sort) 归并和快排都是 基于分治算法 的。分治算法其实应用挺多的,很多分治会用到递归,也有很多递归实现的算法是分治,但事实上 分治和递归是两把事 。分治就是分而治之。因为面对排序,如果不采用合理策略。每多一个数就会对整个整体带来巨大的影响。而分治就是将整个问题可以分解成相似的子问题。子问题的解决要远远高效于整个问题的解决,并且子问题的合并并不占用太大资源。 至于归并的思想是这样的: 第一次:整串先进行划分成1个一个单独,第一次是一一( 12 34 56--- )归并成若干对,分成若干2个区间.归并完( xx xx xx xx---- )这样局部有序的序列。

005-排序算法-归并排序

不想你离开。 提交于 2020-01-23 23:06:05
一、概述   基本思想:采用分治法,将已有的有序子序列合并,得到一个完整的有序序列 排序方法 时间复杂度(平均) 时间复杂度 (最坏) 时间复杂度(最好) 空间复杂度 稳定性 归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定 分治算法   分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。   分治算法的一般步骤:   (1)分解,将要解决的问题划分成若干规模较小的同类问题;   (2)求解,当子问题划分得足够小时,用较简单的方法解决;   (3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。 1.1、算法说明      下图更加能够说明分治法      1.2、算法实现   将长度为 n 的序列分成两个长度为 2/n 的子序列,然后对着两个子序列进行归并排序,子序列又被分成子序列再进行归并排序,最终对有序子序列进行归并,得到最终的有序序列。   根据具体的实现,归并排序包括" 从上往下 "和" 从下往上 "2种方式。 public static int[] mergeSort(int[] nums, int l, int h) { if (l == h) return new int[] { nums[l] }; int mid = l + (h

归并排序分析

走远了吗. 提交于 2020-01-23 23:04:46
一.归并排序原理   1.拆分(以二分归并排序为例:将一个数组折半拆分为两个数组,直到不可拆分)   2.比较(元素之间两两进行比较)   3.归并(元素比较完成后进行合并)   用百度百科的一张图更加方便地理解:         归并排序是一种稳定的排序算法,但是用到了递归,比较消耗内存。 二.归并排序时间复杂度分析   归并排序的时间复杂度包括分解,比较,合并。   最好的情况下,数组是已排序的,那么归并排序的时间复杂度为O(n)级的。   最坏的情况下,数组是逆序的,那么归并排序的时间复杂度为O(nlogn)级的。 归并排序的平均时间复杂度是O(nlogn) 。 三.代码实现(Java) package json.study; import java.util.Arrays; public class Test05 { static int number=0; public static void main(String[] args) { int[] arr = {9,8,7,5,6,1,2,3,4}; cutAndSort(arr); System.out.println(Arrays.toString(arr)); } private static void cutAndSort(int[] arr) { cutAndSort(arr, 0, arr.length -

算法学习——利用归并排序求逆序对的数量

三世轮回 提交于 2020-01-23 22:18:46
首先明白逆序对的定义,逆序对就是数组中两个元素前大后小,我们就称这两个元素为一组逆序对。 接着看题目: 我们利用分治的思想,将区间一分为二,然后得到了逆序对的存在情况共三种: 1.两个元素都在左侧区间。 2.两个元素都在右侧区间。 3.两个元素一个在左,一个在右。 那么很明显我们分治的去解决这个问题,就得到解法, 1.将区间划分成左右两个区间 2.递归左右两个区间 3.统计逆序对数量(1)+(2) 4.计算逆序对数量(3) 5.返回相应的结果。 那么问题来了,逆序对(1)(2)的情况都很容易理解怎么求,但是情况(3)的逆序对我们该怎么样求数量呢? 大佬给的方法是这样的:我们已经将区间划分成为了左右两个区间,我们只需要统计,对于右区间中的每一个元素,在左区间内有多少元素比他大,满足左大右小就可以了。这个时候我们想到了归并排序的合并过程,就是利用两个指针,分别对两个区间的元素进行比较,然后把小的元素放进临时数组里,并且将对应的指针往后移动。由于归并排序的左右区间大小是确定的,左区间有(L+R)/2个元素,所以我们利用这点,当右区间的指针每次需要移动的时候,就表示左区间内当前剩余的所有元素都是比他大的,也就是说,对于右区间指针所指的当前元素,存在有 【左区间剩余的所有元素数量】个逆序对。核心就是这些,接下来是代码。 #include<iostream> using namespace

归并排序

好久不见. 提交于 2020-01-23 21:46:48
思路 归并排序就是先将要排序的元素打半拆分,拆至一个元素时,再使用二路合并的方法将元素重新合并回来。 如图所示: 特点 归并排序具有稳定的特点,并且时间的复杂度比一些其他的排序时间用的少一点,它的时间复杂度是O(n log n) 。 代码如下: #include"stdio.h" int a[10010],b[10010]; void merge(int a[],int begin,int mid,int last) { int i,j,k; k=i=begin; j=mid; while(i<mid&&j<last)//二路合并 { if(a[i]<a[j])b[k++]=a[i++]; else b[k++]=a[j++]; } while(i<mid)//如果有剩下的直接往后装 { b[k++]=a[i++]; } while(j<last) { b[k++]=a[j++]; } for(k=begin;k<last;k++)a[k]=b[k]; } void mergesort(int a[],int begin,int last) { if(begin==last-1)return ;//如果只剩一个值就返回 int mid=(begin+last)/2; mergesort(a,begin,mid);//打半 mergesort(a,mid,last); merge(a

归并排序应用-----求逆序数

风流意气都作罢 提交于 2020-01-23 20:10:55
归并排序是冒泡排序的一种升级版排序,其灵魂是分治思想,在二分的基础上进行排序,可以将原来时间复杂度为O(n^2)的冒泡排序降低为O(nlogn)的归并排序。 下面我们先来看归并排序,之后再来讲归并排序的应用—求逆序数 归并排序 前面提到,归并排序采用的是二分思想,我们先把一段需要排序的序列分成两半,是不是每一段的交换次数就会变少,然后我们又将分成的两段,继续分成四段,以此类推,直到分到每一段只有一个数的时候,就可以停止,接下来就是分治的–“治” 我们把它们拆开之后,就依次合上来,原来一个数合成两个数,在合的时候又进行比较大小,这样效率会提高很多,最终实现整个序列的排序。 看这张图,可以更好的理解: 下面看一下具体的代码实现 int gb [ 100001 ] ; //临时数组 void mers ( int * a , int s , int mid , int end ) //治(合) { int k = s ; int i = s , j = mid + 1 ; while ( i <= mid && j <= end ) { if ( a [ i ] <= a [ j ] ) { gb [ k ++ ] = a [ i ] ; i ++ ; } else { gb [ k ++ ] = a [ j ] ; j ++ ; } } while ( i <= mid ) { gb

归并排序

做~自己de王妃 提交于 2020-01-23 18:49:24
归并排序 个人认为归并排序和快速排序有相似之处,都是从大数组一步一步化为小数组再分步解决。 归并排序的思想其实很简单,总共分为两步,分与治。 分 指的就是将一个大数组一步一步变小,总体化小再化小,如下图本是长度为8的数组分为两个长度为4的数组再一步一步分下去直到8个数字。 核心代码 1 if(first<last) 2 { 3 int mid=(first+last)/2; 4 mergesort(a,first,mid,temp); //左边有序 5 mergesort(a,mid+1,last,temp); //右边有序 6 mergearray(a,first,mid,last,temp); //再将两个有序数组合并 7 } 8 治 就是将小的数组排好序,再一步步整合为大的数组。 之所以要先不断分隔,是为了左右两侧内部要保证有序,才可以进行归并操作。 核心代码 1 while(i<=m&&j<=n) 2 { 3 if(a[i]<a[j]) 4 temp[k++]=a[i++]; 5 else 6 temp[k++]=a[j++]; 7 } 8 while(i<=m) 9 temp[k++]=a[i++]; 10 while(j<=n) 11 temp[k++]=a[j++]; 12 for(i=0;i<k;i++) 13 a[first+i]=temp[i]; / 图源于

外部排序&多路归并排序

有些话、适合烂在心里 提交于 2020-01-23 07:50:39
外部排序: 一、定义问题 外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序 整个文件的目的。外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装入内存的部分,分别把每一部分调入内存完成排序。然后,对已经排 序的子文件进行多路归并排序。 二、处理过程 ( 1)按可用内存的大小,把外存上含有 n个记录的文件分成若干个长度为 L的子文件,把这些子文件依次读入内存,并利用有效的内部排序方法对它们进行排序,再将排序后得到的有序子文件重新写入外存; ( 2)对这些有序子文件逐趟归并,使其逐渐由小到大,直至得到整个有序文件为止。 先从一个例子来看外排序中的归并是如何进行的? 假设有一个含10000 个记录的文件,首先通过10 次内部排序得到10 个初始归并段R1~R10 ,其中每一段都含1000 个记录。然后对它们作如图10.11 所示的两两归并,直至得到一个有序文件为止 如下图 三 、多路归并排序算法以及败者树 多路归并排序算法在常见数据结构书中都有涉及。从2路到多路(k路),增大k可以减少外存信息读写时间,但k个归并段中选取最小的记录需要比较k-1次, 为得到u个记录的一个有序段共需要(u-1)(k-1)次,若归并趟数为s次,那么对n个记录的文件进行外排时

Java数据结构与算法精讲

被刻印的时光 ゝ 提交于 2020-01-23 03:19:40
课程简介 本系列视频教程为数据结构与算法基础,使用java语言描述,适合没有学过C/C++有一定Java基础的同学。没有Java基础的同学可以先行学习Java基础。 课程目录 ├─线性表 ├─栈和队列 ├─HashMap和LinkedHashMap ├─树 ├─二叉树 ├─图 ├─图的遍历与最小生成树 ├─图的最短路径与拓扑排序 ├─算法简介 ├─算法排序 ├─排序与归并 ├─递归与穷举 ├─贪心和分治 ├─动态规划和回溯 来源: CSDN 作者: di_pingxian 链接: https://blog.csdn.net/di_pingxian/article/details/103897423

归并排序

狂风中的少年 提交于 2020-01-23 02:59:18
归并排序是一个典型的基于分治的递归算法。它不断地将原数组分成大小相等的两个子数组(可能相差1),最终当划分的子数组大小为1时(即left小于right不成立时) ,将划分的有序子数组合并成一个更大的有序数组。 归并排序思路分析: 归并排序算法有两个基本的操作,一个是分,也就是把原数组划分成两个子数组的过程。另一个是治,它将两个有序数组合并成一个更大的有序数组。 它将数组平均分成两部分: center = (left + right)/2,当数组分得足够小时---数组中只有一个元素时,只有一个元素的数组自然而然地就可以视为是有序的,此时就可以进行合并操作了。因此,上面讲的合并两个有序的子数组,是从 只有一个元素 的两个子数组开始合并的。 合并后的元素个数:从 1-->2-->4-->8...... 比如初始数组:[19,15,37,12,25] 0 1 2 3 4 19 15 37 12 25 第一步:分解 首先将数组拆分成两部分,即19 15 37为一组,12 25为一组,这是第一层,如图所示: 19 15 37 12 25 第二步:分解 将第一步得到的数组继续分解,19 15为一组,37为一组,12为一组,25为一组,这四组是第二层,如图所示: 19 15 37 12 25 第三步:分解 将第二步分解得到的数组再次分解,此时只剩下19 15这一组可以分解,所以继续分解,19为一组