关于quick_sort中的partition问题

dot99 2003-10-30 09:11:11
按照
http://algorithm.myrice.com/algorithm/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm
所介绍的qsort算法
我写了下面的快速排序算法

typedef int DT;
#define smallenough 12
void qsort(DT*, int, int);
int partition(DT*, int, int);
void insert_sort(DT*, int, int);
DT select_pviot(DT*, int, int);
void swap(DT&, DT&);

void qsort(DT* dtArr, int p, int r)
{
int q;
if (r-p <= smallenough)
insert_sort(dtArr, p, r);
else {
q = partition(dtArr, p, r);
qsort(dtArr, p, q);
qsort(dtArr, q+1, r);
}
}

int partition(DT* dtArr, int p, int r)
{
DT pviot = select_pviot(dtArr, p, r);
int i, j;
i = p-1;
j = r+1;
while (1) {
do {
j--;
} while(dtArr[j] <= pviot); //cause err?
do {
i++;
} while(dtArr[i] >= pviot);
if (i<j)
swap(dtArr[j], dtArr[i]);
else if (j != r)
return j;
else
return j-1;
}

}

其把待分组数据分成了>=和<=两部分
然后递归求解
当数据“比较随机”的时候,算法可以顺利运行
但是,当我构造一个数组时,问题出来了
比如以下数据
0, 3, 2, 2, 3 [设第一个数的下标为m]
当pviot = 3时候
do {
j--;
} while(dtArr[j] <= pviot); //cause err?
将j移动到m-1
do {
i++;
} while(dtArr[i] >= pviot);
将i移动到m
然后return j;
再下一次递归调用时候
q = partition(dtArr, p, r);
qsort(dtArr, p, q); (A)
qsort(dtArr, q+1, r); (B)
由于q < p 所以(A)直接return
(B)就出现错误了 q+1 = p
还是call上次递归调用时候的p, r值
然后就一直递归下去了,直到stack overflow

如果将 cause err 的条件改为
while(dtArr[j] < pviot);
即分为< 和 >= 两部分
则不会出现问题

当然,这是在smallenough足够小(等于3)的情况下测试出来的,当smallenough够大的时候
嵌入的insert_sort()已经将一组数据处理好,不太可能回出现上面的情况。

大家讨论一下我错在什么地方







...全文
103 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
gambolgs 2003-11-03
  • 打赏
  • 举报
回复
那么如果
if (i<j)
swap(dtArr[j], dtArr[i]);
改成
if (i<j)
swap(dtArr[j], dtArr[i++]);
呢?
关于找pviot的问题,好像里面文章很多很多。但是总而言之是建立在概率的基础上的吧……在我印象中好像有人宣布了一种认为很好的找pviot的方法时总是那很多数据排序的效率来说明,但是毕竟找的数据总是有分布规律的(比如用计算机随机产生那么可能由于随机数的伪随机性会对某种排序方法产生适应性)。我看的一本算法书上就是把pviot单独分作一个集合,就相当于割成了3分来排序。
dot99 2003-11-01
  • 打赏
  • 举报
回复
再顶一下~~~是不是偶放错了地方~~好久不来了,以前的算法版不在了~~
carbon107 2003-10-31
  • 打赏
  • 举报
回复
up
我回去,给你看看
dot99 2003-10-31
  • 打赏
  • 举报
回复
up一下
没人讨论谁进来领个分,结了算了
dot99 2003-10-31
  • 打赏
  • 举报
回复
0,3,2,2,3
pviot=3
p,r分别指向头和尾
按楼上模拟
j==p
i==p
return j;
若pviot=2
0,3,2,2,3
j==r
i==p
swap
3,3,2,2,0
next loop
j==p+1
i==p
swap
3,3,2,2,0
next loop
好象死了啊~~~
一直在交换dtArr[p]和dtArr[p+1]

=============没有修饰的分割线===========

我的意思是想讨论一下
****pviot的选择和分类方式(分为<,>= 或<=,>=)的关系****
pviot采用random hit的方式
如果严格的分为不相交两个集合的话
那跟pvoit的选择似乎没有关系(我暂时没找到这样的可怕集合)
<<计算机算法基础>>这本书上面采用了一个巧妙的方法
对集合A(1:n)以A(m)分类时候,多分配一个空间A(n+1)
他说是预防特殊情况能使算法顺利进行下去
但是有必要这么麻烦吗?
还是另外有什么特殊情况?
gambolgs 2003-10-31
  • 打赏
  • 举报
回复
也许可以这样改一下:
i,j初值变为:
i = p;
j = r;

while (dtArr[j] <= pviot && j > i)
{
j--;
}
while(dtArr[i] >= pviot && i < j)
{
i ++;
}
if (i<j)
swap(dtArr[j], dtArr[i]);
else
return j;
dot99 2003-10-30
  • 打赏
  • 举报
回复
若开始选择
pviot = dtArr[p];
即待分组数据的第一个
则分为<=, >=两部分的情况不会出现
q < p的情况
若pviot在待数组中随机选择一个
则出现上述情况的几率要大得多(恰巧pviot为该组中最大一个)
看来pviot的选择跟分组方式有很大关系

自己up一下
哪位说说我的分析对不对?

19,469

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧