首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++快速排序实现,没有正确的输出

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

Stack Overflow用户
提问于 2013-08-10 09:57:03
回答 2查看 1.5K关注 0票数 1

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

代码语言:javascript
复制
 vector<int> numbers = {5, 6, 3, 4, 1, 2, 7, 13, -6, 0, 3, 1, -2};

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

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

书中的伪代码如下所示。

  1. 快速排序(A,p,r)
  2. 若p
  3. Q=划分(A,p,r)
  4. 快速排序(A,p,q-1)
  5. 快速排序(A,q+1,r)
  6. 划分(A,p,r)
  7. X= Ar
  8. I=p-1
  9. 对于j=p到r-1
  10. _____i= i+1;
  11. _____exchange Ai与Aj
  12. 与Ar交换Ai+1
  13. 返回I+ 1;

我的实现如下所示。

代码语言:javascript
复制
 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,

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-08-10 12:18:37

关于您的实现的几个注意事项:

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

代码语言:javascript
复制
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);
    }
}

请注意,您不需要检查“如果(长度< 2)返回;”

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

代码语言:javascript
复制
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()指向最后一个元素之后的位置。因此,您需要将调用更改为快速排序,如下所示:

代码语言:javascript
复制
vector<int>::iterator iterEnd = numbers.end();
--iterEnd;
Q_Sort(numbers.begin(), iterEnd);

在考虑了上述各点之后,您应该能够正确地排序。

票数 1
EN

Stack Overflow用户

发布于 2013-08-10 12:50:29

在几乎所有失败的快速排序()算法中,最主要的罪魁祸首是分区算法,该算法未能正确地排除枢轴槽或其中低端和高下的不正确的数学。这也没什么不同。执行就地分区的见活生生的例子

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

代码语言:javascript
复制
for(j = begin; j != end+1; ++j)

应该是这样:

代码语言:javascript
复制
for(j = begin; j != end; ++j)

导致快速排序()失败的第二个主要原因是未能跳过上次分区运行中的支点。如果您做了前面代码中提到的正确的事情,那么如下所示:

代码语言:javascript
复制
 auto pivot = Partition(begin, end);
 Q_Sort(begin, begin + pivot - 1);  // <<=== -1 should not be here.
 Q_Sort(begin + pivot + 1, end);

实际上应该是这样:

代码语言:javascript
复制
 auto pivot = Partition(begin, end);
 Q_Sort(begin, begin + pivot);
 Q_Sort(begin + pivot + 1, end);

记住,C++迭代器运行到end(),这是继最后一个您想要的元素之后的第一个元素,所以需要使用No-1。给定一个序列,如。

代码语言:javascript
复制
int ar[] = { 5,6,2,7,9,8 }

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

代码语言:javascript
复制
 Q_Sort(begin, begin + pivot);    // includes 5,6,2, NOT 7
 Q_Sort(begin + pivot + 1, end);  // includes 9,8, again, NOT 7

我知道这听起来有些奇怪,但如果你不小心不想跳过枢轴插槽,那么调用将是这样的:

代码语言:javascript
复制
 Q_Sort(begin, begin + pivot);   // beginning through (pivot-1)
 Q_Sort(begin + pivot, end);     // pivot through end

这是快速排序()实现中的另一个常见错误。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18160762

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档