概述
排序问题是数据处理中常会遇到的问题,通常是解决相关问题的前处理过程。这类算法目前有很多,比如相对暴力的冒泡排序和插入排序法。这类暴力求解算法的时间复杂度一般为O(n2),显然这个时间复杂度无法满足工程的应用。所以,在暴力求解的基础上发展出了归并排序、堆排序以及快速排序,这类排序算法时间复杂度为O(nlog2n)。上述算法都是基于比较法去实现排序,还有部分算法并未采用比较法,这部分算法排序速度要更快一些,这类算法会在后面介绍。
本博客中展示了插入排序、归并排序以及基于归并排序算法衍生出的查找逆序列算法代码。
代码
插入排序
def InserSort(my_list):
for i in range(1,len(my_list)):
key=my_list[i]
j=i-1
while j>=0 and key<my_list[j]:
my_list[j+1]=my_list[j]
j-=1
my_list[j+1]=key
归并排序
def Merge(leftList,rightList):
tmpList=[]
i=0
j=0
while i<len(leftList) and j<len(rightList):
if leftList[i]<=rightList[j]:
tmpList.append(leftList[i])
i+=1
else:
tmpList.append(rightList[j])
j+=1
if j==len(rightList):
for k in leftList[i:]:
tmpList.append(k)
else:
for k in rightList[j:]:
tmpList.append(k)
return tmpList
def MergeSort(my_list):
if len(my_list)<=1:
return my_list
middle=int(len(my_list)/2)
left=MergeSort(my_list[:middle])
right=MergeSort(my_list[middle:])
return Merge(left,right)
if __name__=='__main__':
TestList=[5,8,24,1,44,0]
print(MergeSort(TestList))
查找逆序列
def GetPair(left,right,PairList):
TmpList=[]#返回排序好的列表
i=j=0
while i<len(left) and j<len(right):
if left[i]<=right[j]:
TmpList.append(left[i])
i+=1
else:
TmpList.append(right[j])
for z in left[i:]:
PairList.append(z)
PairList.append(right[j])
j+=1
if i==len(left):
for k in right[j:]:
TmpList.append(k)
else:
for k in left[i:]:
TmpList.append(k)
return TmpList
def ReverseOrderPair(my_list,myPair):
if len(my_list)<=1:
return my_list
mid=int(len(my_list)/2)
LeftList=ReverseOrderPair(my_list[:mid],myPair)
RightList=ReverseOrderPair(my_list[mid:],myPair)
return GetPair(LeftList,RightList,myPair)
if __name__=='__main__':
Pair=[]
TestList=[1,2,3,4,5,6,7,0,12,2,4,7,66,45,85,14,2,5,8,6,5,12,44,3,5]
print(ReverseOrderPair(TestList,Pair))
print(Pair)
print(len(Pair)/2)
说明
插入排序比较简单,只有两次循环嵌套,可以看出一共遍历了n-1 + n-2 + … + 2 + 1 = n * (n-1) / 2 = 0.5 * n ^ 2 - 0.5 * n,所以时间复杂度是O(n2)。
归并算法主要是考虑两个函数的时间花销:一、数组划分函数MergeSort();二、有序数组归并函数Merge()。
Merge()函数的时间复杂度为O(n),因为该函数代码中有2个长度为n的循环。
MergeSort()在计算长度为n的归并排序所消耗的时间 T[n],那么调用MergeSort()函数划分两部分,那每一小部分排序好所花时间则为 T[n/2],而最后把这两部分有序的数组合并成一个有序的数组Merge()函数所花的时间为 O(n),最后时间复杂度的计算公式为:
T
[
n
]
=
2
T
[
n
/
2
]
+
O
(
n
)
T[n] = 2T[n/2] + O(n)
T[n]=2T[n/2]+O(n)
这种递归调用函数时间复杂度的计算可以使用主方法或者枚举法。归并算法的整个过程展开来就是一个具有n个根节点的二叉树结构,共有log2n个层,每一层都需要进行时间复杂度为 O(n)的Merge()函数,所以归并算法时间复杂度为O(nlog2n)。