Java排序算法总结

1. 总体介绍

分类

  排序大的分类能够分为两种,内排序和外排序。在排序过程当中,所有记录存放在内存,则称为内排序,若是排序过程当中须要使用外存,则称为外排序。主要须要理解的都是内排序算法:算法

  内排序能够分为如下几类:shell

  (1)、插入排序:直接插入排序、二分法插入排序、希尔排序。性能

  (2)、选择排序:简单选择排序、堆排序。ui

  (3)、交换排序:冒泡排序、快速排序。spa

  (4)、归并排序指针

  (5)、基数排序blog

性能对比

稳定性:就是能保证排序前两个相等的数据其在序列中的前后位置顺序与排序后它们两个前后位置顺序相同。即若是A i == A j,A i 原来在 A j 位置前,排序后 A i  仍然是在 A j 位置前。排序

  不稳定:简单选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法递归

  稳定:冒泡排序、直接插入排序、二分法插入排序,归并排序和基数排序都是稳定的排序算法。内存

时间复杂度:一个算法执行所耗费的时间。

  O(nlogn):快速排序,归并排序,希尔排序,堆排序。

  O(n^2):直接插入排序,简单选择排序,冒泡排序。

  O(n): 桶、箱、基数排序

  快速排序是目前基于比较的内部排序中最好的方法, 其次是归并和希尔,堆排序在数据量很大时效果明显。当数据是随机分布时快速排序的平均时间最短。

空间复杂度:运行完一个程序所需内存的大小。

解释:n: 数据规模;k:“桶”的个数;In-place: 占用常数内存,不占用额外内存;Out-place: 占用额外内存。

 

排序方法的选择

  1.数据规模很小(插入、简单选择、冒泡)

    (1)数据基本有序的状况下,可选直接插入排序

    (2)数据无序时,对稳定性不做要求宜用简单选择排序,对稳定性有要求宜用插入或冒泡

  2.数据规模通常(快速排序、归并排序)

  (1)彻底能够用内存空间,序列杂乱无序,对稳定性没有要求,快速排序,此时要付出log(N)的额外空间。

  (2)序列自己可能有序,对稳定性有要求,空间容许下,宜用归并排序

  3.数据规模很大(归并、桶)

     (1)对稳定性有求,则可考虑归并排序。

      (2)对稳定性没要求,宜用堆排序

  4.待排序列初始基本有序(正序),宜用直接插入,冒泡

 

 2. 插入排序(Insertion Sort)

  基本思想:依次遍历元素,在已排序的序列中找到合适的位置将当前遍历的元素插入,直到全部元素都已排序。

  方法:直接插入排序、二分插入排序、希尔排序

2.1 直接插入排序

算法思想:

  • <1>.从第一个元素开始,该元素能够认为已经被排序;
  • <2>.取出下一个元素,在已经排序的元素序列中从后向前扫描;
  • <3>.若是该元素(已排序)大于新元素,将该已排序元素移到下一位置;
  • <4>.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  • <5>.将新元素插入到该位置后;
  • <6>.重复步骤2~5。

时间复杂度:平均状况下:O(n­2)
        最好的状况下:正序有序(从小到大),这样只须要比较n次,不须要移动。所以时间复杂度为O(n)  
        最坏的状况下:逆序有序,这样每个元素就须要比较n次,共有n个元素,所以实际复杂度为O(n­2)  
稳定性:稳定。由算法思想易知,反向遍历已排序元素,若已排序元素小于等于当前元素,则将当前元素插入该已排序元素后的位置,所以相对顺序不变,插入排序是稳定的。     

 

2.2 二分排序(折半插入排序)

二分法查找基本思想:对于一个有序的待查序列,定义三个指针low、high、mid,分别指向待查序列所在范围的下界、上界及区间中间位置,即mid=(low+high)/2。对比待查数据与mid所指的值,若相等则查找成功并返回mid,若待查数小于mid值,则令high=mid-1,不然令low=mid+1,获得新的须要查找的区间,如此循环直到找出或找不到。以下示例:

二分排序:从第二个数开始日后遍历,用二分法查找合适的插入位置。当low<high条件不成立时说明找到合适位置,将low及以后元素后移

时间复杂度:二分插入排序的比较次数与待排序记录的初始状态无关,仅依赖于记录的个数。当n较大时,比直接插入排序的最大比较次数少得多。但大于直接插入排序的最小比较次数。算法的移动次数与直接插入排序算法的相同,最坏的状况为n2/2,最好的状况为n,平均移动次数为O(n2)。  

稳定性:稳定。

2.3 希尔排序(Shell Sort)

基本思想:希尔排序也是一种插入排序方法,其实是一种分组插入方法。先取定一个小于n的整数d1做为第一个增量,这样能够把表的所有记录分红d1个组:全部距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;而后,取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<…<d2<d1),即全部记录放在同一组中进行直接插入排序为止。

  希尔排序的核心在于间隔序列的设定。既能够提早设定好间隔序列,也能够动态的定义间隔序列。

时间复杂度:  平均状况下:O(N*logN)
       最好状况:因为希尔排序的好坏和步长d的选择(di到di+1的选择策略)有不少关系,所以,目前尚未得出最好的步长如何选择(如今有些比较好的选择了,但不肯定是不是最好的)。因此,不知道最好的状况下的算法时间复杂度。  
       最坏状况:O(N*logN),最坏的状况下和平均状况下差很少。  

稳定性:因为屡次插入排序,咱们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不一样趟的插入排序过程当中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,因此shell排序是不稳定的。(有个猜想,方便记忆:通常来讲,若存在不相邻元素间交换,则极可能是不稳定的排序。)

 

 

 

解释:就是将增量(d)为1的直接插入排序,增量改成从d到1的递减。再也不是相邻元素间的对比,而是以d为间隔的对比插入。

3. 交换排序

3.1 冒泡排序(Bubble Sort)

基本思想经过无序区中相邻记录关键字间的比较和位置的交换,使关键字最小的记录如气泡通常逐渐往上“漂浮”直至“水面”。

时间复杂度:平均O(n2)

  最好状况:正序有序,则只须要比较n次。故,为O(n)  
  最坏状况:  逆序有序,则须要比较(n-1)+(n-2)+……+1,故,为O(N2)

稳定性:稳定。排序过程当中只交换相邻两个元素的位置。所以,当两个数相等时,是不必交换两个数的位置的。因此相对位置并无改变,冒泡排序算法是稳定的! 

算法描述:

  • <1>.比较相邻的元素。若是第一个比第二个大,就交换它们两个;
  • <2>.对每一对相邻元素做一样的工做,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • <3>.针对全部的元素重复以上的步骤,除了最后一个;
  • <4>.重复步骤1~3,直到排序完成

3.2 快速排序(Quick Sort)

基本思想:由冒泡排序改进而来的。在待排序的n个记录中任取一个记录(一般取第一个记录),把该记录放入适当位置后,数据序列被此记录划分红两部分。全部关键字比该记录关键字小的记录放置在前一部分,全部比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位)。

核心思想:经过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另外一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

时间复杂度:O(N*logN)

  最好的状况:由于每次都将序列分为两个部分(通常二分都复杂度都和logN相关),故为 O(N*logN)  
  最坏的状况:基本有序时,退化为冒泡排序,几乎要比较N*N次,故为O(N*N)

稳定性:不稳定。因为每次都须要和中轴元素(不必定相邻)交换,所以原来的顺序就可能被打乱。快速排序是不稳定的。

算法描述:

快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述以下:

  • <1>.从数列中挑出一个元素,称为 "基准"(pivot);
  • <2>.从新排序数列,全部元素比基准值小的摆放在基准前面,全部元素比基准值大的摆在基准的后面(相同的数能够到任一边)。在这个分区退出以后,该基准就处于数列的中间位置。这个称为分区(partition)操做;
  • <3>.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
相关文章
相关标签/搜索