排序算法之插入排序

1)基本思想:

对于大小为N的数组A,插入排序的基本思想是将位置为P的元素插入前面已排好序的从0到P-1的正确位置中,这样一来,从0到P的元素都是排好序的,接着对后面的元素做插入排序,所以总共需要N-1趟插入排序。下面的示例中初始数组为34 8 64 51 32 21,分别对P=1, 2...5位置的元素做插入排序,每一次排序结束后从0到P位置的元素都处于已排好序状态。

初始数组 34 8 64 51 32 21 描述
P = 1 8 34 64 51 32 21 8需要移动
P = 2 8 34 64 51 32 21 64不需要移动
P = 3 8 34 51 64 32 21 51需要移动
P = 4 8 32 34 51 64 21 32需要移动
P = 5 6 21 32 34 51 64 21需要移动

2)算法描述:

算法的思想是对P位置的元素排序时,前面的0到P-1位置的元素已排好序,此时从位置P-1的元素开始与A[P]比较,如果A[P-1]>A[P],那么将元素A[P-1]向后移动一个位置,接着比较A[P-2]与A[P],直到找到元素A[P]的正确位置,将元素放入该位置,即完成一次插入排序。从元素A[1]到A[N-1]共需要N-1次插入排序。代码如下:

 1 void InsertionSort(ElementType A[], int n)
 2 {
 3     ElementType temp;
 4     for(int P = 1; P < N; P++)
 5     {
 6         int k = P;
 7         temp = A[P];
 8         for(; k > 0 && A[k-1] > temp; k--)
 9         {    
10             A[k] = A[k-1];
11         }
12         A[k] = temp;
13     }
14 }

3)复杂度分析:
最坏情况下,初始数组是反序,如64 51 34 32 21 6,那么对位置为P的元素进行一次插入排序需要做P+1次赋值操作,由于需要N-1次插入,那么时间代价为:

T = 2 + 3 + ... + N-1 = O(N^2)

最好情况下,初始数组是已排好序的,那么for循环的测试条件会在最开始的时候就不成立,也就不会执行赋值语句,这样的情况下,只需要N-1次循环操作,循环内部只需要一次测试动作,所以时间复杂度为O(N)。

平均情况下的时间复杂度下界为,证明中引入了逆序的概念:

如果数组A中,对于i < j, A[i] > A[j],那么(A[i],A[j])就构成了一个逆序,因此对于初始数组34 8 64 51 32 21,逆序有:

(34,8),(34,32),(34,21),(64,51),(64,32),(64,21),(51,32),(51,21),(32,21)。

逆序的个数和交换的次数是一致的,这是很好理解的,比如(34,21)是一个逆序,那么这两个元素之间早晚都会有一次比较并导致一次移动。对于一个随机的互异的数组,任意两个数的无序组合为N(N-1)/2,所有的组合要么在原数组中是逆序,要么是在原数组的反序中是逆序,所以逆序的平均数目为N(N-1)/4,那么对应的插入排序平均移动次数为N(N-1)/4 = 。 
  
以上整理于数据结构与算法分析(C语言描述)第二版 第七章 插入排序
  
 

 

 

posted on 2013-05-15 20:00  Sophia-呵呵小猪  阅读(128)  评论(0编辑  收藏  举报