插入排序算法

来源:互联网 发布:nginx rewrite by lua 编辑:程序博客网 时间:2024/06/08 18:12
本文引用《算法导论》一书中的核心思想,作为学习笔记,不作权威性考量。
排序就是将一组无序数据排列成一组指定规则有序的数据,比如有两个数组:
A[a1,a2,...,an]为一组无序数组,作为程序输入。
B[a1',a2',...,an']为一组有序数组,满足a1'<a2'<...,作为程序输出。
这里讨论的是9大排序算法中的插入排序算法,插入排序事实上就是一边插入一边排序,算法刚开始时先从无序数组A中取出一个数,此时将无序数组A
化分成两部分,前面取出的第一个数作为第一部分(A[0...j-1]),后面作为第二部分(A[j...lenght-1]),
这里的规则就是第一部分的数据一直保持有序状态,然后不断从A[j...lenght-1]取出数据
放入A[0...j-1],A[0...j-1]的长度会不断增大,A[j...lenght-1]的长度会不断减小,直到A[j...lenght-1]这个区间无数据,
这里的核心就是第一次取出第一个数,肯定就是有序的(不需要比较),然后从第二次开始取数则需要和A[0...j-1]区间中
的数据进行比较,将其放入指定位置,所以每次从A[j...lenght-1]区间取一个数然后排序插入A[0...j-1]之后就能保证A[0...j-1]区间的数据肯定都是有序的。
比如这里有一个真实的数组A=[5,3,4,6,1,3],将其排序,过程如下图:



黑色背景框前的数据就是已经排好序的,之后的就是A[j...lenght-1]区间等待排序的数据,黑框本身数据就是即将取出放入A[0...j-1]区间的数据。
《算法导论》一书中举了一个非常典型的例子:抓扑克牌。抓扑克牌的时候,第一次抓的牌就直接拿在手上,然后第二次抓的牌就会和
我们第一次抓的牌作比较进行排序,以此往下。我们手里的牌就可以看作是数组中第一部分已经排好序的数据,而放在桌上未抓的牌则为
第二部分未排序的数据。


在这里我们将数组中第一部分已经排好序的数据表示为一个循环不变式,循环不变式用来帮助我们理解算法的正确性,在这里,要证明
循环不变式的三大性质:
初始化:循环的第一次迭代之前,它为真。
保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。
终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。


理论说的比较专业不够通俗,这里来通俗地理解一下,首先是初始化,就是说我们第一次取出一个数将其放入A[0...j-1],
此时A[0...j-1]区间是有序的,这是恒成立的,因为只有一个数肯定是有序的。
其次是保持,这里说的就是上面说的每次取的数插入到A[0...j-1]时,都保持A[0...j-1]区间的数据是有序的。
最后是终止:这个比较好理解,这里说的循环不变式为我们提供的性质就是A[0...j-1]区间的长度就等于原A数组的长度,
并且有序,A[j...lenght-1]区间的长度为0。


该算法的伪代码如下:




用Java代码实现如下:




该算法所花费的时间大约为cn2  ,c是一个不依赖于n的一个常量,从数学的角度上可以理解为
该算法的花费时间大致和n成正比,从此式子分析来看,当所排序数组中的数据非常少时,该算法效率还是比较高的,但当数量级非常大的时候
它的运行效率则会骤降。
0 0
原创粉丝点击