@@ -624,6 +624,15 @@ docompare(x, y, compare)
624624 return 0 ;
625625}
626626
627+ /* MINSIZE is the smallest array we care to partition; smaller arrays
628+ are sorted using a straight insertion sort (above). It must be at
629+ least 3 for the quicksort implementation to work. Assuming that
630+ comparisons are more expensive than everything else (and this is a
631+ good assumption for Python), it should be 10, which is the cutoff
632+ point: quicksort requires more comparisons than insertion sort for
633+ smaller arrays. */
634+ #define MINSIZE 12
635+
627636/* Straight insertion sort. More efficient for sorting small arrays. */
628637
629638static int
@@ -640,30 +649,23 @@ insertionsort(array, size, compare)
640649 register PyObject * key = * p ;
641650 register PyObject * * q = p ;
642651 while (-- q >= a ) {
643- register int k = docompare (* q , key , compare );
652+ register int k = docompare (key , * q , compare );
644653 /* if (p-q >= MINSIZE)
645654 fprintf(stderr, "OUCH! %d\n", p-q); */
646655 if (k == CMPERROR )
647656 return -1 ;
648- if (k <= 0 )
657+ if (k < 0 ) {
658+ * (q + 1 ) = * q ;
659+ * q = key ; /* For consistency */
660+ }
661+ else
649662 break ;
650- * (q + 1 ) = * q ;
651- * q = key ; /* For consistency */
652663 }
653664 }
654665
655666 return 0 ;
656667}
657668
658- /* MINSIZE is the smallest array we care to partition; smaller arrays
659- are sorted using a straight insertion sort (above). It must be at
660- least 2 for the quicksort implementation to work. Assuming that
661- comparisons are more expensive than everything else (and this is a
662- good assumption for Python), it should be 10, which is the cutoff
663- point: quicksort requires more comparisons than insertion sort for
664- smaller arrays. */
665- #define MINSIZE 10
666-
667669/* STACKSIZE is the size of our work stack. A rough estimate is that
668670 this allows us to sort arrays of MINSIZE * 2**STACKSIZE, or large
669671 enough. (Because of the way we push the biggest partition first,
@@ -682,8 +684,9 @@ quicksort(array, size, compare)
682684 PyObject * compare ;/* Comparison function object, or NULL for default */
683685{
684686 register PyObject * tmp , * pivot ;
685- register PyObject * * lo , * * hi , * * l , * * r ;
686- int top , k , n , n2 ;
687+ register PyObject * * l , * * r , * * p ;
688+ register PyObject * * lo , * * hi ;
689+ int top , k , n ;
687690 PyObject * * lostack [STACKSIZE ];
688691 PyObject * * histack [STACKSIZE ];
689692
@@ -699,88 +702,117 @@ quicksort(array, size, compare)
699702
700703 /* If it's a small one, use straight insertion sort */
701704 n = hi - lo ;
702- if (n < MINSIZE ) {
703- /*
704- * skip it. The insertion sort at the end will
705- * catch these
706- */
705+ if (n < MINSIZE )
707706 continue ;
708- }
709707
710- /* Choose median of first, middle and last item as pivot */
711-
712- l = lo + (n >>1 ); /* Middle */
713- r = hi - 1 ; /* Last */
708+ /* Choose median of first, middle and last as pivot;
709+ these 3 are reverse-sorted in the process; the ends
710+ will be swapped on the first do-loop iteration.
711+ */
712+ l = lo ; /* First */
713+ p = lo + (n >>1 ); /* Middle */
714+ r = hi - 1 ; /* Last */
714715
715- k = docompare (* l , * lo , compare );
716+ k = docompare (* l , * p , compare );
716717 if (k == CMPERROR )
717718 return -1 ;
718719 if (k < 0 )
719- { tmp = * lo ; * lo = * l ; * l = tmp ; }
720+ { tmp = * l ; * l = * p ; * p = tmp ; }
720721
721- k = docompare (* r , * l , compare );
722+ k = docompare (* p , * r , compare );
722723 if (k == CMPERROR )
723724 return -1 ;
724725 if (k < 0 )
725- { tmp = * r ; * r = * l ; * l = tmp ; }
726+ { tmp = * p ; * p = * r ; * r = tmp ; }
726727
727- k = docompare (* l , * lo , compare );
728+ k = docompare (* l , * p , compare );
728729 if (k == CMPERROR )
729730 return -1 ;
730731 if (k < 0 )
731- { tmp = * l ; * l = * lo ; * lo = tmp ; }
732- pivot = * l ;
732+ { tmp = * l ; * l = * p ; * p = tmp ; }
733733
734- /* Move pivot off to the side (swap with lo+1) */
735- * l = * (lo + 1 ); * (lo + 1 ) = pivot ;
734+ pivot = * p ;
736735
737736 /* Partition the array */
738- l = lo + 2 ;
739- r = hi - 2 ;
740737 do {
738+ tmp = * l ; * l = * r ; * r = tmp ;
739+ if (l == p ) {
740+ p = r ;
741+ l ++ ;
742+ }
743+ else if (r == p ) {
744+ p = l ;
745+ r -- ;
746+ }
747+ else {
748+ l ++ ;
749+ r -- ;
750+ }
751+
741752 /* Move left index to element >= pivot */
742- while (l < hi ) {
743- k = docompare (* l , pivot , compare );
753+ while (l < p ) {
754+ k = docompare (* l , pivot , compare );
744755 if (k == CMPERROR )
745756 return -1 ;
746- if (k >= 0 )
757+ if (k < 0 )
758+ l ++ ;
759+ else
747760 break ;
748- l ++ ;
749761 }
750762 /* Move right index to element <= pivot */
751- while (r > lo ) {
763+ while (r > p ) {
752764 k = docompare (pivot , * r , compare );
753765 if (k == CMPERROR )
754766 return -1 ;
755- if (k >= 0 )
767+ if (k < 0 )
768+ r -- ;
769+ else
756770 break ;
757- r -- ;
758- }
759-
760- /* If they crossed, we're through */
761- if (l <= r ) {
762- /* Swap elements and continue */
763- tmp = * l ; * l = * r ; * r = tmp ;
764- l ++ ; r -- ;
765771 }
766772
767- } while (l <= r );
768-
769- /* Swap pivot back into place; *r <= pivot */
770- * (lo + 1 ) = * r ; * r = pivot ;
773+ } while (l < r );
774+
775+ /* lo < l == p == r < hi-1
776+ *p == pivot
777+
778+ All in [lo,p) are <= pivot
779+ At p == pivot
780+ All in [p+1,hi) are >= pivot
781+
782+ Now extend as far as possible (around p) so that:
783+ All in [lo,r) are <= pivot
784+ All in [r,l) are == pivot
785+ All in [l,hi) are >= pivot
786+ This wastes two compares if no elements are == to the
787+ pivot, but can win big when there are duplicates.
788+ Mildly tricky: continue using only "<" -- we deduce
789+ equality indirectly.
790+ */
791+ while (r > lo ) {
792+ /* because r-1 < p, *(r-1) <= pivot is known */
793+ k = docompare (* (r - 1 ), pivot , compare );
794+ if (k == CMPERROR )
795+ return -1 ;
796+ if (k < 0 )
797+ break ;
798+ /* <= and not < implies == */
799+ r -- ;
800+ }
771801
772- /* We have now reached the following conditions:
773- lo <= r < l <= hi
774- all x in [lo,r) are <= pivot
775- all x in [r,l) are == pivot
776- all x in [l,hi) are >= pivot
777- The partitions are [lo,r) and [l,hi)
778- */
802+ l ++ ;
803+ while (l < hi ) {
804+ /* because l > p, pivot <= *l is known */
805+ k = docompare (pivot , * l , compare );
806+ if (k == CMPERROR )
807+ return -1 ;
808+ if (k < 0 )
809+ break ;
810+ /* <= and not < implies == */
811+ l ++ ;
812+ }
779813
780814 /* Push biggest partition first */
781- n = r - lo ;
782- n2 = hi - l ;
783- if (n > n2 ) {
815+ if (r - lo >= hi - l ) {
784816 /* First one is bigger */
785817 lostack [top ] = lo ;
786818 histack [top ++ ] = r ;
@@ -793,22 +825,21 @@ quicksort(array, size, compare)
793825 lostack [top ] = lo ;
794826 histack [top ++ ] = r ;
795827 }
796-
797828 /* Should assert top <= STACKSIZE */
798829 }
799830
800831 /*
801832 * Ouch - even if I screwed up the quicksort above, the
802833 * insertionsort below will cover up the problem - just a
803- * performance hit would be noticable.
834+ * performance hit would be noticable.
804835 */
805836
806837 /* insertionsort is pretty fast on the partially sorted list */
807838
808839 if (insertionsort (array , size , compare ) < 0 )
809840 return -1 ;
810-
811- /* Succes */
841+
842+ /* Success */
812843 return 0 ;
813844}
814845
0 commit comments