debruijn.c (1738B)
1#include <string.h> 2#include <stdio.h> 3#include <stdlib.h> 4#include <stdbool.h> 5#include <stdarg.h> 6 7/* De Bruijn sequence generation based on Burrows-Wheeler transform */ 8 9static void 10die(const char *fmt, ...) 11{ 12 va_list ap; 13 14 va_start(ap, fmt); 15 fprintf(stderr, "debruijn: "); 16 vfprintf(stderr, fmt, ap); 17 if (*fmt && fmt[strlen(fmt)-1] == ':') { 18 fputc(' ', stderr); 19 perror(NULL); 20 } else { 21 fputc('\n', stderr); 22 } 23 va_end(ap); 24 25 exit(1); 26} 27 28static void 29gen(bool *visited, const char *alph, size_t k, size_t n, size_t len, size_t cnt) 30{ 31 size_t i, si, so, plen, out; 32 33 plen = len / k; 34 out = 0; 35 memset(visited, 0, len); 36 for (i = 0; i < len; i++) { 37 if (visited[i]) continue; 38 so = i; 39 do { 40 si = so; 41 42 putchar(alph[si / plen]); 43 if (++out == cnt) return; 44 visited[si] = true; 45 46 /* (sorted -> unsorted) translation */ 47 so = (si % plen) * k + si / plen; 48 } while (!visited[so]); 49 } 50} 51 52int 53main(int argc, const char **argv) 54{ 55 const char **arg; 56 const char *alph_arg, *n_arg; 57 size_t i, k, n, len; 58 bool all, *visited; 59 60 all = false; 61 alph_arg = n_arg = NULL; 62 for (arg = argv + 1; *arg; arg++) { 63 if (!strcmp(*arg, "-h") || !strcmp(*arg, "--help")) { 64 break; 65 } else if (!strcmp(*arg, "-a")) { 66 all = true; 67 } else if (!alph_arg) { 68 alph_arg = *arg; 69 } else if (!n_arg) { 70 n_arg = *arg; 71 } else { 72 break; 73 } 74 } 75 76 if (*arg || !alph_arg || !n_arg) { 77 fprintf(stderr, "Usage: debruijn ALPH N\n"); 78 return 1; 79 } 80 81 k = strlen(alph_arg); 82 n = strtoull(n_arg, NULL, 10); 83 if (!k || !n) die("invalid args"); 84 85 for (len = 1, i = 0; i < n; i++) len *= k; 86 visited = malloc(len); 87 if (!visited) die("malloc:"); 88 89 gen(visited, alph_arg, k, n, len, len); 90 if (all) gen(visited, alph_arg, k, n, len, k - 1); 91}