C++ 快速排序实现,没有正确的输出

Posted

技术标签:

【中文标题】C++ 快速排序实现,没有正确的输出【英文标题】:C++ Quick Sort Implementation, not having the right output 【发布时间】:2013-08-10 09:57:03 【问题描述】:

我正在实现 Cormen 算法书 (CLRS) 中的快速排序算法。

 vector<int> numbers = 5, 6, 3, 4, 1, 2, 7, 13, -6, 0, 3, 1, -2;

 My_Quick_Sort(numbers.begin(), numbers.end());

它没有错误,但它不能对数字进行排序。

书中的伪代码如下。

    快速排序(A、p、r) 如果 p q = 分区(A, p, r) 快速排序(A, p, q-1)

    快速排序(A, q+1, r)

    分区(A,p,r)

    x = A[r] i = p - 1 对于 j = p 到 r - 1 ___i= i+1; ___用 A[j] 交换 A[i] 用 A[r] 交换 A[i+1] 返回 i + 1;

我的实现如下。

 template<typename T>
 void Swap(T a, T b)
 
     typedef typename std::iterator_traits<T>::value_type value_type;
     value_type temp;
     temp = *a;
     *a = *b;
     *b = temp;
 

 template<typename T>
 int Partition(T begin, T end)
 
     typedef typename std::iterator_traits<T>::value_type value_type;
     value_type x;
         x = *end;
     T i = begin - 1;
     T j;
     for(j = begin; j != end+1; ++j)
     
         if ( x >= *j )
         
              i++;
              Swap(i, j);
         
         Swap(i+1, end);
     
     return static_cast<int>(distance(begin, i) + 1);
 

 template<typename T>
 void Q_Sort(T begin, T end)
 
     auto length = end - begin;
     if (length < 2) return;

     if ( begin != end )
     
         auto pivot = Partition(begin, end);
         Q_Sort(begin, begin + pivot - 1);
         Q_Sort(begin + pivot + 1, end);
     
 

有人知道我的代码吗?它有效,但不进行排序。 例如,如果我输入 随机播放:13、0、-6、6、-2、5、4、3、1、1、3、2、7、

输出如下 My_Quick_Sort: -6, -2, 0, 6, 13, 0, 5, 1, 1, 4, 2, 3, 7,

【问题讨论】:

嗨。要求人们发现代码中的错误并不是特别有效。您应该使用调试器(或添加打印语句)来隔离问题,方法是跟踪程序的进度,并将其与您期望发生的情况进行比较。一旦两者发生分歧,那么您就发现了您的问题。 为什么不使用std::qsort() 我想练习实现递归和迭代器,这就是我不使用qsort的原因。问题是我没有收到任何错误消息,所以很难发现我错过了什么。 Q_Sort(begin, begin + pivot - 1);Q_Sort(begin + pivot + 1, end); - begin + pivot 什么时候排序? 没有错误,但是无法对数字进行排序 LOL 【参考方案1】:

关于您的实施的几点说明:

首先,为了简化您的 Q_Sort 方法和逻辑,我将从分区方法返回一个迭代器,而不是一个 int。这将简化 Q_Sort 如下:

template<typename T>
void Q_Sort(T begin, T end)

    if ( begin < end )
    
        T pivot = Partition(begin, end);
        Q_Sort(begin, pivot - 1);
        Q_Sort( pivot + 1, end);
    

请注意不需要勾选“if (length

其次,在 for 循环中的分区方法中,您的终止条件“j!= end+1”与伪代码不匹配。它应该是 end - 1。这是 Partition 方法的新代码。请注意,我假设第二个参数(end)指向实际的最后一个值,而不是指向最后一个以外的值。

template<typename T>
T Partition(T begin, T end)

    typedef typename std::iterator_traits<T>::value_type value_type;
    value_type x;

    x = *end;
    T i = begin - 1;

    for(T j = begin; j < end; ++j)
    
        if ( x >= *j )
        
            i++;
            Swap(i, j);
        
    

    Swap(i+1, end);
    //return static_cast<int>(distance(begin, i) + 1);
    return i+1;

最后,我相信伪代码假定第二个参数是最后一个元素,但迭代器 numbers.end() 指向最后一个元素之外的位置。因此,您需要将调用更改为快速排序,如下所示:

vector<int>::iterator iterEnd = numbers.end();
--iterEnd;
Q_Sort(numbers.begin(), iterEnd);

考虑以上几点你应该可以正确排序了。

【讨论】:

很好的建议,但请注意,她/他将其称为My_Quick_Sort(numbers.begin(), numbers.end());,并且调用Partition(begin, end);,因此最后一个参数Partition() 必须指示范围的过去结束(像往常一样)而不是实际最后一个元素的迭代器。这意味着另一个错误:对Q_Sort() 的第一个递归调用应该是Q_Sort(begin, begin + pivot); 当我们像你所说的My_Quick_Sort(numbers.begin(), numbers.end()); 那样使用 numbers.end() 调用 My_Quick_sort 时,第一次调用 Partition(begin,end) 将导致 Partition 方法内部的逻辑错误在 @987654330 行@。此时 end 指向最后一个元素之后的一个,并且 x 的值将是错误的。 可能是的。我可能第一次看错了你的回复。既然你同意我的回复,那就意味着我同意你的看法:) 是的,这可行,但我必须进行一些更棘手的修改。谢谢!【参考方案2】:

在几乎所有失败的 quicksort() 算法中,压倒性的罪魁祸首是分区算法未能正确排除枢轴槽或其中低侧和高侧的不正确数学。这没有什么不同。 See an example live 进行就地分区。

在您的情况下,我会确保您的分区算法假定被分区的区域从 begin 开始并在元素 之前end 结束。换句话说:

for(j = begin; j != end+1; ++j)

应该是这样的:

for(j = begin; j != end; ++j)

quicksort() 失败的第二个压倒性原因是未能从上一次分区运行中跳过仅枢轴。如果你做了之前代码中提到的正确的事情,那么这个:

 auto pivot = Partition(begin, end);
 Q_Sort(begin, begin + pivot - 1);  // <<=== -1 should not be here.
 Q_Sort(begin + pivot + 1, end);

实际上应该是这样的:

 auto pivot = Partition(begin, end);
 Q_Sort(begin, begin + pivot);
 Q_Sort(begin + pivot + 1, end);

请记住,C++ 迭代器运行到end(),这是您想要的最后一个元素之后的第一个元素,因此不需要-1。给定一个序列,例如。

int ar[] =  5,6,2,7,9,8 

假设枢轴槽位于第四个槽(pivot=3),那么

 Q_Sort(begin, begin + pivot);    // includes 5,6,2, NOT 7
 Q_Sort(begin + pivot + 1, end);  // includes 9,8, again, NOT 7

我知道这可能看起来很奇怪,但如果您不小心不想跳过枢轴槽,那么调用将如下所示:

 Q_Sort(begin, begin + pivot);   // beginning through (pivot-1)
 Q_Sort(begin + pivot, end);     // pivot through end

这是 quicksort() 实现中的另一个常见错误。

在这些基础上努力,你应该会很好。

【讨论】:

很好,但请注意,如果您建议 Partition() 将其第二个参数解释为最后一个元素的位置(而不是 C++ 迭代器通常的情况下的最后一个) ),那么对Partition() 的初始调用是错误的,应更改为auto pivot = Partition(begin, end - 1);

以上是关于C++ 快速排序实现,没有正确的输出的主要内容,如果未能解决你的问题,请参考以下文章

C++ 随机化快速排序 最简单易懂的代码! 基于归并分区思想实现

C++ 快速排序算法

快速排序

洛谷 P1177 模板快速排序 快速排序/multiset排序

洛谷 1177 模板快速排序

洛谷——P1177 模板快速排序