文章总结自《编程珠玑》。
首先提一下插入排序,在后面的优化中可以用到:
最简单的插入排序: 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;
}