高速排序总结

文章总结自《编程珠玑》。
首先提一下插入排序,在后面的优化中能够用到:
最简单的插入排序:
isort1:
for i = [1, n)
    for(j = i; j> 0 && x[j - 1] > x[j] ; j--)
            swap(j-1, j)

优化策略:不进行转化。将要插入的数存储起来,从后往前进行查找赋值。直到遇到更小的数时。将存储起来的值赋值给更小的数的后面一位。
isort2:
for i = [1, n)
    t = x[i]
    for(j = i; j> 0 && x[j - 1] > t; j--)
        x[j] = x[j - 1]
    x[j] = t

简单的快排:
一旦发现某个元素比标准元素小了,则进行交换,平均为O(nlogn)时间以及O(logn)栈空间
void qsort1(l, u)
    if(l >= u)    return
    m = l
    for i = [l + 1, u]
        if(x[i] < x[l])
            swap(++m, i)    
    swap(l, m) // 需特别注意
    qsort1(l, m - 1)
    qsort1(m + 1, u)
假设从右向左进行扫描。能够省去for循环外的swap


在排序元素全都相等的情况下,会退化为平方时间的算法。
能够使用双向划分进行优化: 注意元素相等时候的处理措施:进行交换
void qsort2(l, u)
    if l >= u
        return
    t = x[l]; i = l; j = u + 1
    loop
        do i++ while i <=u && x[i] < t
        do j--   while x[j] > t
        if    i > j
            break
        swap(i, j)
    swap(l, j)
    qsort2(l, j - 1)
    qsort2(j + 1, u)

另外,为了防止对于有序序列每次仅仅移动一个元素,採取随机设置排序下标的方式,而不是仅仅以第一个下标为基准进行排序:
swap(l, randint(l, u))


同一时候,当要排序的数组足够小时,能够考虑用插入排序进行处理,由于数组已经基本有序了,cutoff一般在50左右比較理想:
qsort3(0, n - 1)
isort2()

void qsort3(l, u)
    if u - l < cutoff
        return
   swap(l,  randint(l, u))
   t = x[l]; i = l; j = u + 1
   loop
        do i++ while i <=u && x[i] < t
        do j--   while x[j] > t
        if    i > j
            break
        temp = x[i]; x[i] = x[j]; x[j] = temp
   swap(l, j)
   qsort3(l, j - 1)
   qsort4(j + 1, u)

再附上快排的递归以及非递归实现源代码,并非最优化版本号。
转自http://www.cnblogs.com/zhangchaoyang/articles/2234815.html。
非递归实现时间上就是用栈保存每个待排序子串的首尾元素下标,下一次while循环时取出这个范围。对这段子序列进行partition操作

#include<iostream>
#include<vector>
#include<stack>
#include<cstdlib>
#include<algorithm>
using namespace std;
 
/**把数组分为两部分,轴pivot左边的部分都小于轴右边的部分**/
template <typename Comparable>
int partition(vector<Comparable> &vec,int low,int high){
    Comparable pivot=vec[low];  //任选元素作为轴,这里选首元素
    while(low<high){
        while(low<high && vec[high]>=pivot)
            high--;
        vec[low]=vec[high];
        while(low<high && vec[low]<=pivot)
            low++;
        vec[high]=vec[low];
    }
    //此时low==high
    vec[low]=pivot;
    return low;
}
 
/**使用递归高速排序**/
template<typename Comparable>
void quicksort1(vector<Comparable> &vec,int low,int high){
    if(low<high){
        int mid=partition(vec,low,high);
        quicksort1(vec,low,mid-1);
        quicksort1(vec,mid+1,high);
    }
}
 
/**使用栈的非递归高速排序**/
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);
            }       
        }
    }
}
 
int main(){
    int len=1000000;
    vector<int> vec;
    for(int i=0;i<len;i++)
        vec.push_back(rand()); 
    clock_t t1=clock();
    quicksort1(vec,0,len-1);
    clock_t t2=clock();
    cout<<"recurcive  "<<1.0*(t2-t1)/CLOCKS_PER_SEC<<endl;
     
    //又一次打乱顺序
    random_shuffle(vec.begin(),vec.end());
         
    t1=clock();
    quicksort2(vec,0,len-1);
    t2=clock();
    cout<<"none recurcive  "<<1.0*(t2-t1)/CLOCKS_PER_SEC<<endl;
     
    return 0;
}
posted on 2017-05-09 17:39  ljbguanli  阅读(110)  评论(0编辑  收藏  举报