一、简介
快速排序是冒泡排序的改进。可以看成是一个分治的过程。首先将数组A[p,…r]分成三部分:A[p,…,q-1],A[q],A[q+1,…,r],A[p,…,q-1]中的每一个元素都比A[q]小,而A[q+1,…,r]的每一个元素都比A[q]大。然后分别对A[p,…,q-1]和A[q+1,…,r]递归调用快速排序。当左右两部分排序好之后,即完成了整个数组的排序。
那么如何计算下标q是整个快速排序的关键。首先选择一个元素作为主元,围绕它来划分A[p,…r],这个主元也是最后的A[q]。划分过程中需要两个指针,一个j用来遍历数组,另一个i指向被交换的索引。从数组的左端开始遍历,如果A[j]小于主元,i++,并且A[i]和A[j]交换,如果大于等于主元,则不交换,当数组遍历完毕之后,将主元和A[i+1]交换。
快速排序是冒泡排序的改进。在冒泡排序中,每次循环改变一个元素的位置,并确定这个元素的位置,即将这个元素“浮”到最前面的位置。在快速排序中,每次改变多个元素的位置,并确定一个元素的位置,将这个元素“浮”到合适的位置。快速排序在每次循环中,交换的次数明显减少。
二、伪代码
2.1 递归
quickSort(A,p,r)
if p<r
q=partition(A,p,r)
quickSort(A,p,q-1)
quickSort(A,p+1,r)
partition(A,p,r)
x=A[r]
i=p-1
for j=p tp r-1
if A[j]<x
i++
swap(A[i],A[j])
swap(A[i+1],A[r])
return i+1
2.2 非递归
使用一个栈辅助,存储p,q,r
loopQuickSort(A)
S=null //创建一个栈
start=0;
end=A.length-1
S.push(start)
S.push(end)
while(!S.isEmpty)
end=S.pop()
start=S.pop()
q=partition(A,start,end)
if(start<q-1)
S.push(start)
S.push(q-1)
if(end>q+1)
S.push(q+1)
S.push(end)
三、代码实现
3.1 递归
public static void quickSort(int[] array,int p,int r){
//p95
if(p<r){
int q=partition(array,p,r);
quickSort(array,p,q-1);
quickSort(array,q+1,r);
}
}
public static int partition(int[] array,int p,int r){
//p95
int x=array[r];
int i=p-1;
for(int j=p;j<r;j++){
if(array[j]<=x){
i+=1;
int temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}
i+=1;
array[r]=array[i];
array[i]=x;
return i;
}
时间复杂度 O(nlgn)
空间复杂度 原址排序,递归调用需要辅助空间
3.2 非递归
public static void loopQuickSort(int[] array){
//p95
Stack<Integer> s=new Stack<Integer>();
int start=0;
int end=array.length-1;
s.push(start);
s.push(end);
while(!s.isEmpty()){
end=s.pop();
start=s.pop();
int q=partition(array,start,end);
if(start<q-1){
s.push(start);
s.push(q-1);
}
if(end>q+1){
s.push(q+1);
s.push(end);
}
}
}
public static int partition(int[] array,int p,int r){
//p95
int x=array[r];
int i=p-1;
for(int j=p;j<r;j++){
if(array[j]<=x){
i+=1;
int temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}
i+=1;
array[r]=array[i];
array[i]=x;
return i;
}
时间复杂度O(nlgn)
空间复杂度:需要一个栈辅助
四、注意事项
1、快速排序每一次循环可以至少确定一个元素的位置
2、快速排序的非递归不一定比递归快
3、当需要排序的序列中有大量的相等的元素时,用快速排序性能尚可,但还有很大的改进空间,可以设计算法,将序列分成三部分,第一部分和第三部分和之前一样,第二部分存放和主元相同的元素,之后的比较只用在第一和第三部分进行。