记录一下学习过程,大部分代码和教材(Python数据结构)上一致,做了一小部分修改,例如用索引代替列表切片操作,算是完成课后习题吧。
首先是三个经典的排序算法,冒泡,插入,选择。它们思路简单但时间复杂度较高
冒泡
对冒泡排序进行了小小的修改,在序列已经有序之后可以提前退出
def Bubblesort(alist):#冒泡(改)
exchanges = True#这里是改进的地方
right = len(alist)-1
left = 0
while right>left and exchanges:
exchanges = False
for i in range(left,right):
if alist[i]>alist[i+1]:
exchanges=True
alist[i],alist[i+1]=alist[i+1],alist[i]
right = right-1
for j in range(right,left,-1):
if alist[j]<alist[j-1]:
alist[j],alist[j-1]=alist[j-1],alist[j]
插入和选择
插入排序是维护一个有序的序列,选择一个数,插入有序的序列中
选择排序则是生成一个有序的序列,始终选择最大的那个数,这样由它们生成的序列就是有序的
def selectionSort(alist):#选择
for fillslot in range(len(alist)-1, 0, -1):
positionOfMax = 0
for location in range(1, fillslot+1):
if alist[location] > alist[positionOfMax]:
positionOfMax = location
alist[fillslot],alist[positionOfMax]=alist[positionOfMax],alist[fillslot]
def insertionSort(alist):#插入
for index in range(1, len(alist)):
currentvalue = alist[index]
position = index
while position > 0 and alist[position-1] > currentvalue:
alist[position] = alist[position-1]
position = position-1
alist[position] = currentvalue
希尔排序
是更高级的插入排序,把数据分组,对每个小组进行插入排序,之后不断减少组数,增加每组所包含的数的数量,如第一开始两个数一组,分成n/2个组,第二遍四个数一组,分成n/4组,直到最后所有数都为一组,序列就是有序的了。
def shellSort(alist):#希尔
sublistcount = len(alist) // 2
while sublistcount > 0:
for startposition in range(sublistcount):
gapInsertionSort(alist, startposition, sublistcount)
sublistcount = sublistcount // 2
def gapInsertionSort(alist, start, gap):
for i in range(start+gap, len(alist), gap):
currentvalue = alist[i]
position = i
while position >= gap and alist[position-gap] > currentvalue:
alist[position] = alist[position-gap]
position = position-gap
alist[position] = currentvalue
归并排序
一个序列先不断二分拆成一个一个的数,再合并为有序的序列,排序是在合并时进行的。
加入了索引,来避免列表切片操作
def mergeSort(alist):#归并(改)
j=0
for i in mergeSortHelp(alist,0,len(alist)-1)[:]:
alist[j]=i
j+=1
def mergeSortHelp(alist,start,end):
if end-start>=1:
mid=(start+end)//2
lefthalf=mergeSortHelp(alist,start,mid)
righthalf=mergeSortHelp(alist,mid+1,end)
rest=[]
i,j=0,0
while i < len(lefthalf) and j < len(righthalf):
if lefthalf[i] < righthalf[j]:
rest.append(lefthalf[i])
i = i + 1
else :
rest.append(righthalf[j])
j = j + 1
while i < len(lefthalf):
rest.append(lefthalf[i])
i = i + 1
while j < len(righthalf):
rest.append(righthalf[j])
j = j + 1
return rest
else :
return [alist[start]]
快速排序
选择一个数作为基准,比它大的放右边,比它小的放左边,再分别对左边和右边进行同样的操作,直到左右只剩一个元素,有一种递归的感觉。
修改后的,再选基准元素时,在三个里面选中间的,尽量避免了选择过大或者过小的元素。
def quickSort(alist, first, last):#快速排序
if first < last:
pivotvalue = alist[first]
leftmark = first + 1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
leftmark = leftmark + 1
while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
rightmark = rightmark - 1
if rightmark < leftmark:
done = True
else:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[first]
alist[first] = alist[rightmark]
alist[rightmark] = temp
quickSort(alist, first, rightmark-1)
quickSort(alist, rightmark+1, last)
def quickSort3(alist,first,last):#快速排序改
if first < last:
pivotvalue = middle(alist[first],alist[last],alist[(first+last)//2])
leftmark = first
rightmark = last
while rightmark>leftmark:
while alist[leftmark] <= pivotvalue:
leftmark = leftmark + 1
while alist[rightmark] >= pivotvalue:
rightmark = rightmark - 1
if rightmark > leftmark:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
quickSort(alist, first, rightmark)
quickSort(alist, rightmark, last)
def middle(a,b,c):
li=[a,b,c]
li.sort()
return li[1]
对比一下这几种算法的运行时间
import random
alist=[i for i in range(500)]
random.shuffle(alist)
import timeit
t1=timeit.Timer('Bubblesort(alist[:])','from __main__ import alist,Bubblesort' )
t2=timeit.Timer('selectionSort(alist[:])','from __main__ import alist,selectionSort' )
t3=timeit.Timer('insertionSort(alist[:])','from __main__ import alist,insertionSort' )
t4=timeit.Timer('shellSort(alist[:])','from __main__ import alist,shellSort' )
t5=timeit.Timer('mergeSort(alist[:])','from __main__ import alist,mergeSort' )
t6=timeit.Timer('quickSort(alist[:],0,len(alist[:])-1)','from __main__ import alist,quickSort' )
t7=timeit.Timer('quickSort3(alist[:],0,len(alist[:])-1)','from __main__ import alist,quickSort3')
t8=timeit.Timer('alist[:].sort()','from __main__ import alist')
print(t1.timeit(number=100))
print(t2.timeit(number=100))
print(t3.timeit(number=100))
print(t4.timeit(number=100))
print(t5.timeit(number=100))
print(t6.timeit(number=100))
print(t7.timeit(number=100))
print(t8.timeit(number=100))
'''
运行结果
冒泡1.5784653999999998
选择0.6926877
插入0.9691874
希尔0.1233234000000003
归并0.12611349999999977
快速0.0806591000000001
快速改0.08754919999999977
列表类提供的sort方法0.003951200000000377
'''
可以看出冒泡、选择、排序这三个运行时间还是较长的,希尔、归并、快速时间复杂度平均都是,运行时间比较短,改进选择基准值的快速排序算法,作用不大,但是这六个相对于列表类提供的sort(),都慢了太多太多。