插入排序算法---插入排序与希尔排序

本文主要说明插入排序、shell排序两种排序方法。 


一、插入排序 
 
算法思想: 
  假定这个数组的序是排好的,然后从头往后,如果有数比当前外层元素的值大,则将这个数的位置往后挪,直到当前外层元素的值大于或等于它前面的位置为止.这具算法在排完前k个数之后,可以保证a[1…k]是局部有序的,保证了插入过程的正确性.

一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:

⒈ 从第一个元素开始,该元素可以认为已经被排序

⒉ 取出下一个元素,在已经排序的元素序列中从后向前扫描

⒊ 如果该元素(已排序)大于新元素,将该元素移到下一位置

⒋ 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

⒌ 将新元素插入到下一位置中

⒍ 重复步骤2~5

如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。

插入排序过程示例:

下面是对无序表[12,15,9,20,6,31,24]的排序过程:

伪代码:

  INSERTION-SORT(A)
1  for j ← 2 to length[A]
2       do key ← A[j]
3          ? Insert A[j] into the sorted sequence A[1 ‥ j - 1].
4          i ← j - 1
5          while i > 0 and A[i] > key
6              do A[i + 1] ← A[i]
7                 i ← i - 1
8          A[i + 1] ← key

代码实现:

     static int count = 0;
     /***
     * 把n个待排序的元素看成一个有序表和一个无序表, 开始有序表只包含一个元素,无序表中包含n-1个元素,
     * 排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较, 将它插入到有序表中的适当位置,使之成为新的有序表。
     */
    public static void runInsertSort(int[] a) {
        for (int i = 1; i < a.length; i++) {
            int insertVal = a[i];
            // insertValue准备和前一个数比较
                       int index = i - 1;

            while (index >= 0 && insertVal < a[index]) {
                // 将把a[index]向后移动
                                a[index + 1] = a[index];
                // 让index向前移动一位
                               index--;
            }

            // 将insertValue插入到适当位置
                        a[index + 1] = insertVal;
            System.out.println("indexPos>>>"+(index+1));
            System.out.print("第" + (i) + "次排序结果:");
            for (int k = 0; k < a.length; k++) {
                System.out.print(a[k] + "\t");
            }
            System.out.println("");
            count++;
        }
        System.out.print("最终排序结果:");
        for (int l = 0; l < a.length; l++) {
            System.out.print(a[l] + "\t");
        }
    }

public static void main(String[] args) {
        int[] array = new int[6];
        for (int k = 0; k < array.length; k++) {
            array[k] = (int) (Math.random() * 100);
        }
        System.out.print("排序之前结果为:");
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }
        System.out.println("");
        runInsertSort(array);
        System.out.println("交换次数:"+count);
    }

打印结果如下:

排序之前结果为:66    12    90    75    43    85
indexPos>>>0
第1次排序结果:12    66    90    75    43    85
indexPos>>>2
第2次排序结果:12    66    90    75    43    85
indexPos>>>2
第3次排序结果:12    66    75    90    43    85
indexPos>>>1
第4次排序结果:12    43    66    75    90    85
indexPos>>>4
第5次排序结果:12    43    66    75    85    90
最终排序结果:12    43    66    75    85    90    排序次数:5

算法复杂度:

如果目标是把n个元素的序列升序排列,那么采用插入排序存在最好情况和最坏情况。最好情况就是,序列已经是升序排列了,在这种情况下,需要进行的比较操作需(n-1)次即可。最坏情况就是,序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。插入排序的赋值操作是比较操作的次数加上 (n-1)次。平均来说插入排序算法的时间复杂度为O(n^2)。因而,插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,例如,量级小于千,那么插入排序还是一个不错的选择。

稳定性:

插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。

二分插入排序

插入排序中,总是先寻找插入位置,然后在实行挪动和插入过程;寻找插入位置采用顺序查找的方式(从前向后或者从后向前),既然需要插入的数组已经是有序的,那么可以采用二分查找方法来寻找插入位置,提高算法效率,但算法的时间复杂度仍为O(n2)。

public class SortSolution {

    static int count = 0;

    /***
     * 向有序序列中插入元素,那么插入位置可以不断地平分有序序列, 并把待插入的元素的关键字与平分有序序列的关键字比较,以确定下一步要平分的子序列,
     * 直到找到合适的插入位置位置。
     */
    public static void runBinaryInsertSort(int[] a) {
        for (int i = 1; i < a.length; i++) {
            int insertVal = a[i];// 待插入的值

            int low = 0;
            int high = i - 1;

            while (low <= high) {
                // 找出low,high的中间索引
                int mid = (low + high) / 2;
                // 如果要插入的值大于mid的值
                if (insertVal > a[mid]) {
                    low = mid + 1;
                }// 限制在索引大于mid的那一半中搜索
                else {
                    high = mid - 1;
                }// 限制在索引小于mid的那一半中搜索
            }

            // 将low到i处的所有元素向后整体移动一位
            for (int j = i; j > low; j--) {
                a[j] = a[j - 1];
            }

            // 将insertValue插入到适当位置
            a[low] = insertVal;
            System.out.println("indexPos>>>"+(low));
            //System.out.print("\n");
            System.out.print("第" + (i) + "次排序结果:");
            for (int k = 0; k < a.length; k++) {
                System.out.print(a[k] + "\t");
            }
            System.out.println("");
            count++;
        }
    }

    public static void main(String[] args) {
        int[] array = new int[1500];
        for (int k = 0; k < array.length; k++) {
            array[k] = (int) (Math.random() * 100);
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date begintime = new Date();
        System.out.println("开始时间: " + df.format(begintime));
        System.gc();
        System.out.print("排序之前结果为:");
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + "\t");
        }
        System.out.println("");
        runBinaryInsertSort(array);
        System.out.println("交换次数:"+count);
        Date endtime = new Date();
        System.out.println("结束时间:" + df.format(endtime));
        Date time = new Date(endtime.getTime() - begintime.getTime());
        System.out.println("总用时间:" + time.getMinutes() + "分"
                + time.getSeconds() + "秒");
    }

}
时间: 2024-08-01 22:43:30

插入排序算法---插入排序与希尔排序的相关文章

(转) 白话经典算法系列之三 希尔排序的实现(附源代码实现)

链接:http://blog.csdn.net/morewindows/article/details/6668714 希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率

常见排序集合(冒泡排序,选择排序,直接插入排序,二分插入排序,快速排序,希尔排序,归并排序)

一下是一些常见的排序算法: 交换元素(后面算法都有用到): // 交换元素 private static void swap(int[] a, int i, int j) { int temp; temp = a[i]; a[i] = a[j]; a[j] = temp; } 冒泡排序(有优化): // 冒泡排序(优化①,②,③,④) private static void bubbleSort(int[] a) { boolean flag = false;// ①表示整个序列是无序的 for

排序之插入排序:直接插入和希尔排序

一.插入排序 1.思想:原理类似抓扑克牌,在有序表中进行插入和查找,插入合适的位置时,之后的元素需要往后移动 2.时间复杂度: 最好:O(N),正序情况,只有比较时间,无移动时间 最坏:O(N2),逆序情况 平均:O(N2) 3.辅助空间:O(1) 4.稳定性:稳定 5.适用场合:适用于初始序列基本有序的情况,或者n小的时候,插入排序效率高 1 public static void insertSort(int[] a) { 2 int target,i,j; 3 for(j = 1;j<a.l

算法系列【希尔排序】篇

常见的内部排序算法有:插入排序.希尔排序.选择排序.冒泡排序.归并排序.快速排序.堆排序.基数排序等.用一张图概括: 关于时间复杂度: 1.     平方阶 (O(n2)) 排序各类简单排序:直接插入.直接选择和冒泡排序. 2.     线性对数阶 (O(nlog2n)) 排序快速排序.堆排序和归并排序: 3.     O(n1+§))排序,§ 是介于 0 和 1 之间的常数.希尔排序 4.     线性阶 (O(n)) 排序基数排序,此外还有桶.箱排序. 关于稳定性: 稳定的排序算法:冒泡排序

算法基础之希尔排序

希尔排序的实质就是分组插入排序, 是对直接插入排序的改进. 时间复杂度为O(nlongn), 跟快速排序, 堆排序的时间复杂度相同, 是一种较为快速的排序方式. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的 元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为 直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提

Java排序算法(四):希尔排序

[基本思想] 将原本有大量记录数的记录进行分组,分割成若干个子序列,此时每个子序列待排序的记录个数就比较少了,然后在这些子序列内分别进行直接插入排序,当整个序列都基本有序时,再对全体记录进行一次直接插入排序. 所谓的基本有序,就是小的关键字基本在前面,大的基本在后面,不大不小的基本在中间,像{2, 1, 3, 6, 4, 7, 5, 8, 9}这样可以称为基本有序了. [java实现] public class ShellSort { public static void main(String

排序算法总结之希尔排序

一,希尔排序算法介绍 ①希尔排序又称缩小增量排序 ,它本质上是一个插入排序算法.为什么呢? 因为,对于插入排序而言,插入排序是将当前待排序的元素与前面所有的元素比较,而希尔排序是将当前元素与前面增量位置上的元素进行比较,然后,再将该元素插入到合适位置.当一趟希尔排序完成后,处于增量位置上的元素是有序的. ②希尔排序算法的效率依赖于增量的选取 假设增量序列为 h(1),h(2).....h(k),其中h(1)必须为1,且h(1)<h(2)<...h(k) . 第一趟排序时在增量为h(k)的各个元

白话经典算法系列之三 希尔排序的实现

分类: 白话经典算法系列 2011-08-08 11:41 47406人阅读 评论(46) 收藏 举报 算法shell优化c 希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的 元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为 直接插入排序在元素基本有序的情况下(接近最好情

排序算法(二)之希尔排序

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法.希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一.本文会以图解的方式详细介绍希尔排序的基本思想及其代码实现. 基本思想 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止. 简单插入排序很循规蹈矩,不管数组分布是怎么样的,依然