排序函数 C++

Posted

技术标签:

【中文标题】排序函数 C++【英文标题】:Sorting Function C++ 【发布时间】:2013-04-29 16:21:20 【问题描述】:

所以我有这个对枢轴进行排序的功能,我遇到的问题是让枢轴在到达中间数字后切换到它,它在枢轴之间对数字的右侧和数字的左侧进行排序,但一旦到达中心,它就不会越过。我认为这与我的 while 循环有关。请帮忙!

void qsort(int *arry, unsigned int size);

int main()

   int arry[] = 45, 27, 82, 21, 63, 22, 35, 19, 4, 5;

   qsort(arry, 10);


   system("pause");
   return 0;



void qsort(int *arry, unsigned int size)

   int piv = *arry;
   int *left, *right, temp;  // create the traversal pointers
   if (size > 1)
   


      while(WHAT GOES HERE?!)
      

         left  = arry + 1;
         right = arry + (size - 1);


          //process left pointer for value larger than piv.
          while((*left < piv) && (left < right))
          
              ++left;
          
          cout << *left << endl;

          //process right pointer for value smaller tham piv
          while((*right > piv) && (right > left ))
          
              right--;
          
          cout << *right << endl;
          temp   = *left;
          *left  = *right;
          *right = temp;
       

     //How do I verify the placement of the pivot value?
   for(unsigned int i=0; i < size; i++)
      cout << arry[i] << " ";
   cout << endl;

【问题讨论】:

为什么不用STL sort 而不是自己写呢? @hd1 因为赋值可能是“实现快速排序”;不是“使用 std::sort”。只是猜测。 那么,the BSD qsort 代码可能会有所帮助 在解决手头的问题时,William,一旦left 达到right,继续外循环是否有意义?同样,如果 left 已经到达 right,在 while 循环 inside 中执行 swap(left,right) 是否有意义?想一想。 (并且您的左右初始化位置错误。它们需要在主while循环之外 我强烈建议更改函数名称,因为qsort 是一个库方法,链接函数时会很混乱。 【参考方案1】:

这里的内容并不是您应该关注此代码的唯一问题。可能会出现许多问题。

首先,你的 left-ptr 和 right-ptr 初始化器不应该在循环内;他们需要在外部时间之前成为设置的一部分。您的函数序言应如下所示:

void quicksort(int *arry, size_t size)

    if (size <= 1)  // skip 1-length lists.
        return;

    // since you're using a static pivot location, 
    //  may as well use the one at the right end.
    int *left = arry;
    int *right = arry + (size-1);

    // choose a pivot value. ideally a random trio is chosen, and the
    //  middle element of those three is selected. for this simple case
    //  we're using the element at the right-most location of the list
    int piv = arry[size-1];

接下来要做的是限制器,它最终阻止了你的疯狂循环。传统上就是这样:

while (left < right)

只要你的左指针追上你的右指针(反之亦然),就不再需要继续循环了。请记住,left-ptr 左侧的所有值都已知小于(并且可能等于,但我们将在一分钟内到达)枢轴。同样,已知 right-ptr 右侧的所有值都大于枢轴。折叠枢轴窗口背后的想法是,在您有 两个 需要交换位置的项目之前,您永远不会真正交换

这将我们带到内部的while循环。

  //process left pointer for value larger than piv.
  while((*left < piv) && (left < right))
      ++left;

  //process right pointer for value smaller tham piv
  while((*right > piv) && (right > left ))
      right--;

基本问题是当*left *right 碰巧同时(在两个不同的插槽中)遇到枢轴值时会发生什么。他们都停下来,然后他们都这样做:

temp   = *left;
*left  = *right;
*right = temp;

然后循环继续。下一次围绕这两个循环将立即终止(因为它们都位于一个枢轴值上,它们将返回交换,再次切换它们,然后重复这个......永远。为了解决这个问题,这些指针之一必须将枢轴作为允许的遍历。此外,仅当 left-ptr 仍小于 right-ptr 时才交换。

// walk up until we find a value strictly larger than the pivot
while(left < right && (*left <= piv))
    ++left;

// walk down until we find a value smaller than the pivot
while (right > left && (*right > piv))
    --right;

if (left < right)
    swap(*left, *right);

注意:这使用了std::swap() 函数,这是一个最方便的实用程序。

最后,最底层缺失的部分,即递归。我们递归到我们刚刚确定的步行者的两个部分,但只有在确保底部分区和顶部分区确实是分开的之后。

// make sure left and right are properly ordered.
if (left > right)
    swap(left,right);

// sort subslices
quicksort(arry, (left - arry));
quicksort(arry + (right - arry), size - (right - arry));

将它们放在一起,以及一个测试它的示例程序:

示例程序

#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <cstdlib>
#include <ctime>
using namespace std;

// in-place quicksort.
void quicksort(int *arry, size_t size)

    if (size <= 1)
        return;

    // since you're using a static pivot location,
    //  may as well use the one at the right end.
    int *left = arry;
    int *right = arry + (size-1);

    // choose a pivot value. ideally a random trio is chosen, and the
    //  middle element of those three is selected. for this simple case
    //  we're using the element at the right-most location of the list
    int piv = arry[size-1];

    while(left < right)
    
        // walk up until we find a value strictly larger than the pivot
        while(left < right && (*left <= piv))
            ++left;

        // walk down until we find a value smaller than the pivot
        while (right > left && (*right > piv))
            --right;

        if (left < right)
            swap(*left, *right);
    

    // make sure left and right are properly ordered.
    if (left > right)
        swap(left,right);

    // sort subslices
    quicksort(arry, (left - arry));
    quicksort(arry + (right - arry), size - (right - arry));


int main()

    int arry[] = 45, 27, 82, 21, 63, 22, 35, 19, 4, 5;

    // before picture
    std::copy(arry, arry+10, ostream_iterator<int>(cout, " "));
    cout << endl;
    quicksort(arry, 10);

    // after picture
    std::copy(arry, arry+10, ostream_iterator<int>(cout, " "));
    cout << endl;

    std::srand((unsigned)std::time(0));
    std::vector<int> vals(30);
    for (size_t i=0;i<15;++i)
        vals[i] = vals[15+i] = int(i+1);
    std::random_shuffle(vals.begin(), vals.end());

    // before picture
    std::copy(vals.begin(), vals.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    quicksort(vals.data(), vals.size());

    // after picture
    std::copy(vals.begin(), vals.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    return 0;

样本输出

45 27 82 21 63 22 35 19 4 5 
4 5 19 21 22 27 35 45 63 82 
14 9 2 1 3 11 8 4 12 15 10 13 5 3 2 11 14 7 7 12 8 15 6 9 6 5 10 4 13 1 
1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 

我希望这能回答您关于一般快速排序如何工作的一些问题。我个人更喜欢单端就地扫描版本。我发现它更容易解释,当然也更容易理解。如果你想看,请告诉我。

【讨论】:

很好的解释。 @Da11aS:也许这个Quicksort wiki 也有帮助 @hr_117 绝对。事实上,wiki 的就地算法是我更喜欢的一种,因为我认为它是一种更容易理解的算法。这对初学者来说肯定更容易,因为只有一个方向扫描,带有一个尾随枢轴槽,用于枢轴值的最终静止位置。

以上是关于排序函数 C++的主要内容,如果未能解决你的问题,请参考以下文章

C++:排序函数

c++ sort 函数能对类或者结构体进行排序吗

插入排序函数行为怪异 C++

C++排序函数

带有矢量对象 C++ 的快速排序函数

使用非静态成员函数的 C++ 排序向量