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

Posted

技术标签:

【中文标题】如果更多重复键,则快速排序算法改进【英文标题】:quick sort algorithm improvement if more duplicate keys 【发布时间】:2012-11-12 06:27:27 【问题描述】:

我正在阅读 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;

本书有以下关于上述算法的文字。

当文件中存在重复键时,指针交叉是 微妙的。我们可以通过以下方式稍微改进分区过程 当 i

我的问题是

    我们如何修改上面的程序,描述如下?我很难修改它以理解文本。 如果存在更多重复键,为什么上述快速排序算法无法有效工作。 如果存在更多重复键,上述修改将如何改进? 作者所说的“他在调用快速排序(a, i+1, r) 中的第一个分区退化,因为它最右边的键是它的最小键”是什么意思。 ?做什么 作者在这里指的是退化?

感谢您的时间和帮助。

【问题讨论】:

@Clare Macrae:这不是家庭作业。我正在自读这本书,上面有一个问题。 【参考方案1】:

>>如果存在更多重复键,为什么上述快速排序算法无法有效工作? 它变得低效,因为您的中断条件是:if(i &gt;= j) break; 所以,当您使用 ij 从两侧扫描时,很有可能您会在 i == j 时中断,而不是让 i 超过 j . 当我们在i==j存在许多重复键时,可能会发生什么不好的

当您从第一个 while 循环中断 i==j; 时,您必须有 a[i] &gt;= v 和从第二个 while 循环 a[j] &lt;=v 但由于我们正在考虑为:i==j 进行“中断”,因此,a[i] = a[j] = v 即 @ 987654332@ 与v 相同,您的pivot 元素

在这种情况下,您最外层的exch(a[i], a[r]); 将简单地将枢轴值交换给自己。 因此,在您对数组右半部分的下一个递归调用 quicksort(a, i+1, r); 中,您将有最小元素位于最右端。(您的枢轴选择策略很简单,item v = a[r];)并且我们都知道这对 QuickSort 不利选择一个等于数组最小值或最大值的枢轴元素。因此,您随后对右半边的递归调用将是一个退化的。 这就是为什么作者建议不要为 i==j 而中断,而是在此之前抓住它们。 >>作者这里的退化是什么意思?

这里的退化意味着递归树变得倾斜,即后续问题不会产生几乎相等的大小。 您将N 大小的问题划分为N-11 大小的问题,而不是更平衡的问题,例如将其划分为N/2N/2 的大小问题。 >>如何修改上面的程序,描述如下?

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

int partition(int A[], int l, int r)
        int i=l-1, j=r, v = A[r];
        for(;;)
                while(A[++i] < v);
                while(A[--j] > v)
                        if(j == l)
                                break;
                if(i>=j)
                        break;
                swap(A[i], A[j]);
        
        if(i == j)// case when we stopped at the pivot element.
                j = j+1;//backtrack j 1 step.
                if(j <= r)
                    swap(A[j], A[r]);
                return j;// partition the subsequent problems around j now.
        
        swap(A[i], A[r]);
        return i;

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

【讨论】:

感谢您的帮助。但是作者提到我们在 i j 我还没到? 啊!我错过了这一点。你是对的,我们需要在 i 超过 j 之前打破!我们需要在这里做一些额外的检查。我正在编辑我的帖子。

以上是关于如果更多重复键,则快速排序算法改进的主要内容,如果未能解决你的问题,请参考以下文章

Java 快速排序算法的简单说明及实现

快速排序算法详解

《算法》笔记 5 - 快速排序

快速排序算法

排序算法-快速排序

数据结构和算法(十五)排序算法之快速排序