1. 主要思想
快速排序的思想其实很简单,就是分治+递归。
讲故事的方法比较适合描述快速排序的过程,假设有一队人,身高大小不一,先选出一个队长,然后队长说比我低的到我左边去,比我高的到我右边去。partition。
站好后,队长在分别给他左右两边的队员说,你们分别去选出各自的队长,然后执行我刚才的操作。
如此递归下去,直到要排序的队列长度为1就可以停止了。此时队列就是有序的。
快排实现的关键是partition,快排实现的关键是partition,快排实现的关键是partition,重要的事情说三遍!!!
partition要解决的问题是,给定一个数组arr[]和数组中任意一个元素a,重排数组使得a左边都小于它,右边都不小于它,这样经过一次partition后,元素a就放在了正确的位置。
2. step by step
假设要排序的序列为a
1)先随机在序列a中选取一个元素pivot = a[i]
2)将小于a[i]的元素移动到a[i]的左边,大于a[i]的元素移到a[i]的右边
3)递归的对a[i]的左右两边执行1、2过程
4)直到每个partition的size为1,此时序列即为有序序列。
说明:快速排序里的partition算法解决的问题如下,给定一个数组arr[]和数组中任意一个元素a,重排数组使得a左边都小于它,右边都不小于它。
3. example
4. 编程实现
Python版本,简单版(7行):
'''
@desc:对列表arr进行快速排序
@ret:排序后的列表
@author:sheldonwong
'''
def quicksort(arr):
if(len(arr) <= 1):
return arr
pivot = arr[len(arr)//2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left)+middle+quicksort(right)
带partition的版本
public static int partition(int[] arr,int left,int right){
int pivot = arr[left];
int small = left;
for(int i = left + 1; i <= right; i++){
if(arr[i] < pivot){
small++;
if(small != i){
swap(arr,i,small);
}
}
}
swap(arr,left,small);
return small;
}
public static void quicksort(int[] arr,int left,int right){
if(left < right){
int middle = partition(arr,left,right);
quicksort(arr,left,middle-1);
quicksort(arr,middle+1,right);
}
}
可以借助这张图片来理解一下上面的partition函数
重点是理解small指针,small总是记录着pivot左边的索引,i是遍历指针。
初始化
pivot = arr[left]
pivot选定后就不用关注了,因为它不会再变了,在这轮partition中。
下面主要关注small和i
small=left //其实就是0,small刚开始只有0个元素,small其实也记录了比pivot小的元素的个数,同时也是最后和pivot交换的索引值。
//遍历pivot后面的n-1个元素,如果遇到小于pivot的,就把small加1(表示small中又多了一个元素),然后把索引i和索引small对应的元素交换
画了个图,当i=2时,条件(arr[i]<pivot)满足
small++;
swap(small,i);