一 前言
如果对本系列产生什么疑问的话, 建议先下前言, 里面有我的联系方式, 教材的下载地址, 特殊词语的规定之类的........ 链接地址: https://blog.csdn.net/qq_41057280/article/details/89209081 ; 最后, 以下说法仅为个人理解, 如有错误, 欢迎教正
二 介绍
插入排序, 全名 直接插入排序算法(Insertion sort), <<算法导论>>原文介绍如下:
我翻译一下这段话, 插入算法, 就是一个能在一个有序数列中插入一个数,保证插入后此数列仍然有序的排序算法. 适用于数据量级较小的情况.
是不是感觉不太对, 毕竟他的原文和我的翻译完全不一致. 原文是给大家举了个例子, 一个拿牌的案例,这个案例生动形象地介绍了插入排序的原理,简单系统地说明了插入排序基本实现步骤, 能帮助大家快速理解和掌握该算法. 但是, 如果有天要你回答插入算法是什么, 你总不能跟他说是怎么怎么拿牌的吧~~
所以, 在此我就直接忽略原文概括一下.
三 伪代码
这是<<算法导论>> 提供的插入算法的伪代码, 由于是第一个伪代码, 所以就详细谈谈该怎么理解这段伪代码
- 第一行, for循环, 索引 "j" 从2开始遍历数组A, 这里的"2"是指第二个元素
- 第二行, 获取当前索引 "j" 得到的数组值存与变量key
- 第三行, 注释, 该行说明不参与运算, 说明数组A的索引是1开始, 而不是0
- 第四行, 得到当前索引的上一个元素索引 "i"
- 第五、六、七行, while倒序循环, 把比key大的已排序的数据后移一位
- 第八行, 将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