快速排序算法改进,高手请教?100分奉送 急!!!

lzn1 2003-10-15 03:52:34
要求 1 枢轴采用随机数
2 在Partition(..)函数中,要求对枢轴记录最后定位,而不是在中途交换。
如《数据结构》10.10(b)
...全文
115 点赞 收藏 13
写回复
13 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
LeeMaRS 2003-10-16
至于随机化快排以及序列在什么长度时转用插入排序的问题, 可以参考一下starfish的主页http://algorithm.myrice.com/algorithm/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm
回复
LeeMaRS 2003-10-16
plainsong(短歌), 我翻了一下书, 算法的描述里的确用到了递归和排序. 估计就是你见过的那一种了. 不知道为什么说是"近似为O(n)", 书上似乎没有这么说的, 书上用的描述语句是"最坏情况下的线性时间选择算法" (见傅清祥 王晓东 <<算法与数据结构>> P269)
回复
短歌如风 2003-10-16
我上面说“真正非递归”是指不使用栈结构的。
随机取值的情况分析只能根据随机数序列来进行,测试是靠不住的,因为我们使用随机生成数据分布对Quick Sort进行测试时也很难遇到它的不利情况,只有靠分析。而随机序列只是提高了分析的难度而已。事实上我们可以假设有N个数据,它们的排列共有N!个,用任何一个随机数序列对这N!种不同情况进行排序出现的有利和不利情况必然是同等数量的。

我对LeeMaRS所说的O(n)的“选出中位数”的算法很感兴趣。我见过的算法虽然近似为O(n),但其中用到了递归和排序,用来改进Quick Sort并不理想。

此外我的经验是序列不大于16时插入排序就比Quick Sort更优秀了:
序列长度为16时,插入排序的最大比较次数是120,最小比较次数是15,平均比较次数是60,从比较次数上已经不输给Quick Sort了,而由于代码简单本身还减少了效率损失。
回复
短歌如风 2003-10-16
关于消除递归的问题,我知道的二叉树的非递归遍历算法是真正的非递归的,事实上比递归版本要慢,优点是在多线程访问时不需要锁住整棵树而只需要锁住节点。

使用栈模拟递归最大的好处是避免栈溢出问题,因为内存分配失败只是可普通异常,是可以处理的,而栈溢出通常是终止性的,程序除了终止运行再没有其它办法。而这时“手工栈”通常是要用“动态内存分配”实现的,动态内存分配本身的效率代价将抵消减少函数调用带来的好处。而使用定条数组来实现“手工栈”则没有这个缺点。不过对Quick Sort的效率影响也不会很大,因为主要总是还是比较次数问题。
回复
短歌如风 2003-10-16
我觉得对于取随机值的方法可以这样分析:
先假定一个随机序列,随机数是从序列中按顺序取的。很明显,对于任意一个序列,都可以找到一个分布使每次都是畸型划分,同样也可以找到一个分布使每次都是平均划分。因此可以说,使用随机值和使用中间元素的方法没什么区别。如果考虑数据分布有序和倒序情况概率较大的实际情况,则不使用随机值还更好一些。
事实上,使用中间元素的方法相当于选择了所有数值都是0.5的随机序列。
回复
ZhangYv 2003-10-16
楼主要求的是随机快速排序吗?目前对这个算法的优劣似乎还没有一个定论,很多权威的书籍上看法都不同!你可以看一下这里提到的排序http://expert.csdn.net/Expert/topic/2059/2059607.xml?temp=.6762354

倒是LeeMaRS的程序让我大开眼界,堆栈深度确实会被控制在O(logn)下提高效率.要好好想想,否则还挺难理解...
回复
LeeMaRS 2003-10-16
若想快排的效率稳定在O(nlogn),每次排序就要把数列分成大小相等(或差1)的两段.因此数列中的中位数是符合要求的.由于选出中位数有O(n)的算法,所以利用中位数就可以让快排的效率稳定在O(nlogn)上.

对于随机化的快排, 以前国家队有人写过论文讨论过的, 并给出了一些测试的结果, 最后结论是要比标准的快排要好上一些. 通过加入随机化的因素, 可以降低退化的机率. 算法导论上似乎也证明过这个. 我自己在实际的使用中也有相同的感受.

当然要想再次提高快排的效率, 在序列长度小于某一定值(据经验是12)时, 换用插入排序来对序列进行排序. STL中的快排似乎就是这样的. 但这样编程复杂度也增加了...对于我们这样必须手写快排的就亏本了, 所以也不考虑那么多了. 至于上面的那个程序, 也主要是起一个示范的作用, 实际中还是越简单的越好.

另外顺便提一个就是现在书上的快排算法真是让人心寒, 不存在BUG的真的很少见, 清华严蔚敏数据结构(PASCAL版)书上的原地置换的快排有严重缺陷, 当序列中所有元素相同时会让堆栈达到O(n)的深度, 而且每次排序后仅能将序列长度减少1. 王晓东的书上更是提出了"一定要取最后的元素为枢值, 否则排序不能完成"的惊人结论. 现在就是算法导论上的写的比较好了. 我也是花了好多时间才把随机化, 原地置换, 压制堆栈这几项加在一起的.
回复
ZhangYv 2003-10-16
对于用定长数组模拟堆栈来取消系统调用递归的效率,我有一个疑问.因为我做过试验,二叉树遍历的,非递归实现并不会比递归快... :O
取随机值的方法"据说"能有效避免极端情况出现,但是否真正有效偶没有看见一本书给出非常过明确的说法.举个例子吧,王晓东所有的书都说取随机值的很有效;但是Brian W.Kernighan写的<<The Practivce of Programming>>说随机快排的效率更低.
上次,上王晓东的课后忘记问问他咯....
回复
短歌如风 2003-10-16
LeeMaRS的方法确实有效。递归深度受控之后就可以考虑用一个定长数组模拟堆栈来取消递归调用了,这样速度还能快一些(如果不能控制深度,减少调用的好处会被动态内存管理的代价抵消)。

不过只控制递归深度对Quick Sort的改进还是意义不大,因为正常情况下Quick Sort的速度已经很快了,而较慢情况主要原因是比较和交换次数而不是递归深度。

枢轴取随机值的方法在面对基本有序序列和基本倒序序列时都还不如标准的Quick Sort,这两种情况是对Quick Sort改进时应该考虑的,因为与对Quick Sort不利的分布相比,它们在实际应用中出现的概率还要大一些。
回复
LeeMaRS 2003-10-15
Comp是比较函数, a < b -> Comp(a, b) = True, a > b -> Comp(a, b) = False.
回复
LeeMaRS 2003-10-15
今天写凸包极角排序的时候做的, 楼主的要求都有了, 顺带附送一个压制堆栈深度不超过O(logn)的, 呵呵, 大家顺便帮看看有什么地方能改得更好一些.

Procedure QSort(l, r : LongInt);
Var
i, j, q, t : LongInt;
x : TPoint;
Begin
While (l < r) Do
Begin
t := l + Random(r - l + 1);
x := P[t]; P[t] := P[l]; P[l] := x;
i := l; j := r;
While (i < j) Do
Begin
While (i < j) AND (Comp(x, P[j])) Do Dec(j);
If (i < j) Then Begin P[i] := P[j]; Inc(i); End;
While (i < j) AND (Comp(P[i], x)) Do Inc(i);
If (i < j) Then Begin P[j] := P[i]; Dec(j); End;
End;
q := i; P[i] := x;

If (r - q > q - l) Then
Begin
QSort(l, q - 1); l := q + 1;
End
Else
Begin
QSort(q + 1, r); r := q - 1;
End;
End;
End;
回复
短歌如风 2003-10-15
是作业题还是真的想改进Quick Sort?如果是想改进Quick Sort,我见过的最好方法还是Intro Sort。
枢轴用随机数的方法并没有什么改进,只是把最差分布与随机序列联系在一起了,出现的概率还是一样的。还不如取首、尾、中三元素的中间值。如果元素可以计算,取三元素的平均值会更好一些。还有一种方法更有效就是取三元素各三元素的两两平均值和三平均值的中间值。
“对枢轴记录最后定位”?不明白什么意思。
回复
kotton8848 2003-10-15
王晓东的《计算机算法设计与分析〉里说得非常具体
建议楼主去看看。。。。。
写出来不如自己去看看。。。。
回复
相关推荐
发帖
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
帖子事件
创建了帖子
2003-10-15 03:52
社区公告
暂无公告