I find this Quicksort partitioning approach confusing and wrong, yet it seems to work. I am referring to this pseudocode. Note: they also have a C implementation at the end of the article, but it's very different from their pseudocode, so I don't care about that.

I have also written it in C like this, trying to stay true to the pseudocode as much as possible, even if that means doing some weird C stuff:

However, this is wrong, isn't it? Clearly a[5] does not have all the values before it lower than it, since a[2] = 6 > a[5] = 4. Not to mention that 7 is supposed to be the pivot (the initial a[p]) and yet its position is both incorrect and lost.

... it seems to be a correct sorting algorithm. I tested it out on a lot of random inputs, including all 0-1 arrays of length 20.

I have also tried using this partition function for a selection algorithm, in which it failed to produce correct results. It seems to work and it's even very fast as part of the quicksort algorithm however.

So my questions are:

Can anyone post an example on which the algorithm DOESN'T work?

If not, why does it work, since the partitioning part seems to be wrong? Is this another partitioning approach that I don't know about?

4 Answers
4

I think the partitioning is correct. 7 is the pivot. The original array is partitioned into a sub array of length 5 containing elements less than or equal to 7 and a sub array of length 2, containing elements greater or equal to 7.

You mean it's correct because a[1..5] has elements <= 7 and a[6..7] has elements >= 7? That's true, but shouldn't the selected pivot reach its final position? According to my textbooks and wikipedia, it should.
–
IVladMay 21 '10 at 14:08

Yes. In the first link you gave, quicksort then proceeds to sort a[1..5] and a[6..7]. Only in the wikipedia link a[6] is required to have its final value of 7, as here a[1..5] and a[7..7] are sorted in the recursive calls.
–
HenrikMay 21 '10 at 14:23

Interesting, I didn't think about it like that. I always thought the partitioning algorithm is supposed to return the final position of the pivot element. Thanks for your explanation. I'll accept your answer a bit later to give others a chance to comment on this algorithm too.
–
IVladMay 21 '10 at 14:34

Yes, it works as Henrik has said, but it's a very wasteful way to do a quicksort to have the pivot sorted again. It has a different sort invariant than the wikipedia one ([ <= p | >= p] vs. [ <= p | > p]). The reason you don't generally see quicksorts done this way is that it isn't as efficient. Resorting the pivot will generate more stack calls as well as extra unnecessary comparisons (and probably swaps too).
–
Justin PeelMay 21 '10 at 15:47

@Justin Peel - actually, the first implementation seems to be much faster than the wiki one, even with random pivots. But that discussion is for another question :).
–
IVladMay 21 '10 at 16:33

From Wikipedia (I've emphasized the part that I think addresses your question directly):

This is the in-place partition
algorithm. It partitions the portion
of the array between indexes left and
right, inclusively, by moving all
elements less than or equal to
array[pivotIndex] to the beginning of
the subarray, leaving all the greater
elements following them. In the
process it also finds the final
position for the pivot element, which
it returns. It temporarily moves the
pivot element to the end of the
subarray, so that it doesn't get in
the way. Because it only uses
exchanges, the final list has the same
elements as the original list. Notice
that an element may be exchanged
multiple times before reaching its
final place. It should also be noted
that in case of pivot duplicates in
the input array, they can be spread
across left subarray, possibly in
random order. This doesn't represent a
partitioning failure, as further
sorting will reposition and finally
"glue" them together.

No, I don't see what that has to do with my question. That describes the algorithm that I said definitely works, I was asking why the first one also works. Plus, the first one does not find the final position of the pivot element, nor does it temporarily move anything.
–
IVladMay 21 '10 at 14:32

You are getting confused between the index of the item and the iten value

Look at your header

int partition(int a[], int p, int r) ;

Now if we changed the data type on the array a to some weird data type you will see the problem

int partition( Otherdatatype a[], int p, int r) ;

You call the function from within your main with

partition(a, 1, a[0]);

See the problem a[0] is the value of the entry in a[0] not an index value.

Imagine a[0] had the value 200 in your code simply change the first item value to 200 and you will get a runtime error "attempt to access memory out of range" because if you follow
thru a[0] = 200 that is passed into partition as value r then follow what happens inside partition.

The thing to remember is this is a sort routine in your partition header the list in array a may not be of the same type as the indexes .. p and r of your header are clearly indexes referring to an index position and a is the list to be sorted.

Thus your main start to a sort is

partition(a, 0, items_in_array-1);

Do you see why? Array a runs from a[0] ... a[items_in_array-1]

So in your sample above you have preloaded 8 values into your array so your partition call from main should be