插入排序执行流程:
- 将序列分为2个部分,头部是已经排序好的,尾部是待排序的
- 从头扫描每一个元素,将它插入到头部的合适位置,使头部数据依然有序
实现一(比较交换)
代码实现:
/**
* 插入排序
*
* @author zhangj
* @date 2020/9/23
*/
public class InsertSort {
private int[] elements;
public InsertSort(int[] elements) {
this.elements = elements;
}
public void sort() {
for (int begin = 1; begin < elements.length; begin++) {
int curr = begin;
while (curr > 0 && elements[curr - 1] > elements[curr]) {
//交换
int tmp = elements[curr - 1];
elements[curr - 1] = elements[curr];
elements[curr] = tmp;
curr--;
}
}
}
}
平均时间复杂度O(n2),空间复杂度O(1)
实现二(比较挪动)
实现一的实现中,如果后面的数小于前面的数,我们就交换,要交换就要执行固定的三行代码,其实我们可以不交换,实现思路如下:
- 先将待插入的元素备份
- 前面数据大于待插入元素时,前面元素往后挪一位
- 将待插入元素放到最终的位置
代码实现:
public static void sort(int[] array) {
for (int i = 1; i < array.length; i++) {
//记录待插入的值
int current = array[i];
int curr = i;
while (curr > 0 && array[curr - 1] > current) {
//往后挪一位
array[curr] = array[curr - 1];
curr--;
}
//插入合适的位置
array[curr] = current;
}
}
实现三(二分搜索)
每次拿到待插入元素去有序数列中使用二分查找,找到合适的插入位置,再把待插入元素插入。
代码实现:
public class InsertSort {
private int[] array;
public InsertSort(int[] array) {
this.array = array;
}
/**
* 排序
*/
public void sort() {
for (int i = 1; i < array.length; i++) {
insert(i, search(i));
}
}
/**
* 二分搜索查找index位置处元素要插入的位置
*/
private int search(int index) {
int begin = 0;
int end = index;
while (begin < end) {
int mid = (begin + end) >> 1;
if (array[index] < array[mid]) {
end = mid;
} else {
begin = mid + 1;
}
}
return begin;
}
/**
* 把source处的元素插入到dest位置
*/
public void insert(int source, int dest) {
int value = array[source];
for (int i = source; i > dest; i--) {
array[i] = array[i - 1];
}
array[dest] = value;
}
}
总结:
上述三种实现方法的平均时间复杂度都是O(n2),只是不同的实现比较次数不同而已。