Bug 872497 - Remove problematic "optimization" in NS_QuickSort. r=jlebar

This change allows us to avoid O(n^2) performance when partially sorted data
is given to NS_QuickSort.  We no longer attempt an insertion sort if the input
appears pre-sorted.  This brings the expected performance back to O(n*log(n))
but also eliminates the possibility of O(n) best case performance.  Attempts
to achieve O(n) performance should be the responsibility of callers as they
are in a better position to evaluate the costs/benefit trade-off of looking
for special cases that can be sorted quicker.
This commit is contained in:
Derrick Moser 2013-05-18 15:16:02 -04:00
Родитель 0bb228f8cc
Коммит e63f66826d
1 изменённых файлов: 12 добавлений и 13 удалений

Просмотреть файл

@ -104,10 +104,10 @@ void NS_QuickSort (
)
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
int d, r, swaptype;
loop: SWAPINIT(a, es);
swap_cnt = 0;
/* Use insertion sort when input is small */
if (n < 7) {
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0;
@ -115,6 +115,7 @@ loop: SWAPINIT(a, es);
swap(pl, pl - es);
return;
}
/* Choose pivot */
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
@ -131,10 +132,16 @@ loop: SWAPINIT(a, es);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
/* loop invariants:
* [a, pa) = pivot
* [pa, pb) < pivot
* [pb, pc + es) unprocessed
* [pc + es, pd + es) > pivot
* [pd + es, pn) = pivot
*/
for (;;) {
while (pb <= pc && (r = cmp(pb, a, data)) <= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
@ -142,7 +149,6 @@ loop: SWAPINIT(a, es);
}
while (pb <= pc && (r = cmp(pc, a, data)) >= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pc, pd);
pd -= es;
}
@ -151,23 +157,16 @@ loop: SWAPINIT(a, es);
if (pb > pc)
break;
swap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
/* Move pivot values */
pn = (char *)a + n * es;
r = XPCOM_MIN(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = XPCOM_MIN<size_t>(pd - pc, pn - pd - es);
vecswap(pb, pn - r, r);
/* Recursively process partitioned items */
if ((r = pb - pa) > (int)es)
NS_QuickSort(a, r / es, es, cmp, data);
if ((r = pd - pc) > (int)es) {