一.分治思想介绍
二.快速排序算法
思路:
对一个数组进行排序,选取一个参考值(主元)作为中间值,将这个数组中比参考值(主元)小的数放在其左边,比参考值(主元)大的数放在其右边,并且不断递归调用,对左子数组和右子数组进行同样的方法,最后进行整合,即为拍好的有序数组。
1.单项扫描法
确定中间分界点,对左子数组进行排序,对右子数组进行排序
确定中间分界点方法:以数组第一个值作为参考,确定两个指针,左指针指向数组第二个值,右指针指向数组最后一个值,左指针不断右移,在碰到比中间参考值大时停下,与右指针对应的值交换,右指针左移一位,左指针继续右移,直到左指针,右指针交错(左指针的值大于右指针),将右指针对应的值和数组第一个值交换,此时,中间值左边都是比其小的数,右边都是比其大的数。右指针的值为分界点
def quicksort(alist):
quicksorthelper(alist,0,len(alist)-1)
def quicksorthelper(alist,first,last):
if first<last:
splitpoint=partition(alist,first,last) #确定中间分界点
quicksorthelper(alist,first,splitpoint-1) #对左子数组进行排序
quicksorthelper(alist,splitpoint+1,last) #对右子数组进行排序
def partition(alist,first,last):
pivotvalue=alist[first] #以数组第一个值作为中间参考值
left=first+1 #确定指针,左指针指向数组第二个元素
right=last #右指针指向数组最后一个元素
done=True
while done:
while left<=right and alist[left]<=pivotvalue: #当左指针遇到的数比中间参考值小,左指针左移
left+=1
if left>right: #左右指针交错,循环停止
done=False
else:
alist[left], alist[right] = alist[right], alist[left] #当左指针遇到的数比中间参考值大,左指针停下,和右指针进行交换,
right-=1 #并且右指针左移
alist[first],alist[right]=alist[right],alist[first] #左右指针交错,右指针指着数组中比参考值小的数,将右指针指向的数和中间值交换
#这样,中间值左边都是比其小的数,右边都是比其大的数
return right #同时返回右指针,作为数组中间分界点
测试代码
#测试代码
import random
textlist=[]
for i in range(10):
textlist.append(random.randint(1,100))
print(textlist)
quicksort(textlist)
print(textlist)
2.双向扫描法
双向扫描法与单向扫描法大致相同,双向扫描法,左指针向右扫描,右指针也在向左扫描,在左指针对应的值比中间参考值打包,右指针对应的值比中间参考值小的时候两边停下,进行交换
def quicksort(alist):
quicksorthelper(alist,0,len(alist)-1)
def quicksorthelper(alist,first,last):
if first<last:
splitpoint = partition(alist, first, last)
quicksorthelper(alist, first, splitpoint - 1)
quicksorthelper(alist, splitpoint + 1, last)
def partition(alist,first,last):
pivotvalue=alist[first]
leftmark=first+1
rightmark=last
done=True
while done:
while leftmark<=rightmark and alist[leftmark]<=pivotvalue:
leftmark+=1
while leftmark<=rightmark and alist[rightmark]>pivotvalue:
rightmark-=1
if leftmark>rightmark:
done=False
else:
alist[leftmark],alist[rightmark]=alist[rightmark],alist[leftmark]
alist[first],alist[rightmark]=alist[rightmark],alist[first]
return rightmark
3.算法优化(三点取值法)
针对快速排序,最重要的就是选取中间值,能够确保中间值将数组较平均分为两堆,但是进行排序数组的数据并不一定随机分布,选取的中间值并不能将数组较平均分为两堆,极端情况可能是左子数组空缺,右子数组几乎为整个数组,算法复杂度还原为O(n^2)。因此,通过改进选取中间值来改进算法
通过取数组中头,尾,中间三个数据作比较,选取中间值为数组的中间参考值。
def quicksort(alist):
quicksorthelper(alist,0,len(alist)-1)
def quicksorthelper(alist,first,last):
if first<last:
splitpoint = partition(alist, first, last)
quicksorthelper(alist, first, splitpoint - 1)
quicksorthelper(alist, splitpoint + 1, last)
def partition(alist,first,last):
midplace=(first+last)>>1
if (alist[first]<alist[midplace]<alist[last]) or (alist[last]<alist[midplace]<alist[first]):
alist[first],alist[midplace]=alist[midplace],alist[first]
elif (alist[first]<alist[last]<alist[midplace]) or (alist[midplace]<alist[last]<alist[first]):
alist[first], alist[last] = alist[midplace], alist[last]
pivotvalue=alist[first]
leftmark=first+1
rightmark=last
done=True
while done:
while leftmark<=rightmark and alist[leftmark]<=pivotvalue:
leftmark+=1
while leftmark<=rightmark and alist[rightmark]>pivotvalue:
rightmark-=1
if leftmark>rightmark:
done=False
else:
alist[leftmark],alist[rightmark]=alist[rightmark],alist[leftmark]
alist[first],alist[rightmark]=alist[rightmark],alist[first]
return rightmark
三.归并排序算法
思路:将数组分为左右两个子数组,递归调用归并函数进行排序
子数组分别排序后,将两个有序的子数组合并放进一个数组(方法:通过比较两个数组的首元素,谁小谁先出)
def mergesort(textlist):
if len(textlist)<=1: #递归基本结束条件
return textlist #一直分到长度为1的列表,只有一个数据项的表自动就排好顺序了
else:
mid=len(textlist)//2 #取中间
lefthalf=mergesort(textlist[:mid]) #左半部分排序
righthalf=mergesort(textlist[mid:]) #右半部分排序
merge=[] #左右合并,定义一个空列表
while lefthalf and righthalf: #while加列表表示列表不为空就继续执行
if lefthalf[0]<=righthalf[0]: #左半部分第一个和右半部分第一个进行比较
merge.append(lefthalf.pop(0)) #如果左半部分小,那就先加入左半部分,同时删除该数据
else: #如果右半部分小,那就加入右半部分,同时删除
merge.append(righthalf.pop(0))
if righthalf: #有可能出现左右部分长度不相等,
merge.extend(righthalf) #如果左边剩余,把剩下的数据项加入的总列表
elif lefthalf: #右边同理
merge.extend(lefthalf)
return merge
textlist=[10,90,30,40,70,20,50,80]
print(mergesort(textlist))