经典排序之直接插入排序详解
【1】直接插入排序排序算法介绍
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。
思想:每一趟将一个待排序的记录,按其关键字的大小插入到已经排好序的一组记录的适当位置上,直到所有待排序记录全部插入为止。
适用情况:小规模数据 或 者基本有序的数据
- 【2】直接插入排序性能分析:
1、空间效率:O(1)
仅使用了常数个辅助单元,因而空间复杂度为O(1)
2、时间效率:O(n)~O(n方)
在排序过程中,要进行n-1趟。每趟操作要与前面的元素的比较,从而它移不移动移动几次。
最好情况为直接n-1趟不用移动,那么就是O(n)
最坏情况,这n-1趟都要移动,每趟都要移动到第一个,也就是倒序的情况,那么时间复杂度
即 1+2+3+…+n-1 ----》最终时间复杂度即为O(n方)
3、稳定性:稳定
由于每次插入元素时总是从后向前比较在移动,因此在写代码的时候可以将插入元素放到与前面有自己相等
元素的下一个,这样就保证了插入的稳定性。因此直接插入排序是稳定的。
public class InsertSort {
/*
* 算法大致思想:
* 即从数组的第二个往后遍历,假设为升序排列,那么第二个与前一个相比
* 如果第二个比前一个小那么第二个就要往前寻找它要插入的位置,即寻找第二个大于等于哪一个,就往那个元素的下一个插入
* 如果第二个比前一个大,那么就继续往后遍历寻找自己比前一个小的。
* 因为这里每次都是将一个元素往前插入,因此遍历到某个元素时,它的前面都是有序的。
* */
public static void InsertSort(int a[], int length) {
int temp = 0;//用于保存往前要插入节点的值
int j = 0; //用来记录要插入元素的位置
/*
* 从数组第二个开始比较
* */
for (int i = 1; i < length; i++) {
//升序排列,若发现遍历的这个比前一个小,那么遍历的这个就需要往前插入
if (a[i] < a[i - 1]) {
temp = a[i];//用temp来保存要被插入的结点
/*
* 从遍历元素的前一个开始往回遍历,一开始j记录的就是前一个元素
* 然后开始寻找要插入的位置,没往前找一次,那个位置的元素就往后移动。直至找打为止。
* 两种情况寻找插入位置的循环结束:
* 1、当temp找到比它小的或者相等的元素时,就代表要插入的地方找到了,就跳出循环
* 此时j表示的是那个比它小的元素下标,或者和它相等的元素,下标
* 而j+1就代表它的下一个位置,也即代表要插入的位置,同时这个也保证了插入的稳定性。
* 2、当遍历到j=0时,依然没有找到,说明目前temp是数组前面最小的元素了,那么得temp放到数组的第一个位置
* 那么下一次j=-1跳出循环,然后j+1就代表数组的一个位置,将temp赋给数组j+1那个位置
*
* 【注1】这里是如何保持稳定性的?
* 这是在寻找要插入元素位置时,如果遍历到temp和往前遍历的那个元素相等,那么也就停止循环
* 此时j指向的是和temp相等的,j+1代表它的下一个,此时temp放到j+1的那个位置上去
* 【注2】临界情况,数组为空或者数组为1一个元素,怎么实现排序?
* 如果数组为空或者数组为1个元素,那么在第一个for循环里就已经跳出了循环
* */
/* 【注意】在写代码时:
* 下面for循环在写结束条件时,这里有个&&运算。
* 这里注意必须将j >= 0放在前面,电脑会先执行&&的前面的内容
* 如果j >= 0放在&&后面,当j=-1时电脑还会判断temp < a[j],但a[-1]不存在
* 因此程序回显示ArrayIndexOutOfBoundsException-数组下界异常
* */
for (j = i - 1; j >= 0 && temp < a[j]; j--) {
a[j + 1] = a[j];//当前遍历的这个元素往后移动
}
a[j + 1] = temp; //j+1代表要插入元素的位置
}
}
}
}
运行截图: