按照
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()已经将一组数据处理好,不太可能回出现上面的情况。大家讨论一下我错在什么地方

解决方案 »

  1.   

    若开始选择
    pviot = dtArr[p];
    即待分组数据的第一个
    则分为<=, >=两部分的情况不会出现
    q < p的情况
    若pviot在待数组中随机选择一个
    则出现上述情况的几率要大得多(恰巧pviot为该组中最大一个)
    看来pviot的选择跟分组方式有很大关系自己up一下
    哪位说说我的分析对不对?
      

  2.   

    也许可以这样改一下:
    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;
      

  3.   

    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)
    他说是预防特殊情况能使算法顺利进行下去
    但是有必要这么麻烦吗?
    还是另外有什么特殊情况?
      

  4.   

    那么如果
    if (i<j)
    swap(dtArr[j], dtArr[i]);
    改成
    if (i<j)
    swap(dtArr[j], dtArr[i++]);
    呢?
    关于找pviot的问题,好像里面文章很多很多。但是总而言之是建立在概率的基础上的吧……在我印象中好像有人宣布了一种认为很好的找pviot的方法时总是那很多数据排序的效率来说明,但是毕竟找的数据总是有分布规律的(比如用计算机随机产生那么可能由于随机数的伪随机性会对某种排序方法产生适应性)。我看的一本算法书上就是把pviot单独分作一个集合,就相当于割成了3分来排序。