排序算法之 直接插入排序和希尔排序

这一篇要总结的是插入排序中的直接插入排序和希尔排序,我们主要从以下几点进行总结。

1、直接插入排序及算法实现

2、希尔排序及算法实现

1、直接插入排序及算法实现

什么是直接插入排序呢?直接插入排序的基本思想是:每次从无序序列中取出第一个元素插入到已经排好序的有序序列中,从而得到一个新的,数量加1的有序序列。

1-1、示意图

下面是直接插入排序的图解说明。

1-2、代码

下面是直接插入排序的算法实现代码。

InsertSort.java

public class InsertSort {
    public static void main(String[] args) {
        int[] list = {90, 10, 20, 50, 70, 40, 80, 60, 30, 52};
        System.out.println("************直接插入排序************");
        System.out.println("排序前:");
        display(list);
        System.out.println("");

        System.out.println("排序后:");
        insertSort(list);
        display(list);
    }

    /**
     * 直接插入排序算法
     */
    public static void insertSort(int[] list) {
        int temp;
        // 从无序序列中取出第一个元素 (注意无序序列是从第二个元素开始的)
        for (int i = 1; i < list.length; i++) {
            temp = list[i];
            int j;
            // 遍历有序序列
            // 如果有序序列中的元素比临时元素大,则将有序序列中比临时元素大的元素依次后移
            for (j = i - 1; j >= 0 && list[j] > temp; j--) {
                list[j + 1] = list[j];
            }
            // 将临时元素插入到腾出的位置中
            list[j + 1] = temp;
        }
    }
    
    /**
     * 遍历打印
     */
    public static void display(int[] list) {
        System.out.println("********展示开始********");
        if (list != null && list.length > 0) {
            for (int num :
                    list) {
                System.out.print(num + " ");
            }
            System.out.println("");
        }
        System.out.println("********展示结束********");
    }
}
扫描二维码关注公众号,回复: 3215620 查看本文章

测试结果:

       

2、希尔排序及算法实现

 希尔排序是直接插入排序的一种更高效的改进版本,又称为“缩小增量排序”。

2-1、示意图

 

2-2、代码

ShellSort.java 

public class ShellSort {
    public static void main(String[] args) {
        int[] list = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
        System.out.println("************希尔排序************");
        System.out.println("排序前:");
        display(list);
        System.out.println("");

        System.out.println("排序后:");
        shellSort(list);
        display(list);
    }

    /**
     * 希尔排序算法
     */
    public static void shellSort(int[] list) {
        // 取增量
        int gap = list.length / 2;
        int temp;

        while (gap >= 1) {
            // 无序序列
            for (int i = gap; i < list.length; i++) {
                temp = list[i];
                int j;

                // 有序序列
                for (j = i - gap; j >= 0 && list[j] > temp; j = j - gap) {
                    list[j + gap] = list[j];
                }
                list[j + gap] = temp;
            }

            // 缩小增量
            gap = gap / 2;
        }
    }

    /**
     * 遍历打印
     */
    public static void display(int[] list) {
        System.out.println("********展示开始********");
        if (list != null && list.length > 0) {
            for (int num :
                    list) {
                System.out.print(num + " ");
            }
            System.out.println("");
        }
        System.out.println("********展示结束********");
    }
}

测试结果:

        有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

        插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

      希尔排序是一种插入排序算法,它出自D.L.Shell,因此而得名。Shell排序又称作缩小增量排序。

算法分析

         插入排序的思想:

        从第二个元素开始往后,依次选择哨兵元素和前面的元素比较,如果前一个元素大于该哨兵元素(从小到大排序),则把前面那个元素移动到后一个位置;继续往前比较,直到找某个元素不大于该哨兵元素,则把哨兵元素插入到位置上;

        插入排序的步骤:

       1、第二个元素开始外后选择一个哨兵元素;

       2、让哨兵元素和前面的元素进行比较,找到合适的位置插入;

       3、循环上面两步,直到选择完所有元素;

        shell排序的思想:

       shell排序是相当于把一个数组中的所有元素分成几部分来排序;先把几个小部分的元素排序好,让元素大概有个顺序,最后再全面使用插入排序。一般最后一次排序都是和上面的插入排序一样的;

       

       shell排序的步骤:

       比如:

        数组有10个元素,增量 d = 5;则比较元素为:array[0]    array[0+d]    array[0+2d]  array[0+3d];(当然 d 会改变的,d = d/2  或者 d = d -2)

       第一次  d = 5  比较的元素为:array[0]  , array[5]  

       第二次  d = d/2 = 2 比较元素为:array[0]  , array[2]  , array[4] , array[6] , array[8]

       第三次  d = d/2 = 1 比较元素为:从array[0] 到  array[9]

        其实上面的插入排序可以看作是 增量 d = 1的shell排序;当然同理,shell排序 最后增量 d = 1时, 就是插入排序了;

时间复杂度

         插入排序的时间复杂度:

         在最好的情况下(元素已经排好顺序):那么只需要循环 n-1  次就可以了,时间复杂度 O(n)

         在最差的情况下 (元素是逆序的):要循环调整次数: [ n * (n-1) ] / 2 ,时间复杂度为 O(n ^ 2)

        平均时间复杂度为:O(n ^ 2)

        

        shell排序的时间复杂度:   

        shell排序的时间复杂度是根据选中的 增量d 有关的,所以分析shell排序的时间复杂度是个比较麻烦的事;这里只给出答案,不推算了;

         在最优的情况下,时间复杂度为:O(n ^ (1.3) )   (元素已经排序好顺序)

         在最差的情况下,时间复杂度为:O(n ^ 2);

空间复杂度

        空间复杂度都为:O(1);

猜你喜欢

转载自blog.csdn.net/jackwang_dev/article/details/82623079