编程珠玑之排序
时间:2010-11-05 来源:小培
isort3比isort2块15%。
如果输入数组几乎是有序的,那么插入排序的速度会快很多,因为每个元素的移动距离很短。
2.快速排序
快速排序对于大数据量的排序非常有效。
第一个版本:
void qsort1(l,u)
ifl>= u // l should little than u
return;
m = l; //use the first data to split, flagdata
for i =[l+1,u] //scan from the second data
if( x[i] < x[l] ) // the data is little than thefirst data
swap(++m,i); //m should little than i, swap the data
swap(l,m); //m is the write data to set the flag data
qsort1(1,m-1);
qsort1(m+1,u);
运用哨兵,进行代码优化
void qsort2a(l,u)
if l>=u // l should little than u
return;
t = x[l]; //use the first data to split, flag data
m= u+1;
for( i = u;i>=l;i--)
if(x[i]>=t) //even if x[i]== t, also swap
swap(--m,i);
qsort2a(1,m-1);
qsort2a(m+1,u);
对2a算法,利用哨兵进行二次优化:
void qsort2aa(l,u)
if l>=u // l should little than u
return;
t = x[l]; //use the first data to split, flag data
m=i = u+1;
do
while x[--i] < t ;
swap(--m,i);
while i!=l
qsort2aa(1,m-1);
qsort2aa(m+1,u);
哨兵位置变化的算法,哨兵变为x[u],
void qsort2b(l,u)
if l>=u // l should little than u
return;
t = x[u]; //use the first data to split, flag data
m= l-1;
fori = [l,u]
if( x[i] <= t )
swap(++m,i);
qsort2b(1,m-1);
qsort2b(m+1,u);
对于qsort2b算法,利用哨兵进行的二次优化。
void qsort2b(l,u)
if l>=u // l should little than u
return;
t = x[u]; //use the first data to split, flag data
m= i = l-1;
do
while x[++i] > t ;
swap(++m,i);
while i!=u;
qsort2b(1,m-1);
qsort2b(m+1,u);
对于拥有n个相同数据的数组,以上的算法,时间量级退化为为o(n*n).
这个时候使用双向划分,数据相等的时候,停止。
循环不变式为: t=x[l];l<=i<=j<=u; l<a<b<u => x[a]<=x[b]
下标i,j初始化为待划分数组的两端。主循环中有两个内循环,第一个内循环将i向右移过小元素,遇到大元素停止;第二个内循环将j向左移过大元素,遇到小元素停止。然后主循环测试这两个下标是否交叉并交换它们的值。
但是当元素相同的时候,停止扫描,并交换i,j的值。
实现代码:
void qsort3(l,u)
ifl>= u // l should little than u
return;
t = x[l]; //flag
i = l; j= u+1; //init the i,j
loop
do i++ while i<=u && x[i] < t
do j++ while x[i] > t
if i>j
break
swap(i,j);
swap(l,j);
qsort3(1,m-1);
qsort3(m+1,u);
针对qsort3的改善点:
1.flag的值设置为第一个,当给的数据基本有序的时候,程序的性能会变差,所以可以用rand()函数定位,先将第一个数据和定位到的数据交换。提高性能。
2.当l,u距离比较小的时候,快速排序的效率会降低,这个时候可以采用其他的排序方法进行排序,以提高整体的排序效率。
3.将swap函数进行适当的展开。
经过优化的函数为:
void qsort4(l,u,coff) //coff 停止扫描的u-l差距。一般设置为50.
ifu-l<coff // 停止扫描的阀值检测
return;
swap(l,randint(l,u));
t = x[l]; //flag
i = l; j= u+1; //init the i,j
loop
do i++ while i<=u && x[i] < t
do j++ while x[i] > t
if i>j
break
temp=x[i]; x[i]=x[j]; x[j]=temp; //展开swap
swap(l,j);
qsort4(1,m-1);
qsort4(m+1,u);