快速排序 - 中间枢轴实现奇怪的行为

Posted

技术标签:

【中文标题】快速排序 - 中间枢轴实现奇怪的行为【英文标题】:Quick Sort - Middle Pivot implementation strange behaviour 【发布时间】:2015-11-20 23:25:31 【问题描述】:

我正在尝试使用在线提供的各种教程以枢轴值作为向量的中间元素来实现快速排序。 即使它适用于某些样本,也有一个我无法获得已排序的向量。

示例 - 输入 5,3,8,6,1,0,4 但输出为 0,3,4,5,1,6,8

快速排序实现

void quickSortMiddle(vector<int> &a, int left, int right)

    if(left >=right) return;

    int leftI = left;
    int rightI = right;

    int pivot = left + (right - left)/2;

    while(leftI<=rightI)
    
        while(a[leftI] < a[pivot] )leftI++;
        while(a[rightI] > a[pivot])rightI--;

        if(leftI <=rightI)
        
            swap(a[leftI], a[rightI]);
            leftI++;
            rightI--;
        
    

    if(left <= rightI)quickSortMiddle(a,left,rightI);
    if(leftI <= right)quickSortMiddle(a,leftI,right);

以下是我在每次实施后得到的输出

5340168

0345168

0345168

0345168

final : 
0345168

【问题讨论】:

你试过调试了吗? 是的。我认为当左右索引在同一个元素上时,即 1,那就是它不起作用的时候。 问题是一旦leftI或rightI等于pivot,交换[leftI]和[rightI]会改变[pivot]的值。您需要将 [pivot] 复制到单独的变量中。 (或者,如果复制数组元素的成本很高,请修改枢轴以指向交换后枢轴所在的位置)。 是的,我后来被@rcgldr 指出后才意识到这一点。我会记住的。感谢您的帮助。 【参考方案1】:

问题在于使用 a[pivot] 而不是设置 pivot = a[left + (right - left)/2]。您使用此修复的版本:

void quickSortMiddle(vector<int> &a, int left, int right)

    if(left >=right) return;
    int leftI = left;
    int rightI = right;
    int pivot = a[left + (right - left)/2]; // set pivot to value
    while(leftI<=rightI)
    
        while(a[leftI]  < pivot )leftI++;   // use pivot by value
        while(a[rightI] > pivot )rightI--;  // use pivot by value
        if(leftI <=rightI)
        
            swap(a[leftI], a[rightI]);
            leftI++;
            rightI--;
        
    
    if(left < rightI)quickSortMiddle(a,left,rightI); // < not <=
    if(leftI < right)quickSortMiddle(a,leftI,right); // < not <=

标准 Hoare 分区方案,尽管您的版本与枢轴修复一起工作正常:

void quickSortMiddle(vector<int> &a, int left, int right)

    if(left >= right) return;
    int pivot = a[left + (right - left)/2];
    int leftI = left-1;
    int rightI = right+1;
    while(1)
    
        while(a[++leftI] < pivot);
        while(a[--rightI] > pivot);
        if(leftI >= rightI)break;
        swap(a[leftI], a[rightI]);
    
    quickSortMiddle(a,left,rightI);
    quickSortMiddle(a,rightI+1,right);

【讨论】:

是的。非常感谢。这花了很多时间。

以上是关于快速排序 - 中间枢轴实现奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

C++ 向量快速排序 - 似乎对不同的枢轴有不同的工作方式

使用第一个元素作为枢轴进行快速排序[关闭]

快速排序:选择枢轴

C++ 快速排序枢轴优化

Java实现快速排序

快速排序从入门到精通