最近摸了下Pyhton,发现真心好用。写下快排来练手。
import random
def partition(a,lo,hi):
i = lo
j = hi+1
v = a[lo]
while True:
while a[i]<=v:
i = i+1
if i == hi:
break
j = j-1
while a[j]>v:
j = j-1
if j == lo:
break
if i>=j:
break
a[i],a[j]=a[j],a[i]
a[lo],a[j] = a[j],a[lo]
return j
def quicksort(a,lo,hi):
if hi<=lo:
return
j = partition(a,lo,hi)
quicksort(a,lo,j-1)
quicksort(a,j+1,hi)
a = []
for i in range(1000000):
a.append(random.uniform(1,100000000))
quicksort(a,0,len(a)-1)
写的时候很多小细节要注意,比如要注意切分中j的移动,任何一点对i和j不合适的改动都会导致错误。
100万的数据时间是3.44223299616秒排序完成。
对比下选择排序:1万的数据在6.5秒内排序完成。100万数据时间太长。def selectionsort(a):
for i in range(len(a)):
for j in range(i,len(a)):
if a[i]>a[j]:
a[i],a[j]=a[j],a[i]
即使是简单的快速排序也有多种改进方法:
1)存在很多重复元素的时候可以采用3路排序的方法,提高速度;
2)对小数组排序,插入排序比快速排序更快,因为快速排序是递归的。
下面继续修改代码(加入小数组用插入排序):
import random
import time
def partition(a,lo,hi):
<span style="white-space:pre"> </span>i = lo
<span style="white-space:pre"> </span>j = hi+1
<span style="white-space:pre"> </span>v = a[lo]
<span style="white-space:pre"> </span>while True:
<span style="white-space:pre"> </span>while a[i]<=v:
<span style="white-space:pre"> </span>i = i+1
<span style="white-space:pre"> </span>if i == hi:
<span style="white-space:pre"> </span>break
<span style="white-space:pre"> </span>j = j-1
<span style="white-space:pre"> </span>while a[j]>v:
<span style="white-space:pre"> </span>j = j-1
<span style="white-space:pre"> </span>if i>=j:
<span style="white-space:pre"> </span>break
<span style="white-space:pre"> </span>a[i],a[j]=a[j],a[i]
<span style="white-space:pre"> </span>a[lo],a[j] = a[j],a[lo]
<span style="white-space:pre"> </span>return j
def quicksort(a,lo,hi):
<span style="white-space:pre"> </span>f hi>=lo+15:
<span style="white-space:pre"> </span>j = partition(a,lo,hi)
<span style="white-space:pre"> </span>quicksort(a,lo,j-1)
<span style="white-space:pre"> </span>quicksort(a,j+1,hi)
<span style="white-space:pre"> </span>else:
<span style="white-space:pre"> </span>selectionsort(a,lo,hi)
def selectionsort(a,lo,hi):
<span style="white-space:pre"> </span>for i in range(lo,hi+1):
<span style="white-space:pre"> </span>for j in range(i,hi+1):
<span style="white-space:pre"> </span>if a[i]>a[j]:
<span style="white-space:pre"> </span>a[i],a[j]=a[j],a[i]
a = []
for i in range(1000000):
<span style="white-space:pre"> </span>a.append((int)(random.uniform(1,100000000)))
start = time.clock()
quicksort(a,0,len(a)-1)
end = time.clock()
print end-start
print a[0:10]
100万数据3.56445105976s完成,并没有体现特别大的优势,算法书上说省15%左右的时间,还要仔细再研究下。
对多个重复的元素进行排序:
三相切分
import random
import time
def quick3sort(a,lo,hi):
if hi<=lo:
return
lt = lo
i = lo+1
gt = hi
v = a[lo]
while i<=gt:
if a[i]<v:
a[i],a[lt] = a[lt],a[i]
i = i+1
lt = lt+1
elif a[i]>v:
a[i],a[gt] = a[gt],a[i]
gt =gt-1
else:
i = i+1
quick3sort(a,lo,lt-1)
quick3sort(a,gt+1,hi)
a =[]
for i in range(1000000):
a.append((int)(random.uniform(1,100)))
start = time.clock()
quick3sort(a,0,len(a)-1)
end = time.clock()
print end-start
print a[0:10]
100万数据,范围(1,100000000)。6.12628795802s完成。
三相切分基本思路是把数据分成小于v,等于v,大于v的三段。然后再对小于v和大于v的进行快速排序。
如果对相同元素多的数据比如(1:100)100万组数据只在1.45126854664内完成。
(1:10)的数据只在0.754866314071内完成。
而对原始的quicksort要用3.83970068155,和范围大的时间一样。
实际上如果已知到键的种类,桶排序是最快的,它只需要O(N)的算法复杂度。