首页 > 技术文章 > 插入排序

klguang 2016-04-24 15:21 原文

直接插入排序

将待排序序列分为有序区和无序区,将无序区的元素逐一插入到有序区合适的位置上,直到全部有序

类似玩牌时整理排的过程。

直接插入排序步骤

1.以数组第一个元素为有序区。

2.将无序区的第一个元素关键码,插入到有序区。

  • 寻找关键码在有序区的目标位置
  • 插入关键码

重复步骤2,直至全部有序。

直接插入排序演示

clip_image001

算法分析

clip_image002

直接插入排序-java实现

    /**
     * 直接插入排序的分步理解
     * 
     * @param arr
     */

    public static void straightInsertionSort_step(int[] arr) {
        int size = arr.length;
        for (int i = 1; i < size; i++) { // arr[i]为关键码
            int destIndex = 0; // 插入的目标下标
            int key = arr[i]; // 保存关键码
            // 遍历寻找destIndex
            for (int j = i - 1; j >= 0; j--) {
                if (arr[j] <= key) { // 如果关键码>=序区元素j,则插入j之后,否则,插入0下标
                    destIndex = j + 1;
                    break;
                }
            }
            // 后移记录
            for (int j = i - 1; j >= destIndex; j--) {// 从前向后会覆盖
                arr[j + 1] = arr[j];
            }
            // 插入
            arr[destIndex] = key;
            System.out.print("第 " + i + "轮 :" + Arrays.toString(arr));
            System.out.println("\tdestIndex:" + destIndex);
        }
    }

    /**
     * 直接插入排序
     * 
     * @param arr
     */
    public static void straightInsertionSort(int[] arr) {
        int size = arr.length;
        for (int i = 1; i < size; i++) {         // 外层控制轮数
            int key = arr[i];             // arr[i]为关键码
            int j = i - 1;
            for (; j >= 0 && key < arr[j]; j--){    //如果关键码>=序区元素j,则插入j之
                arr[j + 1] = arr[j];        // 在寻找关键码插入位置的同时将元素后移
            }
            arr[j + 1] = key;             // 插入目标位置
            System.out.print("第 " + i + "轮 :" + Arrays.toString(arr));
            System.out.println("\tdestIndex:" + (j + 1));
        }
    }

希尔排序

希尔排序是对直接插入排序的一种改进,着眼于:

  • 若排序记录按关键码基本有序,直接插入排序的效率很高
  • 记录个数少,直接插入排序效率高。因为直接插入排序时间复杂度为O(n^2),n越小,效率越高。

希尔排序思想:

  • 把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。保证整个序列基本有序。
  • 随着步长逐渐减小,所分成的序列包含的记录越来越多,当步长的值减小到 1 时,所有记录合成为一组,经过直接插入排序后,构成一组有序记录,则完成排序。

开始时增量的取值较大,每个子序列记录个数少,排序效率较高;后来增量逐步缩小,每个子序列中的记录个数增加,但已经基本有序,故排序效率也较高。

希尔排序演示:

clip_image003

算法分析

clip_image004

希尔排序-java实现

    /**
     *     “把记录按步长 gap分组,对每组记录采用直接插入排序方法进行排序。保证整个序列基本有序.”<br>
     * @param arr
     */
    public static void shellSort(int[] arr) {
        int size = arr.length;
        //把下标增量为gap的记录编为一个子序列
        //增量逐步减小,直到整个序列的子序列为本身,即增量gap=1
        for (int gap = size / 2; gap >= 1; gap /= 2) {
            //对子序列进行直接插入排序
            for (int i = gap; i < size; i++) {
                int key = arr[i];
                int j = i - gap;
                for (; j >= 0 && key < arr[j]; j -= gap) {
                    arr[j + gap] = arr[j];
                }
                arr[j + gap] = key;
            }
            System.out.println("gap: " + gap + " :" + Arrays.toString(arr));
        }
    }

推荐阅读