排序算法之(直接)插入排序

package com.zzb.sort;

import java.util.Arrays;

/**
 * @Auther: Administrator
 * @Date: 2020/3/6 22:16
 * @Description: 插入排序
 * 插入排序(Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,
 * 开始时有序表中只包含一个元素,无序表中包含有n-1个元素,
 * 排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,
 * 将它插入到有序表中的适当位置,使之成为新的有序表
 */
public class InsertSort {
    public static void main(String[] args) {
        int[] array = {3, 9, -1, 10, 20};

        insertSort(array);
        System.out.println(Arrays.toString(array));
        /*[-1, 3, 9, 10, 20]*/
    }

    /**
     * 插入排序算法
     * 直接插入排序的基本思想是:每一次循环,从所有未排序的元素中取出一个元素跟前面已经排好序的元素相比较,
     * 如果待插入的元素比已排序的元素小,则交换,直到全部元素都比较过为止
     *
     * 具体步骤:
     * 一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下
     * ①从第一个元素开始,该元素可以认为已经被排序
     * ②取出下一个元素作为待插入元素,在已经排序的元素序列中从后向前扫描
     * ③如果待插入元素小于已排序元素,则将已排序元素向后移动一个位置
     * ④重复步骤3,直到找到待插入元素大于或者等于已排序元素的位置
     * ⑤将待插入元素插入到该位置
     * ⑥重复步骤②-⑤
     * @param array 待排序数组
     */
    private static void insertSort(int[] array) {
        // 待插入元素的存储空间
        int insertValue = 0;
        // 已排序元素的索引位置(待插入元素需要插入的位置)
        int insertIndex = 0;

        for(int i = 1; i < array.length; i++) {
            /*原始版:
            // 待插入元素
            insertValue = array[i];
            // 初始默认值为每次循环比较开始时,待插入元素左边的已排序元素的索引位置
            insertIndex = i - 1;
            // insertIndex >= 0 保证在给待插入元素insertVal找插入位置,数组下标不越界
            // insertVal < arr[insertIndex] 待插入元素还没有找到要插入的位置
            while(insertIndex >= 0 && insertValue < array[insertIndex]) {
                // 如果待插入元素小于已排序元素,则将已排序元素向后移动一个位置
                array[insertIndex + 1] = array[insertIndex];
                // 继续与已排序元素进行比较
                insertIndex--;
            }
            // 退出while循环,待插入元素已找到插入位置,为insertIndex + 1
            // insertIndex + 1 的原因:while循环中 insertIndex-- 造成
            // insertIndex + 1 != i 如果相等,则待插入元素的位置不变(即待插入元素比已排序元素大),不需要重新赋值
            if(insertIndex + 1 != i) {
                array[insertIndex + 1] = insertValue;
            }
            */

            // 改良版:
            // 只有当待插入元素比已排序元素小时,才需要循环比较已排序元素来确定待插入元素的位置
            if(array[i] < array[i-1]) {
                // 待插入元素
                insertValue = array[i];
                // 初始默认值为每次循环比较开始时,待插入元素左边的已排序元素的索引位置
                insertIndex = i - 1;
                // insertIndex >= 0 保证在给待插入元素insertVal找插入位置,数组下标不越界
                // insertVal < arr[insertIndex] 待插入元素还没有找到要插入的位置
                while(insertIndex >= 0 && insertValue < array[insertIndex]) {
                    // 如果待插入元素小于已排序元素,则将已排序元素向后移动一个位置
                    array[insertIndex + 1] = array[insertIndex];
                    // 继续与已排序元素进行比较
                    insertIndex--;
                }
                // 退出while循环,待插入元素已找到插入位置,为insertIndex + 1
                array[insertIndex + 1] = insertValue;
            }
        }
    }
}

  (直接)插入排序过程动态图:

 

  

  扩展:

  in-place操作,意思是所有的操作都是”就地“操作,不允许进行移动,或者称作 原位操作,即不允许使用临时变量

  比如,交换两个数的值

  // 设置初始值
  int x = 1,y = 2;

(1)最先想到的方法,就是设置中间变量

  // 设置中间变量
  int temp;
  temp = x;
  x = y;
  y = temp;

(2)然而要满足in-place的要求,就需要通过加减运算实现(但是可能会出现溢出)

  // 加减运算
  x = x + y;
  y = x - y;
  x = x - y;

(3)通过异或操作实现

  // 异或运算
  x = x ^ y;
  y = x ^ y;
  x = x ^ y;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值