0

So I have this function that sorts on a pivot, the issue I'm having is getting the pivot to switch with the middle number once it reaches it, it sorts the right side of numbers and left side of numbers between the pivot, yet once it reaches the center it doesnt cross over. I think it has something to do with my while loop. Help please!

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;
}
6
  • Why don't you use STL sort instead of writing your own? Commented Apr 29, 2013 at 16:22
  • 6
    @hd1 Because the assignment likely is "implement quick-sort"; not "use std::sort". Just a guess. Commented Apr 29, 2013 at 16:23
  • Then, perhaps the BSD qsort code will be of assistance Commented Apr 29, 2013 at 16:25
  • In addressing the issue at hand, William, does it make any sense to continue the outer-while-loop once left has reached right? Likewise, does it make any sense to perform the swap(left,right) inside the while-loop if left has reached right? Think about that for a bit. (and your left and right initialization are in the wrong place. They need to be outside the main while-loop. Commented Apr 29, 2013 at 16:33
  • 1
    I highly recommend changing the function name as qsort is a library method and things will be very confusing when linking functions. Commented Apr 29, 2013 at 16:35

1 Answer 1

1

The WHAT GOES HERE is not the only concern you should have with this code. There are a number of issues that will likely crop up.

First, your left-ptr and right-ptr initializers are NOT supposed to be inside the loop; they need to be part of the setup before the outer-while. Your function preamble should look something like this:

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

Next WHAT GOES HERE is the limiter that finally stops the madness of you're while-loop. Traditionally it is simply this:

while (left < right)

As soon as your left-ptr catches up to your right pointer (or vice-versa), there is no longer any need to continue the loop. Remember, all values to the left of the left-ptr are known to be less than (and potentially equal to, but we'll get there in a minute) the pivot. Likewise, all values to the right of the right-ptr are known to be greater than the pivot. The idea behind a collapsing pivot-window is you never actually swap until you have two items that need to exchange places.

Which bring us to the inner while-loops.

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

The fundamental problem with this is what happens when *left and *right happen to run into the pivot value at the same time (in two different slots). They both stop, then they both do this:

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

then the loop continues. The next time around both loops will immediately terminate (since they're both sitting on a pivot value, they'll come back to the swap, switch them again, and repeat this... forever. To solve this, one of those pointers must include the pivot as an allowable walk-over. Further only swap if left-ptr is still less than 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);

Note: this uses the std::swap() function, a most-handy utility.

Finally, the piece that is missing from the bottom, the recursion. We recurse into the two sections we just identified with our walkers, but only after assuring the bottom partition and top partition are indeed separate.

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

Putting it all together, along with a sample program that tests it:

Sample Program

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

Sample Output

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 

I hope this answers some of your questions about how a general quicksort works. Personally I prefer the single-ended in-place scanning version. I find it much easier to explain, and certainly much easier to understand. If you want to see it let me know.

Sign up to request clarification or add additional context in comments.

2 Comments

Good explanation. @Da11aS: Perhaps this Quicksort wiki may also help
@hr_117 Absolutely. In fact, the wiki's in-place algorithm is the one I prefer for what I believe to be a much easier-to-understand algorithm. It is definitely easier for beginners since there is only one directional scan with a trailing pivot slot for the final resting place of the pivot value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.