迭代快速排序方法的分区算法问题

Posted

技术标签:

【中文标题】迭代快速排序方法的分区算法问题【英文标题】:Partitioning algorithm issue with iterative quicksort method 【发布时间】:2018-05-15 07:35:44 【问题描述】:

原始问题的简短版本:我正在尝试转换此示例:http://programmertech.com/program/cpp/quick-sort-recursive-and-iterative-in-c-plus-plus 的迭代快速排序以使用向量而不是数组并开始简化一些事情。本来直接转换失败的,所以我一行一行的试了一遍,以便更好地理解,但是我的逻辑卡住了。

编辑:从问题中删除了所有内容,提供了我正在尝试的最小(不太有效)示例。这是我到目前为止所拥有的一切。我在纸上手工完成了这个,我摸得越多,它变得越糟,现在陷入无限循环(最初没有正确排序)。

这是我的想法:getMedian 正如我所写的那样,它应该交换枢轴值以及左右值,以便它们是有序的:left 。当我们进入 partition 算法中的 while (right > left) 循环时,它应该不断交换元素以将所有大于枢轴的元素放在它的右侧,以及那些在左边少的。堆栈跟踪仍然需要分区的 Sub(vectors)(在这种情况下)。但这似乎不起作用。我觉得好像我错过了对这项工作非常重要的东西。

#include <iostream>
#include <vector>

class QuickSort 
public:
    QuickSort(std::vector<int> toBeSorted) : toBeSorted(toBeSorted) 
    void sortVector();
    void print();
private:
    int partition(int left, int right);
    int getMedian(int left, int right);

    std::vector<int> toBeSorted;
;

// Iterative method using a stack
void QuickSort::sortVector() 
    int stack[toBeSorted.size()];
    int top = 0;
    stack[top++] = toBeSorted.size() - 1;
    stack[top++] = 0;

    int left, right, pivIndex;

    while (top > 0) 
        // Popping values for subarray
        left = stack[--top];
        right = stack[--top];
        pivIndex = partition(left, right);

        if (pivIndex + 1 < right) 
            stack[top++] = right;
            stack[top++] = pivIndex+1;
        

        if (pivIndex - 1 > left) 
            stack[top++] = pivIndex-1;
            stack[top++] = left;
        
    


int QuickSort::partition(int left, int right) 
    int pivotValue = getMedian(left, right);

    if (right - left > 1) 
    while (right > left) 
        while (toBeSorted[left] < pivotValue)  left++; 
        while (toBeSorted[right] > pivotValue)  right--; 

        if (toBeSorted[right] < toBeSorted[left]) 
            std::swap(toBeSorted[right], toBeSorted[left]);
            left++;
            right--;
        
    
     else 
        if (toBeSorted[right] < toBeSorted[left]) 
            std::swap(toBeSorted[right], toBeSorted[left]);
        
    
    return 0;


int QuickSort::getMedian(int left, int right) 
    int med = (right - left)/2;
    // if there are an even number of elements, instead of truncating
    // goto the rightmost value.
    if ((right - left)%2 != 0) 
        med = (right-left)/2 + 1;
    

    // Organise the elements such that 
    // values at indexes: left <= med <= right.
    if (toBeSorted[med] < toBeSorted[left]) 
        std::swap(toBeSorted[left], toBeSorted[med]);
    
    if (toBeSorted[right] < toBeSorted[left]) 
        std::swap(toBeSorted[left], toBeSorted[right]);
    
    if (toBeSorted[right] < toBeSorted[med]) 
        std::swap(toBeSorted[right], toBeSorted[med]);
    

    return toBeSorted[med];


void QuickSort::print() 
    for (int i = 0; i != toBeSorted.size(); i++) 
        std::cout << toBeSorted[i] << ",";
    
    std::cout << std::endl;


int main() 
    std::vector<int> values = 5, 8, 7, 1, 2, 5, 3;
    QuickSort *sorter = new QuickSort(values);
    sorter->sortVector();
    sorter->print();
    return 0;

【问题讨论】:

能否包含getMidPiv函数的实现? 也只是一个建议:将范围的 [begin, end) 迭代器传递给分区比传递索引和使用在函数的某些非局部范围下定义的向量更像 C++。 您需要包含一个完整的工作示例。你不能只说输出是 4 1 9 2,我们需要知道这里的输入和变量的初始状态......顺便说一句,为什么会有两个数组 listOfNums 和 data ? @eozd 我现在添加了 getMidPiv 代码,并进行了一些更正,抱歉在我尝试简化时出现了一些复制错误。 这仍然不是Minimum, Complete and Verifiable Example。什么是listOfIntspivot?有这么多像这样的非局部变量,很难推理代码并找出错误。 (编辑:显然现在没有data。) 【参考方案1】:

partition 方法中,您不应该在每次迭代中都使用swap(data[low], data[high])。你的错误是这部分。你可以这样做:

void partition(int left, int right) 
  // listOfNums is a vector
  int middle = getMidPiv(left, right);
  int low = left;
  int high = right-1;

  while (low < high) 
    while (listOfNums[low] < middle) 
      lower++;
    

    while (listOfNums[high] > middle) 
      high--;
    

    if (low < high) 
       swap(data[low], data[high]);
       low++;
       high--;
    
  

  // swap(data[low], data[high]); it is incorrect
  return low;

【讨论】:

分区不对部分进行排序,它只保证左边的每个数字 【参考方案2】:

在第一个内部 while 循环中,使用 low++ 代替 lower++ 并将函数的返回类型更改为 int

【讨论】:

以上是关于迭代快速排序方法的分区算法问题的主要内容,如果未能解决你的问题,请参考以下文章

快速排序分区以及优化方法

快速排序分区以及优化方法

Python实现快速排序算法

快速排序算法

学编程必须了解的排序算法——快速排序

常用算法-快速排序