如果更多重复键,快速排序算法改进

时间:2012-11-12 06:27:28

标签: c++ algorithm quicksort

我正在阅读Robert Sedwick算法和数据结构第1-4部分中的快速排序算法。

template <class item>

static void quicksort(item [] a, int l, int r)
{
    if(r <= l) return;
    int i = partition(a,l,r);
    quicksort(a, l, i-1);
    quicksort(a, i+1, r);
}

template <class item>
int partition(item a[], int l, int r)
{
    int i = l-1; j = r; item v = a[r];

    for(;;) {
        while( a[++i] < v );
        while( v < a[--j] ) 
            if( j == l ) 
                break;
        if( i >= j) 
            break;  // pointer crossing.
        exch(a[i], a[j]);
    }

    exch(a[i], a[r]);
    return i;
}

Book上面的算法有以下文字。

  

当文件中存在重复键时,指针交叉为   微妙。我们可以稍微改进分区过程   当i <1时终止扫描。 j,然后用j而不是i-1,   为第一个递归分隔左子文件的右端   呼叫。在这种情况下让循环迭代一次是一个   改进,因为,当扫描循环用j终止时   而且我指的是相同的元素,我们最终得到了两个元素   他们的最终位置:停止两次扫描的元素,必须   因此等于分区元素和分区   元素本身。这种变化可能是值得的,因为,在这   特殊情况下,程序会留下一个等于该键的记录   在[r]中分区键,这使得第一个分区成为   调用快速排序(a,i + 1,r)退化,因为它最右键是   最小的。

我的问题是

  1. 我们如何修改以上程序以及下面的描述?我很难修改它以理解文本。
  2. 如果存在更多重复的密钥,为什么上面的快速排序算法不能有效工作。
  3. 如果存在更多重复密钥,上述修改如何改进?
  4. 作者的意思是“他在调用快速排序(a,i + 1,r)中的第一个分区退化,因为它的最右键是最小的。” ?是什么 作者的意思是退化吗?
  5. 感谢您的时间和帮助。

1 个答案:

答案 0 :(得分:6)

&gt;&gt;如果存在更多重复键,为什么上面的快速排序算法无效?

由于您的违规条件是:if(i >= j) break;,因此效率低下
因此,当您使用ij从两侧进行扫描时,很可能在 i == j 时而不是让{{1超越i

存在许多重复键时}时,可能会发生错误

当你从第一个while循环中断j时,你必须有i==j和第二个while循环i==j;但是因为我们正在考虑'{break}':{{1}所以,a[i] >= va[j] <=vi==j相同,您的枢轴元素

在这种情况下,您最外面的a[i] = a[j] = v将简单地将枢轴值交换给自己。
因此,在你的下一个递归调用a[i]中,对于数组的右半部分,你将最小元素放在最右端。(你的枢轴选择策略就是v),我们都知道它QuickSort选择一个相当于数组最小值或最大值的pivot元素是不好的。因此,您对右半部分的后续递归调用将是退化调用 这就是为什么作者建议不要为 i == j 打破,而是在发生这种情况之前抓住它们。

&gt;&gt;作者在这里贬义是什么意思?

这里的退化意味着递归树变得偏斜,即后续问题不会产生几乎相等的大小。 您将大小为exch(a[i], a[r]);的问题划分为大小为quicksort(a, i+1, r);item v = a[r];的问题而不是更平衡的问题,例如将其划分为大小为N和{{}的问题1}}。

&gt;&gt;我们如何通过以下说明修改上述程序?

我们可以像下面这样实现它:

N-1

&gt;&gt;如果存在更多重复密钥,上述修改如何改进?
它通过让您不会生成退化案例的明显场景来提高性能。