diff options
author | Bobby Bingham <koorogi@koorogi.info> | 2014-11-02 22:34:23 -0600 |
---|---|---|
committer | Bobby Bingham <koorogi@koorogi.info> | 2014-11-02 22:34:23 -0600 |
commit | 8161ac06785068da5234553b528ecbbc8339e232 (patch) | |
tree | 5485f1e1d89ab5a38659e7606e89c2af71c88477 | |
parent | 97427b08ef4e91e31f7694fd691774c012f23dff (diff) |
Fill buffer with smallest elements
This avoids the need to distribute the buffer through the whole array at
the end. It also allows us to skips most of the work for sorted and
reverse-sorted inputs.
-rw-r--r-- | counts.c | 2 | ||||
-rw-r--r-- | counts.h | 3 | ||||
-rw-r--r-- | grailsort.c | 34 |
3 files changed, 36 insertions, 3 deletions
@@ -30,7 +30,7 @@ void add_counts(struct counts *target, struct counts *snapshot) void print_counts(void) { - char *labels[] = {"total", "sortnet", "overlap", "merge", "move buffer", "distribute"}; + char *labels[] = {"total", "sortnet", "check sorted", "steal buffer", "overlap", "merge", "distribute" }; for (int i = 0; i < MAX_COUNTS; i++) { const struct counts *c = counts+i; dprintf(42, "%12s: %10lu cmp, %10lu swap, %10lu rotate\n", labels[i], c->compare, c->swap, c->rotate); @@ -4,9 +4,10 @@ enum { CURRENT, SORTNET, + CHECK_SORTED, + STEAL_BUF, LAST_OVERLAP, MERGE, - MOVE_BUFFER, DISTRIBUTE, MAX_COUNTS }; diff --git a/grailsort.c b/grailsort.c index 9caf28f..2e0131a 100644 --- a/grailsort.c +++ b/grailsort.c @@ -83,6 +83,39 @@ void grailsort(void *unsorted, size_t nmel, size_t width, cmpfun cmp) grailsort(buf, acount * blknmel + bufnmel, width, cmp); grailsort(b, bcount * blknmel, width, cmp); + struct counts snapshot = counts[CURRENT]; + int tmp = cmp(tail(a, acount*blknmel, width), b) <= 0; + add_counts(counts + CHECK_SORTED, &snapshot); + if (tmp) return; + + snapshot = counts[CURRENT]; + tmp = cmp(base, tail(b, bcount*blknmel, width)) >= 0; + if (tmp) { + rotate(base, nmel*width, acount*bwidth + bufnmel*width); + add_counts(counts + CHECK_SORTED, &snapshot); + return; + } + add_counts(counts + CHECK_SORTED, &snapshot); + + /* steal some small elements from b for the buffer, + * so the buffer has the bufnmel smallest elements */ + size_t usebuf = 0, stealb = 0; + snapshot = counts[CURRENT]; + do { + if (cmp(buf + usebuf*width, b + stealb*width) <= 0) { + usebuf++; + } else { + stealb++; + } + } while (usebuf + stealb < bufnmel); + if (stealb) { + swap(a - stealb*width, b, stealb*width); + add_counts(counts + STEAL_BUF, &snapshot); + grailsort(b, bcount * blknmel, width, cmp); + } else { + add_counts(counts + STEAL_BUF, &snapshot); + } + /* sort all the a and b blocks together by their head elements */ grailsort(a, blocks, bwidth, cmp); @@ -102,7 +135,6 @@ void grailsort(void *unsorted, size_t nmel, size_t width, cmpfun cmp) } grailsort(buf, bufnmel, width, cmp); - distribute_buffer(buf, bufnmel, nmel - bufnmel, width, cmp); #if 0 assert_sorted(base, nmel, width, cmp); |