diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2011-10-14 04:55:05 +0200 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2011-10-14 04:55:05 +0200 |
commit | 6aa0e0017d7d0cddc006da885946934b06949a91 (patch) | |
tree | 66b688ec32e2f91266db760b1762f2a50cc52036 /libslang/src/slqsort.c | |
parent | a966db5b71328f6adf9dd767e64b322a3bd7ed9c (diff) | |
download | erlang-slang-fork-6aa0e0017d7d0cddc006da885946934b06949a91.tar.gz |
include libslang-1.4.9 and automatically build it and link erlang-slang against it
few (erlang) people will still have libslang-1.4.9 installed or spend time
to get it to link against the driver
Diffstat (limited to 'libslang/src/slqsort.c')
-rw-r--r-- | libslang/src/slqsort.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/libslang/src/slqsort.c b/libslang/src/slqsort.c new file mode 100644 index 0000000..385f0ae --- /dev/null +++ b/libslang/src/slqsort.c @@ -0,0 +1,257 @@ +/******************************************************************/ +/* qsort.c -- Non-Recursive ANSI Quicksort function */ +/* */ +/* Public domain by Raymond Gardner, Englewood CO February 1991 */ +/* */ +/* Usage: */ +/* qsort(base, nbr_elements, width_bytes, compare_function); */ +/* void *base; */ +/* size_t nbr_elements, width_bytes; */ +/* int (*compare_function)(const void *, const void *); */ +/* */ +/* Sorts an array starting at base, of length nbr_elements, each */ +/* element of size width_bytes, ordered via compare_function, */ +/* which is called as (*compare_function)(ptr_to_element1, */ +/* ptr_to_element2) and returns < 0 if element1 < element2, */ +/* 0 if element1 = element2, > 0 if element1 > element2. */ +/* Most refinements are due to R. Sedgewick. See "Implementing */ +/* Quicksort Programs", Comm. ACM, Oct. 1978, and Corrigendum, */ +/* Comm. ACM, June 1979. */ +/******************************************************************/ + +/* John E. Davis: modifed to use my coding style and made gcc warning + * clean. Also, the name changed to reflect the fact that the function + * carries state data. + */ + +#include <stddef.h> /* for size_t definition */ + +/* prototypes */ +extern void _SLqsort (void *, size_t, size_t, + int (*)(void *, void *, void *), void *); + +static void swap_chars(char *, char *, size_t); + +/* + * Compile with -DSWAP_INTS if your machine can access an int at an + * arbitrary location with reasonable efficiency. Some machines + * cannot access an int at an odd address at all, so be careful. + */ + +#ifdef SWAP_INTS +static void swap_ints(char *, char *, size_t); +# define SWAP(a, b) (swap_func((char *)(a), (char *)(b), width)) +#else +# define SWAP(a, b) (swap_chars((char *)(a), (char *)(b), size)) +#endif + +#define COMP(a, b, c) ((*comp)((void *)(a), (void *)(b), (c))) + +#define T 7 +/* subfiles of T or fewer elements will be sorted by a simple insertion sort. + * Note! T must be at least 3 + */ + +void _SLqsort(void *basep, size_t nelems, size_t size, + int (*comp)(void *, void *, void *), void *cd) +{ + char *stack[40], **sp; /* stack and stack pointer */ + char *i, *j, *limit; /* scan and limit pointers */ + size_t thresh; /* size of T elements in bytes */ + char *base; /* base pointer as char * */ + +#ifdef SWAP_INTS + size_t width; /* width of array element */ + void (*swap_func)(char *, char *, size_t); /* swap func pointer*/ + + width = size; /* save size for swap routine */ + swap_func = swap_chars; /* choose swap function */ + if ( size % sizeof(int) == 0 ) + { + /* size is multiple of ints */ + width /= sizeof(int); /* set width in ints */ + swap_func = swap_ints; /* use int swap function */ + } +#endif + + base = (char *)basep; /* set up char * base pointer */ + thresh = T * size; /* init threshold */ + sp = stack; /* init stack pointer */ + limit = base + nelems * size;/* pointer past end of array */ + + while (1) + { + /* repeat until break... */ + if (limit > base + thresh) + { + /* if more than T elements, swap base with middle */ + SWAP((((limit-base)/size)/2)*size+base, base); + + i = base + size; /* i scans left to right */ + j = limit - size; /* j scans right to left */ + if (COMP(i, j, cd) > 0) /* Sedgewick's */ + SWAP(i, j); /* three-element sort */ + if (COMP(base, j, cd) > 0)/* sets things up */ + SWAP(base, j); /* so that */ + if (COMP(i, base,cd ) > 0)/* *i <= *base <= *j */ + SWAP(i, base); /* *base is pivot element */ + + while (1) + { + do + { + /* move i right until *i >= pivot */ + i += size; + } + while (COMP(i, base, cd) < 0); + + /* move j left until *j <= pivot */ + do + { + j -= size; + } + while (COMP(j, base, cd) > 0); + + /* if pointers crossed, break loop */ + if (i > j) break; + + SWAP(i, j); /* else swap elements, keep scanning*/ + } + + SWAP(base, j); /* move pivot into correct place */ + + if (j - base > limit - i) + { + /* if left subfile larger */ + sp[0] = base; /* stack left subfile base */ + sp[1] = j; /* and limit */ + base = i; /* sort the right subfile */ + } + else + { + /* else right subfile larger*/ + sp[0] = i; /* stack right subfile base */ + sp[1] = limit; /* and limit */ + limit = j; /* sort the left subfile */ + } + sp += 2; /* increment stack pointer */ + } + else + { + /* else subfile is small, use insertion sort */ + j = base; + i = j + size; + + while (i < limit) + { + while (COMP(j, j + size, cd) > 0) + { + SWAP(j, j+size); + if (j == base) + break; + j -= size; + } + + j = i; + i += size; + } + + if (sp == stack) /* done */ + break; + + /* if any entries on stack */ + sp -= 2; /* pop the base and limit */ + base = sp[0]; + limit = sp[1]; + } + } +} + +/* +** swap nbytes between a and b +*/ + +static void swap_chars(char *a, char *b, size_t nbytes) +{ + char tmp; + do + { + tmp = *a; *a++ = *b; *b++ = tmp; + } + while ( --nbytes ); +} + +#ifdef SWAP_INTS + +/* +** swap nints between a and b +*/ + +static void swap_ints(char *ap, char *bp, size_t nints) +{ + int *a = (int *)ap, *b = (int *)bp; + int tmp; + do + { + tmp = *a; *a++ = *b; *b++ = tmp; + } + while ( --nints ); +} + +#endif + +#ifdef TESTING + +#include <stdio.h> +#include <math.h> + +static int cmp_fun (void *a, void *b, void *c) +{ + double x, y; + double *xp, *yp; + double *data; + + data = (double *) c; + + xp = data + *(unsigned int *)a; + yp = data + *(unsigned int *)b; + + x = *xp; + y = *yp; + + if (x > y) return 1; else if (x < y) return -1; + if (xp > yp) return 1; + if (xp == yp) return 0; + return -1; +} + +#define ARRAY_SIZE 10000 +int main (int argc, char **argv) +{ + unsigned int i; + double x, dx; + unsigned int index_array [ARRAY_SIZE]; + double double_array [ARRAY_SIZE]; + + x = 0.0; + dx = 6.28 / ARRAY_SIZE; + for (i = 0; i < ARRAY_SIZE; i++) + { + double_array [i] = sin(x); + index_array [i] = i; + x += dx; + } + + _SLqsort ((void *) index_array, ARRAY_SIZE, + sizeof (unsigned int), cmp_fun, (void *) double_array); + + if (argc > 1) + for (i = 0; i < ARRAY_SIZE; i++) + { + fprintf (stdout, "%f\t%f\n", + double_array[i], double_array[index_array[i]]); + } + + return 0; +} +#endif |