插入排序、半分插入排序、希尔排序

来源:互联网 发布:如何她推做淘宝客 编辑:程序博客网 时间:2024/06/10 00:33

  • 插入排序
  • 二分插入排序
  • 希尔排序


插入排序

最好情况:Ο(n)
最坏情况:Ο(n2
平均情况:Ο(n2
辅助空间:Ο(C)
稳定性:稳定

对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

过程:

  1. 暂存未排序序列第一个元素
  2. 将暂存元素与前元素进行比较
    2.1. 如果前元素比暂存元素大,则前元素后移
    2.2. 如果前元素比暂存元素小或遍历到队列尽头,则将暂存元素插入到当前元素中
public static void main(String[] args) {    int[] arr = new int[]{5, 8, 6, 12, 2, 4, 10, 9, 1, 7, 3, 0, 13};    int length = arr.length;    for (int i = 1; i < length; i++) {    //i < length 使i能遍历每一个节点,i的大小代表已排序序列的长度        int j = i - 1, temp = arr[i];    //temp暂存i位置的元素,因为接下来i位置要被前面的元素占据        while (j >= 0 && arr[j] > temp) {    //如果没有走到序列尽头而且当前元素比temp大,那就将当前元素后移            arr[j + 1] = arr[j];            j--;        }        arr[j + 1] = temp;    //将temp插入合适的位置        print(arr);    }}

输出:

5 8 6 12 2 4 10 9 1 7 3 0 13
5 6 8 12 2 4 10 9 1 7 3 0 13
5 6 8 12 2 4 10 9 1 7 3 0 13
2 5 6 8 12 4 10 9 1 7 3 0 13
2 4 5 6 8 12 10 9 1 7 3 0 13
2 4 5 6 8 10 12 9 1 7 3 0 13
2 4 5 6 8 9 10 12 1 7 3 0 13
1 2 4 5 6 8 9 10 12 7 3 0 13
1 2 4 5 6 7 8 9 10 12 3 0 13
1 2 3 4 5 6 7 8 9 10 12 0 13
0 1 2 3 4 5 6 7 8 9 10 12 13
0 1 2 3 4 5 6 7 8 9 10 12 13

插入排序

插入排序

插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。


二分插入排序

最好情况:Ο(nlogn)
最坏情况:Ο(n2
平均情况:Ο(n2
辅助空间:Ο(C)
稳定性:稳定

对于插入排序,如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。

过程:

  1. 确定未排序序列范围
  2. 暂存未排序序列第一个元素
  3. 使用二分查找法查找合适位置
  4. 将该位置及以后的元素后移一个单位
  5. 将暂存元素插入该位置
public static void main(String[] args) {    int[] arr = new int[]{5, 8, 6, 12, 2, 4, 10, 9, 1, 7, 3, 0, 13};    int length = arr.length;    for (int i = 1; i < length; i++) {    //i < length 使i能遍历每一个节点,i的大小代表已排序序列的长度        int temp = arr[i];    //temp暂存i位置的元素,因为接下来i位置要被前面的元素占据        int left = 0, right = i - 1;        while (left <= right) {    //使用二分查找法定位插入位置,左边界必须有可能等于右边界,不然第一个元素不会被遍历            int middle = (left + right) / 2;            if (arr[middle] > temp) {                right = middle - 1;            } else {                left = middle + 1;            }        }    //此时的左边界会在右边界的右边,左边界所处位置正是暂存元素要插入的位置        for (int j = i - 1; j >= left; j--) {    //将左边界右边所有元素向后移动            arr[j + 1] = arr[j];        }        arr[left] = temp;    //将temp插入左边界位置        print(arr);    }}

当n较大时,二分插入排序的比较次数比直接插入排序的最差情况好得多,但比直接插入排序的最好情况要差,所当以元素初始序列已经接近升序时,直接插入排序比二分插入排序比较次数少。二分插入排序元素移动次数与直接插入排序相同,依赖于元素初始序列。


希尔排序

最好情况:Ο(n1.3
最坏情况:Ο(n2
平均情况:Ο(nlogn)~ Ο(n2
辅助空间:Ο(C)
稳定性:不稳定

希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
假设有一个很小的数据在一个已按升序排好序的数组的末端。如果用复杂度为O(n^2)的排序(冒泡排序或直接插入排序),可能会进行n次的比较和交换才能将该数据移至正确位置。而希尔排序会用较大的步长移动数据,所以小数据只需进行少数比较和交换即可到正确位置。

过程:

  1. 暂存未排序序列第一个步长元素
  2. 将暂存元素与前步长元素进行比较
    2.1. 如果前元素比暂存元素大,则前元素后移
    2.2. 如果前元素比暂存元素小或遍历到队列尽头,则将暂存元素插入到当前元素中
public static void main(String[] args) {    int[] arr = new int[]{5, 8, 6, 12, 2, 4, 10, 9, 1, 7, 3, 13, 0};    int length = arr.length;    for (int gap = length / 3; gap > 0; gap /= 3) {    //定义步长        for (int i = gap; i < length; i++) {    //最开始gap的目的是让后面的元素向前移动足够长的距离。gap在最后一次遍历时候会为1,也就是变为简单插入排序            int j = i - gap, temp = arr[i];    //temp暂存i位置的元素,因为接下来i位置要被前面的元素占据            while (j >= 0 && arr[j] > temp) {    //如果没有走到序列尽头而且当前元素比temp大,那就将当前元素后移                arr[j + gap] = arr[j];                j -= gap;            }            arr[j + gap] = temp;    //将temp插入合适的位置            print(arr);        }    }}

输出:

2 8 6 12 5 4 10 9 1 7 3 13 0
2 4 6 12 5 8 10 9 1 7 3 13 0
2 4 6 12 5 8 10 9 1 7 3 13 0
2 4 6 9 5 8 10 12 1 7 3 13 0
1 4 6 9 2 8 10 12 5 7 3 13 0
1 4 6 9 2 7 10 12 5 8 3 13 0
1 4 3 9 2 7 6 12 5 8 10 13 0
1 4 3 9 2 7 6 12 5 8 10 13 0
0 4 3 9 1 7 6 12 2 8 10 13 5
0 4 3 9 1 7 6 12 2 8 10 13 5
0 3 4 9 1 7 6 12 2 8 10 13 5
0 3 4 9 1 7 6 12 2 8 10 13 5
0 1 3 4 9 7 6 12 2 8 10 13 5
0 1 3 4 7 9 6 12 2 8 10 13 5
0 1 3 4 6 7 9 12 2 8 10 13 5
0 1 3 4 6 7 9 12 2 8 10 13 5
0 1 2 3 4 6 7 9 12 8 10 13 5
0 1 2 3 4 6 7 8 9 12 10 13 5
0 1 2 3 4 6 7 8 9 10 12 13 5
0 1 2 3 4 6 7 8 9 10 12 13 5
0 1 2 3 4 5 6 7 8 9 10 12 13

希尔排序

希尔排序是不稳定的排序算法,虽然一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱。





来源:http://www.cnblogs.com/eniac12/p/5329396.html

0 0