/* ** Choose an element in the middle (2nd-3th quarters) of [lo,up] ** "randomized" by 'rnd' */ private static IdxT choosePivot(IdxT lo, IdxT up, uint rnd) { IdxT r4 = (up - lo) / 4; /* range/4 */ IdxT p = rnd % (r4 * 2) + (lo + r4); lua_assert(lo + r4 <= p && p <= up - r4); return(p); }
/* ** Does the partition: Pivot P is at the top of the stack. ** precondition: a[lo] <= P == a[up-1] <= a[up], ** so it only needs to do the partition from lo + 1 to up - 2. ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] ** returns 'i'. */ private static IdxT partition(lua_State L, IdxT lo, IdxT up) { IdxT i = lo; /* will be incremented before first use */ IdxT j = up - 1; /* will be decremented before first use */ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ for (;;) { /* next loop: repeat ++i while a[i] < P */ while (partition_f1(L, ref i)) { if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ { luaL_error(L, "invalid order function for sorting"); } lua_pop(L, 1); /* remove a[i] */ } /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ /* next loop: repeat --j while P < a[j] */ while (partition_f2(L, ref j)) { if (j < i) /* j < i but a[j] > P ?? */ { luaL_error(L, "invalid order function for sorting"); } lua_pop(L, 1); /* remove a[j] */ } /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ if (j < i) /* no elements out of place? */ /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ { lua_pop(L, 1); /* pop a[j] */ /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ set2(L, up - 1, i); return(i); } /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ set2(L, i, j); } }
/* ** QuickSort algorithm (recursive function) */ private static void auxsort(lua_State L, IdxT lo, IdxT up, uint rnd) { while (lo < up) /* loop for tail recursion */ { uint p; /* Pivot index */ uint n; /* to be used later */ /* sort elements 'lo', 'p', and 'up' */ lua_geti(L, 1, (lua_Integer)lo); lua_geti(L, 1, (lua_Integer)up); if (0 != sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ { set2(L, lo, up); /* swap a[lo] - a[up] */ } else { lua_pop(L, 2); /* remove both values */ } if (up - lo == 1) /* only 2 elements? */ { return; /* already sorted */ } if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ { p = (lo + up) / 2; /* middle element is a good pivot */ } else /* for larger intervals, it is worth a random pivot */ { p = choosePivot(lo, up, rnd); } lua_geti(L, 1, (lua_Integer)p); lua_geti(L, 1, (lua_Integer)lo); if (0 != sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ { set2(L, p, lo); /* swap a[p] - a[lo] */ } else { lua_pop(L, 1); /* remove a[lo] */ lua_geti(L, 1, (lua_Integer)up); if (0 != sort_comp(L, -1, -2)) /* a[up] < a[p]? */ { set2(L, p, up); /* swap a[up] - a[p] */ } else { lua_pop(L, 2); } } if (up - lo == 2) /* only 3 elements? */ { return; /* already sorted */ } lua_geti(L, 1, (lua_Integer)p); /* get middle element (Pivot) */ lua_pushvalue(L, -1); /* push Pivot */ lua_geti(L, 1, (lua_Integer)(up - 1)); /* push a[up - 1] */ set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ p = partition(L, lo, up); /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ if (p - lo < up - p) /* lower interval is smaller? */ { auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ n = p - lo; /* size of smaller interval */ lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ } else { auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ n = up - p; /* size of smaller interval */ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ } if ((up - lo) / 128u > n) /* partition too imbalanced? */ { rnd = l_randomizePivot(); /* try a new randomization */ } } /* tail call auxsort(L, lo, up, rnd) */ }
private static void set2(lua_State L, IdxT i, IdxT j) { lua_seti(L, 1, (lua_Integer)i); lua_seti(L, 1, (lua_Integer)j); }