From: Ben Pfaff Date: Wed, 30 Mar 2005 05:17:28 +0000 (+0000) Subject: Replace quick_sort() that uses quick sort and O(lg n) space X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b2b1f040894e1db4fec9e5ee9efc2fcca5f9829c;p=pintos-anon Replace quick_sort() that uses quick sort and O(lg n) space by sort() that uses heap sort and O(1) space. --- diff --git a/TODO b/TODO index 3ccce4b..6090635 100644 --- a/TODO +++ b/TODO @@ -117,8 +117,6 @@ * Code: - - Rewrite quick_sort() to use heap sort, for O(1) stack usage. - - Make printf() test actually check its results. - Make threads test use a program and arguments like the other diff --git a/grading/vm/page-merge-par.c b/grading/vm/page-merge-par.c index 06209e8..8f3be48 100644 --- a/grading/vm/page-merge-par.c +++ b/grading/vm/page-merge-par.c @@ -35,7 +35,7 @@ init (void) /* Sort each chunk of buf1 using a subprocess. */ static void -sort (void) +sort_chunks (void) { pid_t children[CHUNK_CNT]; size_t i; @@ -162,7 +162,7 @@ main (void) { printf ("(page-merge-par) begin\n"); init (); - sort (); + sort_chunks (); merge (); verify (); printf ("(page-merge-par) end\n"); diff --git a/grading/vm/page-merge-seq.c b/grading/vm/page-merge-seq.c index 203ca9c..57cd53c 100644 --- a/grading/vm/page-merge-seq.c +++ b/grading/vm/page-merge-seq.c @@ -35,7 +35,7 @@ init (void) /* Sort each chunk of buf1 using a subprocess. */ static void -sort (void) +sort_chunks (void) { size_t i; @@ -150,7 +150,7 @@ main (void) { printf ("(page-merge-seq) begin\n"); init (); - sort (); + sort_chunks (); merge (); verify (); printf ("(page-merge-seq) end\n"); diff --git a/src/lib/stdlib.c b/src/lib/stdlib.c index 0056fc1..84c7f61 100644 --- a/src/lib/stdlib.c +++ b/src/lib/stdlib.c @@ -52,18 +52,22 @@ compare_thunk (const void *a, const void *b, void *aux) 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++) @@ -74,47 +78,48 @@ swap (unsigned char *a, unsigned char *b, size_t size) } } -/* 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, @@ -122,34 +127,27 @@ randomized_partition (void *array, size_t cnt, size_t size, 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); } } diff --git a/src/lib/stdlib.h b/src/lib/stdlib.h index cfc12ed..d14afa3 100644 --- a/src/lib/stdlib.h +++ b/src/lib/stdlib.h @@ -11,9 +11,9 @@ void *bsearch (const void *key, const void *array, size_t cnt, size_t size, int (*compare) (const void *, const void *)); /* Nonstandard functions. */ -void quick_sort (void *array, size_t cnt, size_t size, - int (*compare) (const void *, const void *, void *aux), - void *aux); +void sort (void *array, size_t cnt, size_t size, + int (*compare) (const void *, const void *, void *aux), + void *aux); void *binary_search (const void *key, const void *array, size_t cnt, size_t size, int (*compare) (const void *, const void *, void *aux),