直接插入 基本思想
把n个待排序的元素看成为一个有序表和一个无序表。开始时有序表只包含第1个元素,无序表是后n-1个元素,排序过程中每次从无序表中取出第一个元素,从后往前遍历有序表,将它插入到适当位置(有逐个平移和逐个交换两种插入方法),使之成为新的有序表,重复n-1次可完成排序过程。
算法性能分析:
1、时间复杂度
-
最坏情况下:待排序列为逆序。
- 总的比较次数为外层循环(趟数),为。
-
总的移动次数为内层循环,为。
-
最好情况下:待排序列逆序,内层循环的判断条件始终不成立,故内层循环始终不执行。双层循环就变成了单层循环,循环内的操作皆为常量级。
-
平均情况下:比较次数和移动次数皆均为,故时间复杂度为
2、空间复杂度
无论是用哨兵还是用temp,都是常数个,故为
算法特点
-
稳定性:因为每次插入元素时都是从后往前先比较再移动,不会出现相同大小元素相对位置发生改变的情况,故是稳定的。
-
适用性:适用于顺序存储和链式存储,用链式时可从前往后查找指定元素的位置。(大部分排序算法都仅适用于顺序存储)
-
插入类排序算法的共同特点:一趟排序后不能保证一个关键字到达其最终位置
-
更适用于初始序列基本正序的情况,且n比较小
代码实现
/*
每次从前往后从无序表里拿出第一个元素x,在有序表里从后往前搜寻第一个比x大的元素y,把x放到y前面的位置,y及y以后的元素依次往后移动一个单位。然后从无序表中拿出下一个元素继续到有序表中搜寻, 循环往复.......
*/
static void insertSort1() {
int i,j,temp;
for(i=1;i<len;i++) {
temp = arr[i];
for(j=i-1;j>=0 && temp<arr[j];j--) {
arr[j+1]=arr[j];
}
arr[j+1]=temp;
}
}
单链表的直接插入排序
void insertSort()
{
int i, j, temp; // 也可以用数组第一位充当哨兵
for (i = 0; i < arr.length; i++)
{
temp = arr[i];
for (j = i-1; j >= 0 && temp < arr[j]; j--)
arr[j+1] = arr[j];
arr[j+1] = temp;
}
}
折半插入 基本思想
直接插入排序采用顺序存储结构法在有序表中查找插入位置,既然是有序表,则这个“查找”操作可以用折半查找来实现。
直接插入是将无序元素依次插入有序表,需从后往前依次比较来查找插入位置,并且是边比较边移动,效率较低。而对于在有序表中查找某位置,折半查找效率更高,可以固定好插入位置后同意移动后续元素,减少了比较元素的次数(因为是折半比较)
算法性能分析:
-
时间复杂度
-
折半插入仅减少了比较元素的次数,约为。比较次数与初始序列的排列状态无关,仅取决于表中的元素个数n,无论初始序列排列情况如何,在插入第i个元素时,都需要经过次比较才能确定插入位置。所以当初始序列为正序或接近正序时,直接插入要比折半插入比较次数少。
-
折半插入排序中元素的移动次数相较于直接插入并未改变,只是是一次性大量移动的,移动次数依赖于序列的初始排列。
因此,时间复杂度最好的情况下为,最差情况下为,平均情况下为。
-
-
空间复杂度 等同于直接插入排序,为,只需要一个记录的辅助空间r[0]或temp。
算法特点
-
稳定性:是稳定的排序。
-
适用性:因为要进行折半查找,所以只能用顺序存储结构,不能用链式
-
适合初始计量无序,n较大时的情况
代码实现
import java.util.Arrays;
public class A {
static int[] arr = {1, 5, 3, 2, -7, 8, 0, 9, 4, 6};
static int len = arr.length;
static void BinaryInsertSort() {
int i, j, temp, left, right;
for (i = 1; i < len; i++) {
temp = arr[i];
left = 0;
right = i - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] > temp)
right = mid - 1;
else
left = mid + 1;
}
for (j = i - 1; j >= right + 1; j--)
arr[j + 1] = arr[j];
arr[right + 1] = temp;
}
}
public static void main(String[] args) {
BinaryInsertSort();
System.out.println(Arrays.toString(arr));
}
}
单链表的折半插入排序(带头结点)
void Sort(LinkList &L)
{
LinkList p = L->next, pre;
LinkList r = p->next;
p->next = NULL;
p = r;
while (p != NULL)
{
r = p->next;
pre = L;
while (pre->next != NULL && pre->next->data < p->data)
pre = pre->next;
p->next = pre->next;
pre->next = p;
p = r;
}
}