3、由java实现的简单算法——插入排序

一  前言

如果对本系列产生什么疑问的话,  建议先下前言,  里面有我的联系方式,  教材的下载地址,   特殊词语的规定之类的........   链接地址: https://blog.csdn.net/qq_41057280/article/details/89209081 ;   最后, 以下说法仅为个人理解, 如有错误, 欢迎教正

二  介绍

插入排序, 全名 直接插入排序算法(Insertion sort),  <<算法导论>>原文介绍如下: 

我翻译一下这段话,  插入算法, 就是一个能在一个有序数列中插入一个数,保证插入后此数列仍然有序的排序算法.  适用于数据量级较小的情况.  

是不是感觉不太对, 毕竟他的原文和我的翻译完全不一致.   原文是给大家举了个例子, 一个拿牌的案例,这个案例生动形象地介绍了插入排序的原理,简单系统地说明了插入排序基本实现步骤, 能帮助大家快速理解和掌握该算法.   但是,  如果有天要你回答插入算法是什么,  你总不能跟他说是怎么怎么拿牌的吧~~

所以, 在此我就直接忽略原文概括一下. 

三  伪代码

 

这是<<算法导论>> 提供的插入算法的伪代码,  由于是第一个伪代码, 所以就详细谈谈该怎么理解这段伪代码

  1.   第一行,  for循环, 索引 "j" 从2开始遍历数组A,   这里的"2"是指第二个元素
  2.   第二行,  获取当前索引 "j" 得到的数组值存与变量key
  3.   第三行,  注释,  该行说明不参与运算,  说明数组A的索引是1开始, 而不是0
  4.   第四行,  得到当前索引的上一个元素索引  "i"  
  5.   第五、六、七行,  while倒序循环,  把比key大的已排序的数据后移一位
  6.   第八行,  将key放入空出来的位置

以上就是插入算法的核心实现思路,  从第二个元素开始插入,  倒序循环并按照排序规则后移元素,  保证位置能空出一位, 直到退出循环,  将元素插入空出来的位置

不清楚怎么看伪代码的朋友,  可以看看我写的伪代码规则 https://blog.csdn.net/qq_41057280/article/details/90176737 

四  java实现

好了,  重头戏来了.  首先,  先来个常规的照着伪代码写.

/**
* 插入排序 ,  这里把变量名尽量与伪代码统一,  方便大家查看    
*/
public void insertSort(int[] A) {
    int n = A.length;
    for (int j = 1; j < n; j++) {
        int key = A[j];
        int i = j - 1;
        while (i >= 0 && A[i] > key) {
            A[i + 1] = A[i]; // 比key大的已排序数据后移一位
            i--;
        }
        A[i + 1] = key; // 空出来的位置,把key放进去
    }
}

就把伪代码换成java代码即可,  唯一要注意的就是数组索引,  在伪代码里面数组下标是从1开始,  而java是从0开始.  所以 while的判断和  j 的初始值,  都要做点改动

五  基于插入算法实现的数组

按照插入算法的定义,  该算法存在保证数组在插入数据后依旧有序的特性,  如果把该特性运用在数组中, 不就可以实现一个自动排序的数组

代码如下,   重点在insert方法,   上面插入算法是倒序遍历,  这次用正序遍历,  其余逻辑一致.  之所以换种写法, 纯粹就是闲起来了(滑稽)

class InsertArray{
    private int length;
    private Integer[] arr;
    
    public InsertArray() {
        arr = new Integer[50];
    }
	
    public InsertArray(int length) {
        arr = new Integer[length];
        this.length = length;
    }
	
    /**
     * 添加数据
     */
    public void insert(int value) {
        int i;
        // 从前往后遍历,  找到value的位置
        for(i = 0; i < length; i++) {
            if(arr[i] > value) {
                break;
            }
        }
        // 将所有比value大的元素,后移一位
        for(int j = length; j > i; j--) {
            arr[j] = arr[j - 1];
        }
        arr[i] = value;
        length++;
    }
	
    /**
    * 重写toStirng,用于数据展示
    * @return 
    */
    public String toString() {
        return Arrays.stream(arr)
                .filter(e -> e != null)
                .map(e -> e.toString())
                .collect(Collectors.joining(","));
    }
}

然后测试一下

嗯,  看来是成功了

六   二分插入排序

最后, 我再引申一个插入排序算法的变种,  二分插入排序 .  与直接插入的区别,  就是在搜索数据插入位置, 采用二分法进行搜索,  这样可以有效的减少比较次数.   仅此而已,  可惜时间复杂度还是O(n²).   代码复杂,  提升的是无关紧要的效率.  数据量级一大,  该慢还是慢.  评价.  鸡肋

/**
* 二分法插入排序
*/
public static void binaryInsertSort(int[] arr) {
    int n = arr.length;
    
    for (int i = 1; i < n; i++) {
        int key = arr[i];
	
        int right = i - 1;
        int left = 0;
			
        while (left <= right) {
            int mid = (left + right) / 2;
	
            if (key < arr[mid]) {
            	right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
			
        for (int j=i; j>left;j--) {
            arr[j] = arr[j - 1]; // 比key大的已排序数据后移一位
        }
        arr[left] = key; // 空出来的位置,把key放进去
    }
}

七   总结

插入排序, 是一个很简单的排序算法.  他在数据量级较小或者数据基本有序的时候推荐使用.   话是这么说,  其实没啥人使用(笑~~)。

如果有不懂时间复杂度怎么计算的朋友,可以看下这篇我写的这篇关于时间复杂度的简单介绍和基本运算,里面还有一些计算示例。欢迎纠错!!https://blog.csdn.net/qq_41057280/article/details/90266042

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值