Kaydet (Commit) 3176bb1d authored tarafından Guido van Rossum's avatar Guido van Rossum

Some more tuning of quicksort: use pointers instead of indexing.

üst 042a2070
...@@ -609,19 +609,20 @@ insertionsort(array, size, compare) ...@@ -609,19 +609,20 @@ insertionsort(array, size, compare)
object *compare;/* Comparison function object, or NULL for default */ object *compare;/* Comparison function object, or NULL for default */
{ {
register object **a = array; register object **a = array;
register int i; register object **end = array+size;
register object **p;
for (i = 1; i < size; i++) { for (p = a+1; p < end; p++) {
register object *key = a[i]; register object *key = *p;
register int j = i; register object **q = p;
while (--j >= 0) { while (--q >= a) {
register int k = docompare(a[j], key, compare); register int k = docompare(*q, key, compare);
if (k == CMPERROR) if (k == CMPERROR)
return -1; return -1;
if (k <= 0) if (k <= 0)
break; break;
a[j+1] = a[j]; *(q+1) = *q;
a[j] = key; /* For consistency */ *q = key; /* For consistency */
} }
} }
...@@ -629,7 +630,9 @@ insertionsort(array, size, compare) ...@@ -629,7 +630,9 @@ insertionsort(array, size, compare)
} }
/* MINSIZE is the smallest array we care to partition; smaller arrays /* MINSIZE is the smallest array we care to partition; smaller arrays
are sorted using a straight insertion sort (above). */ are sorted using a straight insertion sort (above). You may want
to play with this to tune it for your system. It must be at least
2; more than 20 probably doesn't make sense. */
#define MINSIZE 10 #define MINSIZE 10
/* STACKSIZE is the size of our work stack. A rough estimate is that /* STACKSIZE is the size of our work stack. A rough estimate is that
...@@ -649,64 +652,66 @@ quicksort(array, size, compare) ...@@ -649,64 +652,66 @@ quicksort(array, size, compare)
int size; /* Number of elements to sort */ int size; /* Number of elements to sort */
object *compare;/* Comparison function object, or NULL for default */ object *compare;/* Comparison function object, or NULL for default */
{ {
register object **a, *tmp, *pivot; register object *tmp, *pivot;
register int n, l, r, k; register object **lo, **hi, **l, **r;
int top, i, j, n2; int top, k, n, n2;
object **astack[STACKSIZE]; object **lostack[STACKSIZE];
int nstack[STACKSIZE]; object **histack[STACKSIZE];
/* Start out with the whole array on the work stack */ /* Start out with the whole array on the work stack */
astack[0] = array; lostack[0] = array;
nstack[0] = size; histack[0] = array+size;
top = 1; top = 1;
/* Repeat until the work stack is empty */ /* Repeat until the work stack is empty */
while (--top >= 0) { while (--top >= 0) {
a = astack[top]; lo = lostack[top];
n = nstack[top]; hi = histack[top];
/* If it's a small one, use straight insertion sort */ /* If it's a small one, use straight insertion sort */
n = hi - lo;
if (n < MINSIZE) { if (n < MINSIZE) {
if (insertionsort(a, n, compare) < 0) if (insertionsort(lo, n, compare) < 0)
return -1; return -1;
continue; continue;
} }
/* Choose median of a[0], a[n/2], a[n-1] as pivot */ /* Choose median of first, middle and last item as pivot */
i = n>>1;
j = n-1; l = lo + (n>>1); /* Middle */
k = docompare(a[0], a[i], compare); r = hi - 1; /* Last */
k = docompare(*lo, *l, compare);
if (k == CMPERROR) if (k == CMPERROR)
return -1; return -1;
if (k < 0) if (k < 0)
{ tmp = a[0]; a[0] = a[i]; a[i] = tmp; } { tmp = *lo; *lo = *l; *l = tmp; }
k = docompare(a[j], a[i], compare); k = docompare(*r, *l, compare);
if (k == CMPERROR) if (k == CMPERROR)
return -1; return -1;
if (k < 0) if (k < 0)
{ tmp = a[j]; a[j] = a[i]; a[i] = tmp; } { tmp = *r; *r = *l; *l = tmp; }
k = docompare(a[j], a[0], compare); k = docompare(*r, *lo, compare);
if (k == CMPERROR) if (k == CMPERROR)
return -1; return -1;
if (k < 0) if (k < 0)
{ tmp = a[j]; a[j] = a[0]; a[0] = tmp; } { tmp = *r; *r = *lo; *lo = tmp; }
pivot = a[0]; pivot = *lo;
/* Partition the array */ /* Partition the array */
l = 0; l = lo;
r = n; r = hi;
for (;;) { for (;;) {
/* Move left index to element > pivot */ /* Move left index to element > pivot */
while (++l < n) { while (++l < hi) {
k = docompare(a[l], pivot, compare); k = docompare(*l, pivot, compare);
if (k == CMPERROR) if (k == CMPERROR)
return -1; return -1;
if (k > 0) if (k > 0)
break; break;
} }
/* Move right index to element < pivot */ /* Move right index to element < pivot */
while (--r > 0) { while (--r > lo) {
k = docompare(a[r], pivot, compare); k = docompare(*r, pivot, compare);
if (k == CMPERROR) if (k == CMPERROR)
return -1; return -1;
if (k < 0) if (k < 0)
...@@ -716,40 +721,41 @@ quicksort(array, size, compare) ...@@ -716,40 +721,41 @@ quicksort(array, size, compare)
if (r < l) if (r < l)
break; break;
/* Swap elements and continue */ /* Swap elements and continue */
{ tmp = a[l]; a[l] = a[r]; a[r] = tmp; } { tmp = *l; *l = *r; *r = tmp; }
} }
/* Move the pivot into the middle */ /* Move the pivot into the middle */
{ tmp = a[0]; a[0] = a[r]; a[r] = tmp; } { tmp = *lo; *lo = *r; *r = tmp; }
/* We have now reached the following conditions: /* We have now reached the following conditions:
0 <= r < l <= n lo <= r < l <= hi
all x in a[0:r] are <= pivot all x in [lo,r) are <= pivot
all x in a[r:l] are == pivot all x in [r,l) are == pivot
all x in a[l:n] are >= pivot all x in [l,hi) are >= pivot
The partitions are a[0:r] and a[l:n] The partitions are [lo,r) and [l,hi)
*/ */
/* Push biggest partition first */ /* Push biggest partition first */
n2 = n - l; n = r - lo;
if (r > n2) { n2 = hi - l;
if (n > n2) {
/* First one is bigger */ /* First one is bigger */
if (r > 1) { if (n > 1) {
astack[top] = a; lostack[top] = lo;
nstack[top++] = r; histack[top++] = r;
if (n2 > 1) { if (n2 > 1) {
astack[top] = a+l; lostack[top] = l;
nstack[top++] = n2; histack[top++] = hi;
} }
} }
} else { } else {
/* Second one is bigger */ /* Second one is bigger */
if (n2 > 1) { if (n2 > 1) {
astack[top] = a+l; lostack[top] = l;
nstack[top++] = n2; histack[top++] = hi;
if (r > 1) { if (n > 1) {
astack[top] = a; lostack[top] = lo;
nstack[top++] = r; histack[top++] = r;
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment