zoukankan      html  css  js  c++  java
  • 插入排序

    概述

      最近在学习算法,面试时候问了我快速排序,当场懵逼了,竟然没有听说过,我支支吾吾了半天然后告诉面试官,我TM没听说过,然后面试官用一种看智障的眼神结束了面试(以上纯属虚构,哈哈),本来以为排序算法也就什么冒泡排序,快速排序什么的,今天自己一看,我姹,竟然那么多种排序算法,没办法了,只能一个一个的看咯。

    核心思想

      其实核心思想很简单,就是把一个数组中的数据分成两个部分,第一部分是排好序的,第二部分是还没有排序的,然后遍历第二部分的数据,查找这个元素应该在第一个排好序的部分的什么位置,然后插入这个地方,之后把第一部分插入元素之后的部分向后移动。说着一大段,有些麻烦,下面通过一个例子讲解一下。

    举例: 3,4,1,5,2,6

    要求:使用插入排序算法进行排序(从小到大)

    实现过程:

    第一步:假设排好序的部分就是3,未排序部分为4,1,5,  2,  6

    第二步:遍历第二步分数据和第一部分数据(由于现在只有一个,直接比较了),发现4>3,继续下一个,发现3>1,那1应该在3的前面,把1插入到3的位置,之后元素3和4向后移动,注意:不要动5,2,6的位置

    第三步:经过第二步处理之后,排好序的部分为1,3,4 未排序的部分为5, 2,6,重复第二步

    总结:简单来说,就是把未排序的数据元素寻找在排好序的数据元素中的位置,然后插入进入,之后排好序的数据元素向后移动(注意:这里是从插入的位置向后移动,并不是全部排好序的部分)

    改进版本

      在上面的过程中,排好序的数组也需要一个一个遍历,最终找到元素需要插入的位置,这样时间复杂度太高,可以使用二分法查找,因为这一部分数组本身是有序的,使用二分法查找速度快很多。

    举例:1,5,6,8,10,9

    假设标绿的部分是已经排好序的,如果按照上面遍历的方法,需要查5次才知道9应该插入8和10之间,如果使用二分法查找,如下:

    第一步:计算中间值 (0 + 4)/ 2 = 2,发现 数组中下标为2的位置元素为 6 ,而 6 < 9,继续

    第二步:计算中间值 (2 + 4)/ 2 = 3,发现 数组中下标为3的位置元素为8, 而 8 < 9,继续

    第三步:计算中间值 (3 + 4)/ 2 = 3.5,把3.5取整为4,之后发现下标为4的元素为10, 而 10 > 9,ok,发现9应该插入10的位置,而10应该向后移动

    整个过程只需要查找3次,所以快非常多。

    其实,遍历的时间复杂度为O(n),而二分法查找时间复杂度为O(log(n))

    代码实现

    package sort;
    
    /**
     * @author: steve
     * @date: 2020/7/6 16:44
     * @description: 插入排序
     */
    public class InsertSort {
    
        public static int array[] = {72, 6, 57, 88, 60, 42, 83, 73, 48, 8, 1};
    
        /***
         *@Description 插入排序
         *@Param []
         *@Return void
         *@Author steve
         */
        public static void insertSort() {
            //排好序的位置
            int flag = 1;
            int temp = 0;
            //外层循环控制未排序的部分
            for (int j = 1; j < array.length; j++) {
                //内层循环处理排过序的部分
                for (int i = 0; i < flag; i++) {
                    if (array[i] > array[j]) {
                        temp = array[j];
                        System.arraycopy(array, i, array, i + 1, j - i);
                        array[i] = temp;
                        flag = j + 1;
                    }
                }
            }
        }
    
        /***
         *@Description 二分插入排序
         *@Param []
         *@Return void
         *@Author steve
         */
        public static void bisectionInsertSort() {
            int flag = 0;
            int temp;
            for (int i = flag + 1; i < array.length; i++) {
                int result = bisectionSearch(flag, array[i]);
                temp = array[i];
                System.arraycopy(array, result, array, result + 1, i - result);
                array[result] = temp;
                flag = flag + 1;
    
            }
        }
    
        /***
         *@Description 二分查找
         *@Param [flag:排好序的位置, num:待排序数]
         *@Return int
         *@Author steve
         */
        public static int bisectionSearch(int flag, int num) {
    
            int start = 0;
            int end = flag;
            int mid;
            //通过while循环,最后一定可以end-start<=1,也就是说要插入的元素一定在start左边,或者等于start,或者在start和end之间
            while (end >= start) {
                //由于这里mid的计算方式,导致要插入的元素不可能存在end-start=1,且end=要插入的元素的情况
                mid = (start + end) / 2;
                if (array[mid] > num) {
                    end = mid - 1;
                } else if (array[mid] <= num) {
                    start = mid + 1;
                }
            }
            return start;
        }
    
        public static void main(String[] args) {
    //        insertSort();
            bisectionInsertSort();
            for (int i = 0; i < array.length; i++) {
                System.out.println(array[i]);
            }
        }
    }

    上面的写法可能有的胖友对arraycopy比较好奇,大家可以自己写个demo试一下这个方法有什么用,我也是参考java8中ArrayList的sort方法写的,他就是用这个函数搞的。至于这个函数的性能和普通的遍历的性能对比,我也不太清楚,不过这个方法是一个native方法,性能应该还可以。

    总结

      写这种算法,思路一定要清晰,通过实验是不管用的,思路清晰了,很快就可以写出来,不然写的一定很复杂。

      

  • 相关阅读:
    四种方案解决ScrollView嵌套ListView问题
    [Android Bug] ListView中Header, Footer无法隐藏(gone)的问题
    Mysql介绍,与将脚本导入新数据库
    000 SpringBoot属性配置
    navicat的安装
    gradle
    004 Numpy
    003 Scipy库简介
    Mysql安装(绿色版安装)
    010 secondary namenode(同步元数据和日志)
  • 原文地址:https://www.cnblogs.com/gunduzi/p/13256187.html
Copyright © 2011-2022 走看看