八大排序算法分析-插入排序

来源:互联网 发布:手机淘宝怎么追加评价 编辑:程序博客网 时间:2024/05/22 13:54

大部分内容转自:
http://www.cnblogs.com/liuling/p/2013-7-24-01.html
http://www.cnblogs.com/Braveliu/archive/2013/01/15/2861201.html
http://blog.csdn.net/gameover8080/article/details/7054248

排序大的分类可以分为两种:内排序和外排序。在排序过程中,全部记录存放在内存,则称为内排序,如果排序过程中需要使用外存,则称为外排序。先从内排序算法开始。本文所有代码以Java实现,以增序排序。

内排序有可以分为以下几类:

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

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

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

  (4)、归并排序

  (5)、基数排序

插入排序算法,其基本思想是这样的:每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的字序列的合适位置,直到全部插入排序完为止。

1. 直接插入排序

从首位开始,每次向后选一个与前方记录挨个比较,选择合适的位置将其插入,直到末尾,所有记录完成排序。示例图如下:
这里写图片描述

没啥好解释的,直接上代码:

public static void main(String[] args) {    int[] a = {123,4,122,5,435,13,253,19,53};    for(int i=0 ; i<a.length ; i++) {        int temp = a[i];        int j;        for(j=i-1 ; j>=0 ; j--) {            if(a[j] > a[i]) {               a[j+1] = a[j]            }else {             break;         }      }      a[j] = temp;    } }

直接插入排序的初始数据状态对耗时影响非常大,如果输入时为已排序状态,则时间复杂度为O(n),既只需比较一次。如果逆序输入,则每次都需要比较,既复杂度为O(n2)。

直接插入排序是稳定的排序算法。

2. 二分插入排序

二分插入排序与直接插入排序思想是一致的,有所区别的地方,在于其选择插入位置的时候,使用的是二分查找法,意图减少选择的比较次数。算法示意图如下:
这里写图片描述

这个同样没啥好解释的,直接上代码:

package com.sort;public class 二分插入排序 {    public static void main(String[] args) {        int[] a={49,38,65,97,176,213,227,49,78,34,12,164,11,18,1};        System.out.println("排序之前:");        for (int i = 0; i < a.length; i++) {            System.out.print(a[i]+" ");        }        //二分插入排序        sort(a);        System.out.println();        System.out.println("排序之后:");        for (int i = 0; i < a.length; i++) {            System.out.print(a[i]+" ");        }    }    private static void sort(int[] a) {        for (int i = 0; i < a.length; i++) {            int temp = a[i];            int left = 0;            int right = i-1;            int mid = 0;            while(left<=right){                mid = (left+right)/2;                if(temp<a[mid]){                    right = mid-1;                }else{                    left = mid+1;                }            }            for (int j = i-1; j >= left; j--) {                a[j+1] = a[j];            }            if(left != i){                a[left] = temp;            }        }    }}

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

3. shell排序

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。算法如图:
这里写图片描述

注意的要点是,每个增量中包含的数据,需要按照插入排序。例如图中72、874、283、911、820,需要进行排序,排序后为72、283、820、874、911。代码如下:

package com.sort;//不稳定public class 希尔排序 {    public static void main(String[] args) {        int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1};        System.out.println("排序之前:");        for (int i = 0; i < a.length; i++) {            System.out.print(a[i]+" ");        }        //希尔排序        int d = a.length;        while(true){            d = d / 2;            for(int x=0;x<d;x++){                for(int i=x+d;i<a.length;i=i+d){                    int temp = a[i];                    int j;                    for(j=i-d;j>=0&&a[j]>temp;j=j-d){                        a[j+d] = a[j];                    }                    a[j+d] = temp;                }            }            if(d == 1){                break;            }        }        System.out.println();        System.out.println("排序之后:");        for (int i = 0; i < a.length; i++) {            System.out.print(a[i]+" ");        }    }}

直接插入排序是稳定的,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

  希尔排序的时间性能优于直接插入排序,原因如下:
  (1)当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
  (2)当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。
  (3)在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
  因此,希尔排序在效率上较直接插人排序有较大的改进。
  希尔排序的平均时间复杂度为O(nlogn)。
插入排序的

1 0