算法熟记-排序系列-插入排序

1. 简述

    假设待排序数组为 int array[], 数组长度为n。

    第1趟,认为array[0]-array[0]已经排序,把array[1]插入到合适的位置。
    第2趟,认为array[0]-array[1]已经排序,把array[2]插入到合适的位置。
    ···
    第n-1趟,认为array[0]-array[n-2]已经排序,把array[n-1]插入到合适的位置。

2. 复杂度

    最好的时间复杂度是O(n),对已经排序好的数组,只需要n-1次比较就可以了。平均时间复杂度和最坏时间复杂度都是O(n^2)。
    在每次趟中,寻找合适位置时,可以使用二分查找的方法,来减少比较次数。
    稳定性上,如果不使用二分查找,那么是稳定的排序,否则是不稳定的排序。

3. 代码

void insertion_sort(int array[], int n) {
  
int pos, left, right, mid, tmp;
  
for(int i=1; i<n; i++) {
    
if(array[i] >= array[i-1]) { // 不需要插入
      continue;
    }
    
else if(array[i] < array[0]) { // 插入到最前面
      pos = 0;
    }
    
else { // 使用二分查找,来确定插入位置
      left = 0; right = i-1;
      
while(right - left > 1) {
        mid 
= (left+right)/2;
        
if(array[i] < mid) right = mid;
        
else left = mid;
      }
      pos 
= right; 
    }
    
// 插入过程
    tmp = array[i];
    
for(int j=i; j>pos; j--)
      array[i] 
= array[i-1];
    array[pos] 
= tmp;
  }
}

    实际上,插入排序的元素赋值操作往往是比较耗时的,二分的方法只能减少一些比较的次数,并不能减少元素移动的次数,因此对于性能提升不是很多。下面给出一个比较“简化”的插入排序代码:    

void insertion_sort(int array[], int n) {
  
int temp,i,j;
  
for(i=1; i<n; i++) {
    temp 
= array[i];
    
for(j=i; j>0 && temp<array[j-1]; j--) { // 此时array[j]==temp
      array[j] = array[j-1];
    }   
    array[j] 
= temp; 
  }
}

上面代码举个例子来说明一下,比如对1 3 4 5 6 7 2,现在要把最后的2插入到前面有序的数组中了,首先,temp=2,然后就用temp与前面的这些数字逐个比较,如果temp更小,那么就把前面的数字后移一位,直到结束,在把temp放到空出的位置。对于例子就是在循环结束时,1 3 3 4 5 6 7 ,temp=2, j=1,然后array[1]=2,得到1 2 3 4 5 6 7

4. 参考资料

   维基百科-插入排序   http://en.wikipedia.org/wiki/Insertion_sort

posted @ 2011-06-07 16:24  xiaodongrush  阅读(288)  评论(0编辑  收藏  举报