插入排序思路:
对于长度为n的序列来说,在插入元素Ri(i=1,2,…,n-1)时,序列被划分为两个区间,分别是[R0,Ri-1]和[Ri,Rn-1],其中[R0,Ri-1]已经排好序,即Ri-1>=Ri-2>=…>=R0,而[Ri,Rn-1]为待排序列。将Ri分别与Ri-1,Ri-2,…,R0比较,当Ri<=Rx时,将Ri插入Rx之前(若Ri>=Ri-1,则Ri不需要移动位置)。此时有序序列的区间元素又增加一位。当从i=1进行上述排序操作知道i=n-1时,序列将变为有序。
以长度为6的序列 {6,3,5,4,1,2} 的插入排序过程做示范:
第一趟排序:[3 6] 5 4 1 2 (3插入6之前)
第二趟排序:[3 5 6] 4 1 2 (5插入6之前)
第三趟排序:[3 4 5 6] 1 2 (4插入5之前)
第四趟排序:[1 3 4 5 6] 2 (1插入3之前)
第五趟排序:[1 2 3 4 5 6] (2插入3之前)
(注:用中括号括起来的是有序区间,之后的元素序列为待排区间)
本文根据上述的插入排序思路给出C++与Java的代码实现,并且使用Java对插入排序算法和排序算法:选择排序中介绍的选择排序算法、以及排序算法:冒泡排序中介绍的两种冒泡排序算法进行性能比较。
C++代码:
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void insertionSort(int *arr, int length)
{
if (arr == NULL || length <= 0)return;
for (int i = 1; i < length ; ++i)
{
for (int j = i - 1;j >= 0; --j)
{
if (arr[j]>arr[j + 1])
{
swap(&arr[j + 1], &arr[j]);
}
else break;
}
}
}
Java代码:
private void insertSort(List<Integer> list) {
int length = list.size();
for (int i = 1; i < length; ++i) {
for (int j = i - 1; j >= 0; --j) {
if (list.get(j) > list.get(j + 1)) {
swap(list, j, j + 1);
} else
break;
}
}
}
//效率比insertSort()方法更高的一种插入排序实现
public void insertSort2(List<Integer> list){
int length = list.size();
for (int i = 1; i < length ; ++i) {
if(list.get(i-1)>list.get(i)){
//备份待排元素
int temp = list.get(i);
int k = i-1;
//逐位覆盖后一位
while(k >= 0 && list.get(k) > temp){
list.set(k+1, list.get(k));
--k;
}
//插入待排元素
list.set(k+1,temp);
}
}
}
使用完全相同的元素为整数的List对插入排序算法、选择排序算法以及两种冒泡排序算法进行性能测试结果如下:(使用的是上述的insertSort2方法而不是insertSort)
序列长度1000:
序列长度5000:
序列长度10000:
序列长度50000:
可以看到,插入排序在效率上慢于选择排序,但也比两种冒泡法快得多。