| 1 | /*
|
|---|
| 2 | * Tree search generalized from Knuth (6.2.2) Algorithm T just like
|
|---|
| 3 | * the AT&T man page says.
|
|---|
| 4 | *
|
|---|
| 5 | * The node_t structure is for internal use only, lint doesn't grok it.
|
|---|
| 6 | *
|
|---|
| 7 | * Written by reading the System V Interface Definition, not the code.
|
|---|
| 8 | *
|
|---|
| 9 | * Totally public domain.
|
|---|
| 10 | *
|
|---|
| 11 | * $NetBSD: tsearch.c,v 1.3 1999/09/16 11:45:37 lukem Exp $
|
|---|
| 12 | * $NetBSD: twalk.c,v 1.1 1999/02/22 10:33:16 christos Exp $
|
|---|
| 13 | * $NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
|
|---|
| 14 | * $NetBSD: tfind.c,v 1.2 1999/09/16 11:45:37 lukem Exp $
|
|---|
| 15 | */
|
|---|
| 16 |
|
|---|
| 17 | #include <config.h>
|
|---|
| 18 | #include "roken.h"
|
|---|
| 19 | #include "search.h"
|
|---|
| 20 | #include <stdlib.h>
|
|---|
| 21 |
|
|---|
| 22 | typedef struct node {
|
|---|
| 23 | char *key;
|
|---|
| 24 | struct node *llink, *rlink;
|
|---|
| 25 | } node_t;
|
|---|
| 26 |
|
|---|
| 27 | #ifndef __DECONST
|
|---|
| 28 | #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
|
|---|
| 29 | #endif
|
|---|
| 30 |
|
|---|
| 31 | /*
|
|---|
| 32 | * find or insert datum into search tree
|
|---|
| 33 | *
|
|---|
| 34 | * Parameters:
|
|---|
| 35 | * vkey: key to be located
|
|---|
| 36 | * vrootp: address of tree root
|
|---|
| 37 | */
|
|---|
| 38 |
|
|---|
| 39 | ROKEN_LIB_FUNCTION void *
|
|---|
| 40 | rk_tsearch(const void *vkey, void **vrootp,
|
|---|
| 41 | int (*compar)(const void *, const void *))
|
|---|
| 42 | {
|
|---|
| 43 | node_t *q;
|
|---|
| 44 | node_t **rootp = (node_t **)vrootp;
|
|---|
| 45 |
|
|---|
| 46 | if (rootp == NULL)
|
|---|
| 47 | return NULL;
|
|---|
| 48 |
|
|---|
| 49 | while (*rootp != NULL) { /* Knuth's T1: */
|
|---|
| 50 | int r;
|
|---|
| 51 |
|
|---|
| 52 | if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
|
|---|
| 53 | return *rootp; /* we found it! */
|
|---|
| 54 |
|
|---|
| 55 | rootp = (r < 0) ?
|
|---|
| 56 | &(*rootp)->llink : /* T3: follow left branch */
|
|---|
| 57 | &(*rootp)->rlink; /* T4: follow right branch */
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | q = malloc(sizeof(node_t)); /* T5: key not found */
|
|---|
| 61 | if (q != 0) { /* make new node */
|
|---|
| 62 | *rootp = q; /* link new node to old */
|
|---|
| 63 | /* LINTED const castaway ok */
|
|---|
| 64 | q->key = __DECONST(void *, vkey); /* initialize new node */
|
|---|
| 65 | q->llink = q->rlink = NULL;
|
|---|
| 66 | }
|
|---|
| 67 | return q;
|
|---|
| 68 | }
|
|---|
| 69 |
|
|---|
| 70 | /*
|
|---|
| 71 | * Walk the nodes of a tree
|
|---|
| 72 | *
|
|---|
| 73 | * Parameters:
|
|---|
| 74 | * root: Root of the tree to be walked
|
|---|
| 75 | */
|
|---|
| 76 | static void
|
|---|
| 77 | trecurse(const node_t *root, void (*action)(const void *, VISIT, int),
|
|---|
| 78 | int level)
|
|---|
| 79 | {
|
|---|
| 80 |
|
|---|
| 81 | if (root->llink == NULL && root->rlink == NULL)
|
|---|
| 82 | (*action)(root, leaf, level);
|
|---|
| 83 | else {
|
|---|
| 84 | (*action)(root, preorder, level);
|
|---|
| 85 | if (root->llink != NULL)
|
|---|
| 86 | trecurse(root->llink, action, level + 1);
|
|---|
| 87 | (*action)(root, postorder, level);
|
|---|
| 88 | if (root->rlink != NULL)
|
|---|
| 89 | trecurse(root->rlink, action, level + 1);
|
|---|
| 90 | (*action)(root, endorder, level);
|
|---|
| 91 | }
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | /*
|
|---|
| 95 | * Walk the nodes of a tree
|
|---|
| 96 | *
|
|---|
| 97 | * Parameters:
|
|---|
| 98 | * vroot: Root of the tree to be walked
|
|---|
| 99 | */
|
|---|
| 100 | ROKEN_LIB_FUNCTION void
|
|---|
| 101 | rk_twalk(const void *vroot,
|
|---|
| 102 | void (*action)(const void *, VISIT, int))
|
|---|
| 103 | {
|
|---|
| 104 | if (vroot != NULL && action != NULL)
|
|---|
| 105 | trecurse(vroot, action, 0);
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | /*
|
|---|
| 109 | * delete node with given key
|
|---|
| 110 | *
|
|---|
| 111 | * vkey: key to be deleted
|
|---|
| 112 | * vrootp: address of the root of the tree
|
|---|
| 113 | * compar: function to carry out node comparisons
|
|---|
| 114 | */
|
|---|
| 115 | ROKEN_LIB_FUNCTION void *
|
|---|
| 116 | rk_tdelete(const void * vkey, void ** vrootp,
|
|---|
| 117 | int (*compar)(const void *, const void *))
|
|---|
| 118 | {
|
|---|
| 119 | node_t **rootp = (node_t **)vrootp;
|
|---|
| 120 | node_t *p, *q, *r;
|
|---|
| 121 | int cmp;
|
|---|
| 122 |
|
|---|
| 123 | if (rootp == NULL || (p = *rootp) == NULL)
|
|---|
| 124 | return NULL;
|
|---|
| 125 |
|
|---|
| 126 | while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) {
|
|---|
| 127 | p = *rootp;
|
|---|
| 128 | rootp = (cmp < 0) ?
|
|---|
| 129 | &(*rootp)->llink : /* follow llink branch */
|
|---|
| 130 | &(*rootp)->rlink; /* follow rlink branch */
|
|---|
| 131 | if (*rootp == NULL)
|
|---|
| 132 | return NULL; /* key not found */
|
|---|
| 133 | }
|
|---|
| 134 | r = (*rootp)->rlink; /* D1: */
|
|---|
| 135 | if ((q = (*rootp)->llink) == NULL) /* Left NULL? */
|
|---|
| 136 | q = r;
|
|---|
| 137 | else if (r != NULL) { /* Right link is NULL? */
|
|---|
| 138 | if (r->llink == NULL) { /* D2: Find successor */
|
|---|
| 139 | r->llink = q;
|
|---|
| 140 | q = r;
|
|---|
| 141 | } else { /* D3: Find NULL link */
|
|---|
| 142 | for (q = r->llink; q->llink != NULL; q = r->llink)
|
|---|
| 143 | r = q;
|
|---|
| 144 | r->llink = q->rlink;
|
|---|
| 145 | q->llink = (*rootp)->llink;
|
|---|
| 146 | q->rlink = (*rootp)->rlink;
|
|---|
| 147 | }
|
|---|
| 148 | }
|
|---|
| 149 | free(*rootp); /* D4: Free node */
|
|---|
| 150 | *rootp = q; /* link parent to new node */
|
|---|
| 151 | return p;
|
|---|
| 152 | }
|
|---|
| 153 |
|
|---|
| 154 | /*
|
|---|
| 155 | * find a node, or return 0
|
|---|
| 156 | *
|
|---|
| 157 | * Parameters:
|
|---|
| 158 | * vkey: key to be found
|
|---|
| 159 | * vrootp: address of the tree root
|
|---|
| 160 | */
|
|---|
| 161 | ROKEN_LIB_FUNCTION void *
|
|---|
| 162 | rk_tfind(const void *vkey, void * const *vrootp,
|
|---|
| 163 | int (*compar)(const void *, const void *))
|
|---|
| 164 | {
|
|---|
| 165 | node_t **rootp = (node_t **)vrootp;
|
|---|
| 166 |
|
|---|
| 167 | if (rootp == NULL)
|
|---|
| 168 | return NULL;
|
|---|
| 169 |
|
|---|
| 170 | while (*rootp != NULL) { /* T1: */
|
|---|
| 171 | int r;
|
|---|
| 172 |
|
|---|
| 173 | if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */
|
|---|
| 174 | return *rootp; /* key found */
|
|---|
| 175 | rootp = (r < 0) ?
|
|---|
| 176 | &(*rootp)->llink : /* T3: follow left branch */
|
|---|
| 177 | &(*rootp)->rlink; /* T4: follow right branch */
|
|---|
| 178 | }
|
|---|
| 179 | return NULL;
|
|---|
| 180 | }
|
|---|