// written in ed because cellphone keyboards suck at vi #include #include #include #include void *xmalloc(size_t n) { void *p = malloc(n); if (!p) abort(); return p; } char *xstrdup(char *s) { char *p = strdup(s); if (!p) abort(); return p; } typedef struct node { char *s; int count; struct node *kids[4]; } node; uint32_t hash(char *s) { uint32_t h = 0; while (*s) { h *= 17903; h += *s++; } return h; } // based on Chris Wellons's hash trie post in collaboration with NRK: // and node *upsert(node **n, char *s) { for (uint32_t h = hash(s); *n; n = &(*n)->kids[h & 3], h>>= 2) { if (0 == strcmp(s, (*n)->s)) return *n; } *n = xmalloc(sizeof(**n)); **n = (node) { xstrdup(s) }; return *n; } void print_words(node *t, int d) { if (!t) return; for (int i = 0; i != d; i++) putchar(' '); printf("- %d %s\n", t->count, t->s); for (int i = 0; i != 4; i++) print_words(t->kids[i], d + 2); } int main(int argc, char **argv) { char buf[128]; node *t = 0; for (;;) { if (!fgets(buf, sizeof buf, stdin)) break; char *p = buf; for (char *q = buf; *q; q++) { char c = *q; if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { if (!*p) p = q; continue; } *q = 0; if (strlen(p)) upsert(&t, p)->count++; p = q; } if (strlen(p)) upsert(&t, p)->count++; } print_words(t, 0); return 0; }