快速排序是一种比较实用的排序算法,平均时间复杂度为O(nlogn),最坏情况为O(n*n),最好情况也是O(nlogn)。该算法基于分治处理思想,在数列中选取一个主元,根据这个主元把整个数列分为两部分:一部分比这个主元小,一部分比这个主元大。然后对这两部分分别再选取主元划分,以此递归下去。
针对一个A[p....r]的数组,其执行步骤可以描述为:
1、分组:A[p..r]被划分为两个可能为空的子数组A[p..q-1]和A[q+1..r],使得A[p..q-1] <= A[q] <= A[q+1..r];
2、解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]排序。
3、合并。
快速排序的关键是实现分组(partion),此过程有多种实现方法。主元可以分别选取首、尾,或者使用三数取中法。数组扫描方向又可以单向扫描和双向扫描。另外,借助栈结构,还有非递归版本的实现。
目前,自己分析实现了的版本如下:
1、尾数作为主元,从前往后单向扫描
貌似此版本是《算法导论》里的实现版本,具体我也没看过,好多博客里都这样说。伪代码如下:
QUICKSORT(A, p, r)
if p < r
then q ← PARTITION(A, p, r)
QUICKSORT(A, p, q - 1)
QUICKSORT(A, q + 1, r)
关键的分组过程:
PARTITION(A, p, r)
x ← A[r]
i ← p - 1
for j ← p to r - 1
do if A[j] ≤ x
then i ← i + 1
exchange A[i] <-> A[j]
exchange A[i + 1] <-> A[r]
return i + 1
具体实现:
int partionLast(int arr[], int p, int r){
int x = arr[r];
int i = p - 1;
int j, tmp;
for(j = p; j < r ; j++){
if(arr[j] <= x){
i++;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
tmp = arr[i+1];
arr[i+1] = arr[j];
arr[j] = tmp;
return i+1;
}
<pre name="code" class="cpp"> void quicksort(int arr[], int p, int r){
if(p<r){
int q = partionLast(arr,p,r);
quicksort(arr,p,q-1);
quicksort(arr,q+1,r);
}
}
2、第一个数作为主元,从前往后单向扫描
int partionFirst(int arr[], int p, int r){
int x = arr[p];
int i = p;
int j,tmp;
for(j = p+1; j <= r; j++){
if(arr[j] <= x){
i++;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
tmp = arr[i];
arr[i] = arr[p];
arr[p] = tmp;
return i;
}
3、尾数作主元,双向扫描
int partionDoubleEnded(int arr[], int p, int r){
int x = arr[r];
int i = p;
int j = r - 1;
int tmp;
do{
if(arr[i] <= x){
i++;
}else{
if(arr[j] >= x){
j--;
}else{
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
}
}
}while(i <= j&&j >= p);
tmp = arr[i];
arr[i] = arr[r];
arr[r] = tmp;
return i;
}
还有一种非递归的实现,网上搜了许多,似乎只有一种实现方式,摘抄如下:
template<typename Comparable>
void quicksort2(vector<Comparable> &vec,int low,int high){
stack<int> st;
if(low<high){
int mid=partition(vec,low,high);
if(low<mid-1){
st.push(low);
st.push(mid-1);
}
if(mid+1<high){
st.push(mid+1);
st.push(high);
}
//其实就是用栈保存每一个待排序子串的首尾元素下标,下一次while循环时取出这个范围,对这段子序列进行partition操作
while(!st.empty()){
int q=st.top();
st.pop();
int p=st.top();
st.pop();
mid=partition(vec,p,q);
if(p<mid-1){
st.push(p);
st.push(mid-1);
}
if(mid+1<q){
st.push(mid+1);
st.push(q);
}
}
http://blog.youkuaiyun.com/v_july_v/article/details/6116297
http://blog.youkuaiyun.com/v_JULY_v/article/details/6211155
http://blog.youkuaiyun.com/v_JULY_v/article/details/6262915