几种快速排序的耗时比较
数组长度=10^4 | 固定pivot(首) | 随机pivot | 三数取中 | 三数取中+插排 | 五数取中 |
随机数组 | 0.03429 s | 0.04581 s | 0.0415 s | ||
升序数组 | 4.98177 s | 0.03306 s | 0.03784 s | ||
降序数组 | 4.96196 s | 0.03328 s | 0.0342 s | ||
重复数组 | 4.29686 s | 4.69243 s | 4.53609 s |
Quick Sort 快速排序
本质:分治思想特点:每经过一次快排,轴点(pivot)元素必然就位!
过程:每经过一次快排,枢轴元素将所处理区域划分为“小元素”和“大元素”两段,并通过递归不断划分,最终得到一个排序的序列。
核心技巧:每一次的partition都比较平均。
1.如果每次划分都将所处理的区域划分为长度基本相等的两段$$\frac{n}{2^k}=1\rightarrow k=log_{2}n$$
很显然只需大约log n层划分,就能使最底层的每个分段长度不超过1。而每一趟划分的过程中,关键码比较次数不超过对象长度。所以当前情况下,元素比较次数不超过:
$$O(nlogn)$$
2.最坏情况:每次划分得到的两段总有一段为空,总的比较次数是
$$O(n^2)$$
方法1. 固定枢轴:
Created on Sun Apr 8 10:35:06 2018
@author: yzdeng
"""
import numpy as np
import timeit
import sys
sys.setrecursionlimit(1000000)
#固定pivot(数组首元素做pivot)
def quick_sort1(lst,l,r):
if l>=r:
return
i=l
j=r
pivot=lst[i]
while i<j:
while i<j and lst[j]>=pivot:
j-=1
if i<j:
lst[i]=lst[j]
i+=1
while i<j and lst[i]<=pivot:
i+=1
if i<j:
lst[j]=lst[i]
j-=1
lst[i]=pivot
quick_sort1(lst,l,i-1)
quick_sort1(lst,i+1,r)
return lst
方法2. 随机枢轴:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 8 17:20:36 2018
@author: dengyuzhao
"""
from random import choice
import numpy as np
import timeit
import sys
sys.setrecursionlimit(1000000)
def quick_sort1(lst,l,r):
if l>=r:
return
a=np.arange(l,r+1)
p=choice(a)
i=l
j=r
pivot=lst[p]
lst[p]=lst[i]
while i<j:
while i<j and lst[j]>=pivot:
j-=1
if i<j:
lst[i]=lst[j]
i+=1
while i<j and lst[i]<=pivot:
i+=1
if i<j:
lst[j]=lst[i]
j-=1
lst[i]=pivot
quick_sort1(lst,l,i-1)
quick_sort1(lst,i+1,r)
return lst
#test:
a1=np.random.normal(100,100,(10000,))
b1=list(a1)
print(timeit.Timer(lambda:quick_sort1(b1,0,9999)).timeit(1))
a2=np.arange(10000)
b2=list(a2)
print(timeit.Timer(lambda:quick_sort1(b2,0,9999)).timeit(1))
a3=np.arange(10000,0,-1)
b3=list(a3)
print(timeit.Timer(lambda:quick_sort1(b3,0,9999)).timeit(1))
a4=[2]*10000
print(timeit.Timer(lambda:quick_sort1(a4,0,9999)).timeit(1))