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

时间:2013-08-10 09:57:04

标签: c++ algorithm sorting iterator quicksort

我正在使用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());

没有错误,但无法对数字进行排序。

书中的伪代码如下所示。

  1. Quicksort(A,p,r)
  2. 如果p < [R
  3. q =分区(A,p,r)
  4. Quicksort(A,p,q-1)
  5. Quicksort(A,q + 1,r)

  6. 分区(A,p,r)

  7. x = A [r]
  8. i = p - 1
  9. 表示j = p到r - 1
  10. _ _ _i = i + 1;
  11. _ _ _exchange A [i]与A [j]
  12. 用A [r]
  13. 交换A [i + 1]
  14. return i + 1;
  15. 我的实施如下。

     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);
         }
     }
    

    有人对我的代码有任何想法吗?它有效,但不进行排序。 例如,如果我输入 shuffle: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,

2 个答案:

答案 0 :(得分: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&lt; 2)return”

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

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);

在考虑以上几点后,您应该能够正确排序。

答案 1 :(得分:1)

在几乎所有失败的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()实现中的另一个常见错误。

研究这些基础知识,你应该做得很好。