插入排序
适用于少量元素的排序,思想和排序扑克牌一样:一张张地抽取,然后和手中已经排好序的最大的牌进行比较,大之则插入右边,小之则和它的前一张牌比较。
伪代码:
//[1,j-1]是手中牌,[j,A.length]是待插入的牌
for j = 2 to A.length //从待插入的第二张开始,A[1]表示第一张已经抽在手中的牌
key = A[j]
i = j - 1 //得到手中牌的数
while i > 0 and A[i] > key //从手中最大的牌开始比较
A[i+1] = A[i] //大于时,向当前位置的下一张移位
i = i-1 //取当前位置的前一位进行比较
A[i+1] = key //从前一位回到当前位置进行插入
时间复杂度为O(n^2)
随机访问机器RAM,没有并发操作,指令一条接一条地执行。
归并排序(分治法排序)
使用分治法实现,思想:将扑克牌分成2份已经排好序的堆,从上到下按从小到大放好,然后从2堆牌的顶层开始相互比较,拿出较小的那张,以此直到一方或双方没有牌了,就将剩下的直接合并。递归:将分成的2份继续分成2份,直到只剩下1张牌,然后和同等级的牌进行一对一地比较,取出较小的一张放在顶层。
伪代码:
合并(A,p,q,r):
//p开始位置,r结束位置,q分界点
n1 = q - p + 1
n2 = r - q
for i = 1 to n1
L[i] = A[p + i -1]
for j = 1 to n2
R[i] = A[q + j]
L[n1+1] = 标志
R[n2+2] = 标志
i = 1
j = 1
for k = p to r
if L[i]<=R[j]
A[k] = L[i]
i = i + 1
else
A[k] = R[j]
j = j + 1
递归(A,p,r):
if p < r
q = (p+r)/2(取下界)
递归(A,p,q)
递归(A,q+1,r)
合并(A,p,q,r)
时间复杂度为nlgn。
分治:将规模为T(n)的问题分解为a个规模为原问题规模1/b的子问题,设D(n)为分解所需时间,C(n)为合并所需时间,当规模大于1时,递归表达式如下。
T(n) = aT(n/b) + D(n) + C(n)
- 渐进符号
f(n) = O(g(n)) 类似于 a<=b
f(n) = Ω(g(n)) 类似于 a>=b
f(n) = θ(g(n)) 类似于 a=b
f(n) = o(g(n)) 类似于 a< b
f(n) = w(g(n)) 类似于 a>b
分治策略
3个步骤:
分解:将问题分解为一些规模更小但是本质一样的子问题
解决:如果子问题的规模足够小,则停止递归,直接求解
合并:将子问题的解组合成原问题的解
一般和递归一起使用:先列出递归式,然后根据递归式设计算法。
分治法求解具有最大和的子数组
问题:给出一个值为实数的数组,求解具有最大和的连续的子数组。比如股票投资求出最佳的买入时间和卖出时间。
思想:将数组递归地分成相同量的2份,分别求出左边数组的最大和,右边数组的最大和,然后求出跨中间点的数组最大和,然后将3个最大和进行比较,取最大的那个就是整个数组的最大和子数组。
伪代码:
跨中间点最大子数组(A,low,mid,high)
leftsum = 负无穷
sum = 0
for i = mid downto low //从中间向2边取值相加
sum = sum + A[i]
if sum > leftsum
leftsum = sum
maxleft = i //记录最大处的下界
rightsum = 负无穷
sum = 0
for j = mid + 1 to high
sum = sum + A[j]
if sum > rightsum
rightsum = sum
maxright = j //记录最大处的上界
return (maxleft,maxright,leftsum + rightsum) //(下界,上界,和)
递归(A,low,high)
if high == low
return (low,high,A[low])
else mid = (low + high)/2 //取下界
(leftlow,lefthigh,leftsum) = 递归(A,low,mid)
(rightlow,righthigh,rightsum) = 递归(A,mid+1,high)
(crosslow,crosshigh,crosssum) = 跨中间点最大子数组(A,low,mid,high)
if leftsum >= 其他2个
return (leftlow,lefthigh,leftsum)
elseif rightsum >= 其他2个
return (rightlow,righthigh,rightsum)
else return (crosslow,crosshigh,crosssum)