插入排序
插入排序算法是基于某序列已经有序排列的情况下,通过一次插入一个元素的方式按照原有排序方式增加元素。这种比较是从该有序序列的最末端开始执行,即要插入序列中的元素最先和有序序列中最大的元素比较,若其大于该最大元素,则可直接插入最大元素的后面即可,否则再向前一位比较查找直至找到应该插入的位置为止。插入排序分直接插入排序、折半插入排序和希尔排序3类。
插入排序图解
原理及思路
每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。
- 1、从第一个元素开始,该元素可以认为已经被排序
- 2、取出下一个元素,在已经排序的元素序列中从后向前扫描
- 3、如果该元素(已排序)大于新元素,将该元素移到下一位置
- 4、重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 5、将新元素插入到下一位置中
- 6、重复步骤2~5
排序的效率
- 时间复杂度:O(n^2);当待排序列有序时,不需要插入数据进行数据移动,此时时间复杂度为:O(n);
- 空间复杂度:O(1) -> 未新开辟内存
算法稳定性
插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
插入排序的优化
如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序的一个变种,称为二分查找排序。
插入排序的特点
越有序越快
对于一般情况下,冒泡,选择,插入效率相同,进行排序时可以随便选择。如果序列基本有序,则选择插入排序的效率更高。当序列完全逆序时(5,4,3,2,1),此时插入排序退化为冒泡排序,其两者步骤相似。
代码实现
public static <T extends Comparable<T>> void insertSort(T[] arr){
if(arr == null || arr.length == 0 || arr.length == 1){
return;
}
//从一下标遍历整个数组,一开始将0下标元素当作有序序列,1下标之后当作待排序列
for(int i = 1;i < arr.length;i++){
//将当前需要进行判断插入的数据进行临时存储
T value = arr[i];
//定义有序序列下标
int j = i - 1;
//遍历有序序列
for(;j >= 0;j--){
//判断如果需要插入的数据比已排列数据小,将已排列数据依次进行后移数据移动
if(value.compareTo(arr[j]) < 0){
arr[j+1] = arr[j];
}else {
//因为需要插入的数据前面的数据已经有序,
// 因此只要旁边的数据不满足要求,直接退出循环,不需要再进行判断
break;
}
}
//将此时数据插入已排列数据中
arr[j+1] = value;
}
}