文章链接:http://blog.csdn.net/jewangs/article/details/52424313
一、插入排序
插入排序属于原址排序,算法在数组A中重排元素,算法思想与玩扑克牌时依次将抓到的牌放到手中合适的位置一致,当输入完成时,手中的牌即已完成排序。
插入排序(A)
for j = 2..A.length setp = 1 //A 下标从 1 开始计数
key = A[j]
i = j - 1
while i > 0 && A[i] > key
A[i + 1] = A[i]
--i
A[i + 1] = key //当 i == 0 || A[ i ] <= key 时,插入寻找退出,此时的 key 应该放到 A[ i ] 的下一个单元 A[ i ]+ 1
算法的时间复杂度为O(n^2)
二、分治模式
分治思想:将原问题分解为几个规模较小的但类似于原问题的子问题,递归的求解这些子问题,然后合并这些子问题的解来建立原问题的解。
步骤:
分解:分解原问题为若干个子问题,这些子问题是原问题的规模较小的的实例
解决:递归地求解这些子问题,子问题足够小,可直接求解
合并:合并子问题的解为原问题的解
算法的核心在于 合并 操作,对于数组 A ,p,q,r 为数组下标,满足 p <= q < r,假定子数组 A[ p..q ] 和 A[ q + 1,r] 都已排好序,下面的例程将合并这两个子数组形成单一
的已排好序的子数组A[ p..r ]:
合并(A,p,q,r)
n1 = q - p + 1
n2 = r - q
new array L[ n1 + 1 ] and R[ n2 + 1 ]
for i = 1..n1 step = 1
L[ i ] = A[ p + i - 1] //L数组为 [p,q]
for j = 1..n2 step = 1
R[ j ] = A[ q + j ]
L[ n1 + 1 ] = 哨兵
R[ n2 + 1 ] = 哨兵
i = j = 1
for k = p .. r
if L[ i ] <= R[ j ]
A[ k ] = L[ i ]
++i
else
A[ k ] = L[ j ]
++j
有了这个合并例程,根据分治思想,归并排序算法水到渠成:
归并排序(A,p,r)
if p < r
q = (p + r)/2 //向下取整
归并排序(A,p,q)
归并排序(A,q + 1,r)
合并(A,p,q,r)
算法的时间复杂度为O(nlgn)
三、递归式的求解
归并排序算法复杂度的计算符合递归式:
T(n) = aT(n/b) + f(n)
其中,a >= 1,b > 1是常数,f(n) 是渐进正函数,关于这个递归式的求解有很多种方法,最常用的当属 主方法,主方法依赖于主定理:
定理:令 a >= 1,b > 1 是常数,f(n) 是一个函数,T(n)是定义在非负整数上的递归式:T(n) = aT(n/b) + f(n)
那么,T(n) 有如下渐进界:
1.若存在某常数 c > 0 有 f(n) = O(n^(logb(a-c))),则T(n) =O(n^(logb(a)))
2.若 f(n) = O(n^(logb(a))),则 T(n) = O(n^(logb(a))lgn)
3.若对于某常数 c > 0 有 f(n) = Ω(n^(logb(a + c))),且对某个常数 c < 1 和所有足够大的 n 有 af(n/b) <= cf(n),则T(n)=O(f(n))