1 快速排序
1960年由查尔斯·安东尼·理查德·霍尔(Charles Antony Richard Hoare,缩写为C. A. R. Hoare)提出。简称为东尼·霍尔(Tony Hoare)。
1.1 执行流程
(1)从序列中选择一个轴点元素(pivot)。我们先假设每次选择 0 位置的元素为轴点元素。
(2)利用 pivot 将序列分割成 2 个子序列。将小于 pivot 的元素放在pivot前面(左侧),将大于 pivot 的元素放在pivot后面(右侧),等于pivot的元素放哪边都可以。
(3)对在轴点前后,由轴点分割而成的两个子序列进行相同的操作,直到不能再分割(子序列中只剩下1个元素)
示例(非绿色的表示成为轴点的元素):
快速排序的本质:逐渐将每一个元素都转换成轴点元素。
1.2 轴点构造
通过执行流程,我们可以发现这个排序的过程并不复杂,但如何将比轴点小的元素放至轴点左侧,大的元素放至轴点右侧,是完成快速排序的关键问题。对此的处理方法是,保存首个元素(轴点元素),并用左指针记录该位置(此时该位置的元素已经没有用处,可用于放置比轴点小的元素),然后让右指针从右端向前遍历,若发现比轴点大,说明该元素应该在右侧,右指针继续向前遍历前一个元素,若发现比轴点小(或等于),则将右指针的元素插入左指针位置,也就是放到轴点前,然后将左指针向后移动,继续判断与轴点的大小关系,若比轴点大,则放入此时的右指针中…直到左右指针重合,就是轴点元素的位置。示例如下。
通过不断地比较,就可以做到轴点左侧元素小于轴点,右侧元素大于轴点了。
1.3 代码实现
在此将快速排序封装成一个类。
class QuickSort():
def quick_sort(self, array):
n = len(array)
self.array=array#获取数组
self.inner_sort(0, n)
def inner_sort(self,begin,end):#区间采用左闭右开
if end-begin<2:
return
mid=self.pivot_index(begin,end)
self.inner_sort(begin,mid)
self.inner_sort(mid+1,end)
def pivot_index(self,begin,end,rand=True):
end-=1#将end指向有效索引
if rand:
rand_index=random.randint(begin,end)
self.array[begin],self.array[rand_index]=self.array[rand_index],self.array[begin]
pivot=self.array[begin]
while begin<end:
while begin<end:
if pivot<self.array[end]:
end-=1
else:
self.array[begin]=self.array[end]
begin+=1
break
while begin<end:
if self.array[begin]<pivot:
begin+=1
else:
self.array[end]=self.array[begin]
end-=1
break
self.array[begin]=pivot
return begin
1.4 时间复杂度
在轴点左右元素数量比较均匀的情况下,同时也是最好的情况,此时的时间复杂度是:T(n) = 2 ∗ T(n/2) + O(n) = O(nlogn)。
如果轴点左右元素数量极度不均匀,最坏情况:T(n) = T(n) − 1 + O(n) = O(n*2)。
为了降低最坏情况的出现概率,一般采取的做法是随机选择轴点元素,在代码中,则是将首个元素和一个随机元素作交换。
由于递归调用的缘故,空间复杂度:O(logn),且其属于不稳定排序。