using COMPARE. When COMPARE is passed a pair of elements A
and B, respectively, it must return a strcmp()-type result,
i.e. less than zero if A < B, zero if A == B, greater than
- zero if A > B. */
+ zero if A > B. Runs in O(n lg n) time and O(1) space in
+ CNT. */
void
qsort (void *array, size_t cnt, size_t size,
int (*compare) (const void *, const void *))
{
- quick_sort (array, cnt, size, compare_thunk, &compare);
+ sort (array, cnt, size, compare_thunk, &compare);
}
-/* Swaps the SIZE bytes at A and B. */
+/* Swaps elements with 1-based indexes A_IDX and B_IDX in ARRAY
+ with elements of SIZE bytes each. */
static void
-swap (unsigned char *a, unsigned char *b, size_t size)
+do_swap (unsigned char *array, size_t a_idx, size_t b_idx, size_t size)
{
+ unsigned char *a = array + (a_idx - 1) * size;
+ unsigned char *b = array + (b_idx - 1) * size;
size_t i;
for (i = 0; i < size; i++)
}
}
-/* Selects a random "pivot" element in ARRAY, which contains CNT
- elements of SIZE bytes each, and partitions ARRAY into two
- contiguous subranges around the pivot, so that the first N
- elements are less than or equal to the pivot and the remaining
- elements are greater than the pivot. Returns N.
+/* Compares elements with 1-based indexes A_IDX and B_IDX in
+ ARRAY with elements of SIZE bytes each, using COMPARE to
+ compare elements, passing AUX as auxiliary data, and returns a
+ strcmp()-type result. */
+static int
+do_compare (unsigned char *array, size_t a_idx, size_t b_idx, size_t size,
+ int (*compare) (const void *, const void *, void *aux),
+ void *aux)
+{
+ return compare (array + (a_idx - 1) * size, array + (b_idx - 1) * size, aux);
+}
- Uses COMPARE to compare elements, passing AUX as auxiliary
- data. When COMPARE is passed a pair of elements A and B,
- respectively, it must return a strcmp()-type result, i.e. less
- than zero if A < B, zero if A == B, greater than zero if A >
- B. */
-static size_t
-randomized_partition (void *array, size_t cnt, size_t size,
- int (*compare) (const void *, const void *, void *aux),
- void *aux)
+/* "Float down" the element with 1-based index I in ARRAY of CNT
+ elements of SIZE bytes each, using COMPARE to compare
+ elements, passing AUX as auxiliary data. */
+static void
+heapify (unsigned char *array, size_t i, size_t cnt, size_t size,
+ int (*compare) (const void *, const void *, void *aux),
+ void *aux)
{
- unsigned char *first = array; /* Beginning of array. */
- unsigned char *last = first + size * cnt; /* End of array. */
- unsigned char *pivot = last - size; /* Element used as pivot. */
- unsigned char *middle; /* Invariant: elements on left are <= pivot. */
- unsigned char *current;
-
- ASSERT (array != NULL);
- ASSERT (cnt > 1);
- ASSERT (size > 0);
- ASSERT (compare != NULL);
-
- /* Choose a random pivot. */
- swap (pivot, first + (random_ulong () % cnt) * size, size);
-
- /* Iterate through the array moving elements less than or equal
- to the pivot to the middle. */
- middle = array;
- for (current = first; current < last; current += size)
- if (compare (current, pivot, aux) <= 0)
- {
- swap (middle, current, size);
- middle += size;
- }
-
- return (middle - first) / size;
+ for (;;)
+ {
+ /* Set `max' to the index of the largest element among I
+ and its children (if any). */
+ size_t left = 2 * i;
+ size_t right = 2 * i + 1;
+ size_t max = i;
+ if (left <= cnt && do_compare (array, left, max, size, compare, aux) > 0)
+ max = left;
+ if (right <= cnt
+ && do_compare (array, right, max, size, compare, aux) > 0)
+ max = right;
+
+ /* If the maximum value is already in element I, we're
+ done. */
+ if (max == i)
+ break;
+
+ /* Swap and continue down the heap. */
+ do_swap (array, i, max, size);
+ i = max;
+ }
}
/* Sorts ARRAY, which contains CNT elements of SIZE bytes each,
data. When COMPARE is passed a pair of elements A and B,
respectively, it must return a strcmp()-type result, i.e. less
than zero if A < B, zero if A == B, greater than zero if A >
- B. */
+ B. Runs in O(n lg n) time and O(1) space in CNT. */
void
-quick_sort (void *array_, size_t cnt, size_t size,
- int (*compare) (const void *, const void *, void *aux),
- void *aux)
+sort (void *array, size_t cnt, size_t size,
+ int (*compare) (const void *, const void *, void *aux),
+ void *aux)
{
- unsigned char *array = array_;
+ size_t i;
ASSERT (array != NULL || cnt == 0);
ASSERT (compare != NULL);
ASSERT (size > 0);
-
- if (cnt > 1)
+
+ /* Build a heap. */
+ for (i = cnt / 2; i > 0; i--)
+ heapify (array, i, cnt, size, compare, aux);
+
+ /* Sort the heap. */
+ for (i = cnt; i > 1; i--)
{
- size_t q = randomized_partition (array, cnt, size, compare, aux);
-
- /* Sort smaller partition first to guarantee O(lg n) stack
- depth limit. */
- if (q < cnt - q)
- {
- quick_sort (array, q, size, compare, aux);
- quick_sort (array + q * size, cnt - q, size, compare, aux);
- }
- else
- {
- quick_sort (array + q * size, cnt - q, size, compare, aux);
- quick_sort (array, q, size, compare, aux);
- }
+ do_swap (array, 1, i, size);
+ heapify (array, 1, i - 1, size, compare, aux);
}
}