Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b705764

Browse files
committed
Tim's quicksort on May 10.
1 parent 01fc65d commit b705764

1 file changed

Lines changed: 99 additions & 68 deletions

File tree

Objects/listobject.c

Lines changed: 99 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -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

629638
static 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

Comments
 (0)