直接插入排序(Straight Insertion Sorting)的基本思想:在要排序的一组数中,假设前面(n-1) [n>=2] 个数已经是排好顺序的,现在要把第n个数插到前面的有序数中,使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
复杂度:时间复杂度 O(n2) ,空间复杂度O(1)
稳定性: 插入排序是稳定的,排序前后两个相等元素相对次序不变(能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。)
结构的复杂性及适用情况:是一种简单的排序方法,不仅适用于顺序存储结构(数组),而且适用于链接存储结构,不过在链接存储结构上进行直接插入排序时,不用移动元素的位置,而是修改相应的指针。
哨兵的作用
算法中引进的附加记录R[0]称监视哨或哨兵(Sentinel)。
哨兵有两个作用:
① 进人查找(插入位置)循环之前,它保存了R[i]的副本,使不致于因记录后移而丢失R[i]的内容;
② 它的主要作用是:在查找循环中"监视"下标变量j是否越界。一旦越界(即j=0),因为R[0].key和自己比较,循环判定条件不成立使得查找循环结束,从而避免了在该循环内 的每一次均要检测j是否越界(即省略了循环判定条件"j>=1")。
注意:
① 实际上,一切为简化边界条件而引入的附加结点(元素)均可称为哨兵。
【例】单链表中的头结点实际上是一个哨兵
② 引入哨兵后使得测试查找循环条件的时间大约减少了一半,所以对于记录数较大的文件节约的时间就相当可观。对于类似于排序这样使用频率非常高的算法,要尽可能 地减少其运行时间。所以不能把上述算法中的哨兵视为雕虫小技,而应该深刻理解并掌握这种技巧。
JAVA源代码(成功运行):
public class StraightInsertionSort {
public static void main(String[] args) {
int[] array = { 49, 38, 65, 97, 76, 13, 27 };
straightInsertionSort(array);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
public static void straightInsertionSort(int[] array) {
int sentinel, j;
for (int i = 0; i < array.length-1; i++) {
j = i;
sentinel = array[j+1];// 哨兵位
while (j >= 0 && sentinel < array[j]) {
array[j + 1] = array[j];// 将大于sentinel的值整体后移一个单位
j--;
}
array[j + 1] = sentinel;
}
}
}
自己理解:
/**
* 直接插入
*
*/
public class StraightInsertionSort {
public static void main(String[] args) {
int[] array = { 49, 38, 65, 97, 76, 13, 27 };
straightInsertionSort(array);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
public static void straightInsertionSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
int j = i;//i之前的顺序是正确
int sentryValue = array[j + 1];
while (j >= 0 && array[j] > sentryValue) {//当有小值的时候,前面排好序的向后移
array[j + 1] = array[j];
j--;
}
if(j!=i){//如果这轮没有换位,就不需要把哨兵位补上去
array[j + 1] = sentryValue;
}
}
}
}