排序算法 - 插入排序算法及速度测试

插入排序算法

插入排序,一般也被称为直接插入排序。它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动

插入排序的精髓在与将元素序列分成有序表无序表,有序表初始为第一个元素(只有一个元素当然有序),然后一个个判断无序表的第一个元素,将其插入有序表中,保证有序表一直有序,直到无序表为空结束
排序算法 - 插入排序算法及速度测试_第1张图片


Java实现插入排序算法的过程

先一步步实现插入排序的过程

第一轮:
设置第一个待插入元素insertValue=arr[1],插入位置的索引初始值为insertIndex=0(带插入元素的前一位)
while循环,查找当前待插入的元素是否小于insertIndex指向的元素,如果小于,就arr[insertIndex+1] = arr[insertIndex];把arr[0]赋值给arr[1],然后insertIndex-1,继续查找,直到到达数组边界或者待插入的元素大于insertIndex指向的元素

退出while循环,把insertValue赋值给arr[insertIndex-1]

后续第二轮,直到无序表为空

package com.company.sort;

import java.util.Arrays;

/**
 * @author zfk
 * 插入排序
 */
public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {101,34,119,1};
        insertSort(arr);
    }

    public static void insertSort(int[] arr){

        //第一轮

        //定义待插入的数
        int insertValue = arr[1];
        //插入位置的索引,待插入数的前一位
        int insertIndex = 1 - 1;

        //循环,给insertValue找插入的位置
        //1.保证给insertValue找插入的位置时不越界
        //2. insertValue < arr[insertIndex] 待插入的数还没有找到插入位置
        //3. 将arr[insertIndex]后移
        while (insertIndex >= 0 && insertValue < arr[insertIndex]){
            arr[insertIndex+1] = arr[insertIndex];
            insertIndex--;
        }
        //当退出while循环时,插入位置找到,位置为insertIndex+1
        arr[insertIndex+1] = insertValue;

        System.out.println("第一轮插入后:"+ Arrays.toString(arr));


        //第二轮

        //定义待插入的数
        insertValue = arr[2];
        //插入位置的索引,待插入数的前一位
        insertIndex = 2 - 1;

        //循环,给insertValue找插入的位置
        //1.保证给insertValue找插入的位置时不越界
        //2. insertValue < arr[insertIndex] 待插入的数还没有找到插入位置
        //3. 将arr[insertIndex]后移
        while (insertIndex >= 0 && insertValue < arr[insertIndex]){
            arr[insertIndex+1] = arr[insertIndex];
            insertIndex--;
        }
        //当退出while循环时,插入位置找到,位置为insertIndex+1
        arr[insertIndex+1] = insertValue;

        System.out.println("第二轮插入后:"+ Arrays.toString(arr));

        //第三轮

        //定义待插入的数
        insertValue = arr[3];
        //插入位置的索引,待插入数的前一位
        insertIndex = 3 - 1;

        //循环,给insertValue找插入的位置
        //1.保证给insertValue找插入的位置时不越界
        //2. insertValue < arr[insertIndex] 待插入的数还没有找到插入位置
        //3. 将arr[insertIndex]后移
        while (insertIndex >= 0 && insertValue < arr[insertIndex]){
            arr[insertIndex+1] = arr[insertIndex];
            insertIndex--;
        }
        //当退出while循环时,插入位置找到,位置为insertIndex+1
        arr[insertIndex+1] = insertValue;

        System.out.println("第三轮插入后:"+ Arrays.toString(arr));
    }
}

排序算法 - 插入排序算法及速度测试_第2张图片

很明显,这也是可以通过两个for循环嵌套简化的

注意,因为是循环处理无序表,所以外面的这个for循环应当从1开始

package com.company.sort;

import java.util.Arrays;

/**
 * @author zfk
 * 插入排序
 */
public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {101,34,119,1};
        insertSort(arr);
    }

    public static void insertSort(int[] arr){

        //仅循环无序表的大小,所以是从1开始
        for (int i = 1;i < arr.length;i++) {
            //定义待插入的数
            int insertValue = arr[i];
            //插入位置的索引,待插入数的前一位
            int insertIndex = i - 1;

            //循环,给insertValue找插入的位置
            //1.保证给insertValue找插入的位置时不越界
            //2. insertValue < arr[insertIndex] 待插入的数还没有找到插入位置
            //3. 将arr[insertIndex]后移
            while (insertIndex >= 0 && insertValue < arr[insertIndex]) {
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            //当退出while循环时,插入位置找到,位置为insertIndex+1
            arr[insertIndex + 1] = insertValue;

            System.out.println("第"+i+"轮插入后:" + Arrays.toString(arr));
        }

    }
}

排序算法 - 插入排序算法及速度测试_第3张图片


速度检测

很明显,插入排序算法是两个for循环嵌套,时间复杂度是O(n^2),那么同为平方阶的时间复杂度,冒泡排序、选择排序、插入排序哪个更快?
排序8000个0~80000内的数据

    public static void main(String[] args) {
        int[] arr = new int[8000];
        for(int i = 0 ;i <arr.length;i++){
            //随机生成80000内的整数
            arr[i] = (int) (Math.random()*80000);
        }
        Date dataBefore = new Date();

        insertSort(arr);

        Date dateAfter = new Date();

        System.out.println("消耗了:"+(dateAfter.getTime()-dataBefore.getTime())+"ms");

    }

排序算法 - 插入排序算法及速度测试_第4张图片

多次执行,大概速度在20ms左右

冒泡排序速度:

排序算法 - 插入排序算法及速度测试_第5张图片

选择排序速度:
排序算法 - 插入排序算法及速度测试_第6张图片

当设置为8万个数据:插入排序为910ms左右;选择排序为3400ms左右;冒泡排序为13000ms左右

总的来说:在数组为存储数据的情况下,插入排序 优于 选择排序 优于 冒泡排序

为什么会这样?

冒泡排序是都要遍历一遍,且很大可能需要交换多次,最耗时没得说;选择排序也是需要遍历数组,只是需要交换一次;插入排序是从有序表的最边上开始遍历,平均遍历是少于选择排序的

开销问题:

  1. 比较开销:选择排序的比较开销是固定的n(n-1)/2,而插入排序平均下来是
    n(n-1)/4.
  2. 交换开销选择排序最多只需要执行2*(n-1)次交换,而插入排序平均的交换开销也是n(n-1)/4.这就取决于单次比较和交换的开销之比。如果是一个量级的,则插入排序优于选择排序,如果交换开销远大于插入开销,则插入排序可能比选择排序慢

你可能感兴趣的:(数据结构和算法,算法,数据结构,java,排序算法)