1、插入排序:
A=[1,4,7,9,10,8,12]
# j 表示现在待插入的索引,len(A)=6,range(1,len(A))的取值为1,2,3,4,5,
# 计算复杂度时还是n次,因为最后的j加一之后才跳出循环的。
for j in range(1,len(A)):
# i表示左边第一个比较的元素索引
i=j-1
# 一定要注意保存当前待插入的值,因为插入过程会覆盖掉
key = A[j]
while (i>-1) and (A[i]>key):
A[i+1]=A[i]
i=i-1
A[i+1]=key
print(A)
复杂度(c4表示第4行代码执行一次的代价):
2、归并排序(分治思想)
采用递归的方法,将数组一直二分,直至只剩一个数字,然后开始归并
def MergeSort(lists):
if len(lists) <= 1:
return lists
num = int( len(lists) / 2 )
left = MergeSort(lists[:num])
right = MergeSort(lists[num:])
return Merge(left, right)
def Merge(left,right):
r, l=0, 0
result=[]
while l<len(left) and r<len(right):
if left[l] < right[r]:
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += list(left[l:])
result += list(right[r:])
return result
print MergeSort([1, 2, 3, 4, 5, 6, 7, 90, 21, 23, 45])
n为数组中数字个数,那么递归树高度为lgn,层数为lgn+1,所以总代价为
重点:逆序对与归并排序的关系:在归并排序合并步骤时,每移动一个右边数组R中的一个数,查看未排好序左边数组L还剩多少数,然后将其总数相加,就可以得到逆序对的数目了。(思考了一下,觉得主要是因为逆序数的数目与两个数在数组的位置有关,归并排序因为递归的原因,从小达到扩大数组规模,当右边数组中任意一个数移动时,左边数组剩几个,表明有几个数和这个数是逆序数对,以此类推。因为逆序对随着逆序对向正确方向移动一次则逆序对数目减少一次,并不是交换就可以(交换会改变别的逆序对),所以需要累加。)