xref: /openbsd-src/lib/libc/stdlib/tsearch.c (revision 89cd0876c414e6118d016a4e433b82db2c730404)
1*89cd0876Sguenther /*	$OpenBSD: tsearch.c,v 1.10 2015/09/26 16:03:48 guenther Exp $	*/
248f0b646Sjsg 
3e728c442Sderaadt /*
4e728c442Sderaadt  * Tree search generalized from Knuth (6.2.2) Algorithm T just like
5e728c442Sderaadt  * the AT&T man page says.
6e728c442Sderaadt  *
7acf82b0aSguenther  * The node_t structure is for internal use only
8e728c442Sderaadt  *
9e728c442Sderaadt  * Written by reading the System V Interface Definition, not the code.
10e728c442Sderaadt  *
11e728c442Sderaadt  * Totally public domain.
12e728c442Sderaadt  */
13e728c442Sderaadt 
14e728c442Sderaadt #include <search.h>
15581b1b82Smillert #include <stdlib.h>
16e728c442Sderaadt 
17e728c442Sderaadt typedef struct node_t {
18e728c442Sderaadt     char	  *key;
19e728c442Sderaadt     struct node_t *left, *right;
20e728c442Sderaadt } node;
21e728c442Sderaadt 
22e728c442Sderaadt /* find or insert datum into search tree */
23e728c442Sderaadt void *
tsearch(const void * vkey,void ** vrootp,int (* compar)(const void *,const void *))24d8bc04e4Spat tsearch(const void *vkey, void **vrootp,
25d8bc04e4Spat     int (*compar)(const void *, const void *))
26e728c442Sderaadt {
27d8bc04e4Spat     node *q;
28e728c442Sderaadt     char *key = (char *)vkey;
29e728c442Sderaadt     node **rootp = (node **)vrootp;
30e728c442Sderaadt 
31e728c442Sderaadt     if (rootp == (struct node_t **)0)
32e728c442Sderaadt 	return ((void *)0);
33e728c442Sderaadt     while (*rootp != (struct node_t *)0) {	/* Knuth's T1: */
34e728c442Sderaadt 	int r;
35e728c442Sderaadt 
36e728c442Sderaadt 	if ((r = (*compar)(key, (*rootp)->key)) == 0)	/* T2: */
37e728c442Sderaadt 	    return ((void *)*rootp);		/* we found it! */
38e728c442Sderaadt 	rootp = (r < 0) ?
39e728c442Sderaadt 	    &(*rootp)->left :		/* T3: follow left branch */
40e728c442Sderaadt 	    &(*rootp)->right;		/* T4: follow right branch */
41e728c442Sderaadt     }
42fa713987Sderaadt     q = malloc(sizeof(node));	/* T5: key not found */
43e728c442Sderaadt     if (q != (struct node_t *)0) {	/* make new node */
44e728c442Sderaadt 	*rootp = q;			/* link new node to old */
45e728c442Sderaadt 	q->key = key;			/* initialize new node */
46e728c442Sderaadt 	q->left = q->right = (struct node_t *)0;
47e728c442Sderaadt     }
48e728c442Sderaadt     return ((void *)q);
49e728c442Sderaadt }
50e728c442Sderaadt 
51e728c442Sderaadt /* delete node with given key */
52e728c442Sderaadt void *
tdelete(const void * vkey,void ** vrootp,int (* compar)(const void *,const void *))53d8bc04e4Spat tdelete(const void *vkey, void **vrootp,
54d8bc04e4Spat     int (*compar)(const void *, const void *))
55e728c442Sderaadt {
56e728c442Sderaadt     node **rootp = (node **)vrootp;
57e728c442Sderaadt     char *key = (char *)vkey;
58d8bc65b2Sguenther     node *p = (node *)1;
59d8bc04e4Spat     node *q;
60d8bc04e4Spat     node *r;
61e728c442Sderaadt     int cmp;
62e728c442Sderaadt 
63d8bc65b2Sguenther     if (rootp == (struct node_t **)0 || *rootp == (struct node_t *)0)
64e728c442Sderaadt 	return ((struct node_t *)0);
65e728c442Sderaadt     while ((cmp = (*compar)(key, (*rootp)->key)) != 0) {
66e728c442Sderaadt 	p = *rootp;
67e728c442Sderaadt 	rootp = (cmp < 0) ?
68e728c442Sderaadt 	    &(*rootp)->left :		/* follow left branch */
69e728c442Sderaadt 	    &(*rootp)->right;		/* follow right branch */
70e728c442Sderaadt 	if (*rootp == (struct node_t *)0)
71e728c442Sderaadt 	    return ((void *)0);		/* key not found */
72e728c442Sderaadt     }
73e728c442Sderaadt     r = (*rootp)->right;			/* D1: */
74e728c442Sderaadt     if ((q = (*rootp)->left) == (struct node_t *)0)	/* Left (struct node_t *)0? */
75e728c442Sderaadt 	q = r;
76e728c442Sderaadt     else if (r != (struct node_t *)0) {		/* Right link is null? */
77e728c442Sderaadt 	if (r->left == (struct node_t *)0) {	/* D2: Find successor */
78e728c442Sderaadt 	    r->left = q;
79e728c442Sderaadt 	    q = r;
80e728c442Sderaadt 	} else {			/* D3: Find (struct node_t *)0 link */
81e728c442Sderaadt 	    for (q = r->left; q->left != (struct node_t *)0; q = r->left)
82e728c442Sderaadt 		r = q;
83e728c442Sderaadt 	    r->left = q->right;
84e728c442Sderaadt 	    q->left = (*rootp)->left;
85e728c442Sderaadt 	    q->right = (*rootp)->right;
86e728c442Sderaadt 	}
87e728c442Sderaadt     }
88e728c442Sderaadt     free((struct node_t *) *rootp);	/* D4: Free node */
89e728c442Sderaadt     *rootp = q;				/* link parent to new node */
90e728c442Sderaadt     return(p);
91e728c442Sderaadt }
92e728c442Sderaadt 
93e728c442Sderaadt /* Walk the nodes of a tree */
94e728c442Sderaadt static void
trecurse(node * root,void (* action)(const void *,VISIT,int),int level)95d8bc04e4Spat trecurse(node *root, void (*action)(const void *, VISIT, int), int level)
96e728c442Sderaadt {
97e728c442Sderaadt     if (root->left == (struct node_t *)0 && root->right == (struct node_t *)0)
98e728c442Sderaadt 	(*action)(root, leaf, level);
99e728c442Sderaadt     else {
100e728c442Sderaadt 	(*action)(root, preorder, level);
101e728c442Sderaadt 	if (root->left != (struct node_t *)0)
102e728c442Sderaadt 	    trecurse(root->left, action, level + 1);
103e728c442Sderaadt 	(*action)(root, postorder, level);
104e728c442Sderaadt 	if (root->right != (struct node_t *)0)
105e728c442Sderaadt 	    trecurse(root->right, action, level + 1);
106e728c442Sderaadt 	(*action)(root, endorder, level);
107e728c442Sderaadt     }
108e728c442Sderaadt }
109e728c442Sderaadt 
110e728c442Sderaadt /* Walk the nodes of a tree */
111e728c442Sderaadt void
twalk(const void * vroot,void (* action)(const void *,VISIT,int))112d8bc04e4Spat twalk(const void *vroot, void (*action)(const void *, VISIT, int))
113e728c442Sderaadt {
114e728c442Sderaadt     node *root = (node *)vroot;
115e728c442Sderaadt 
116d8bc04e4Spat     if (root != (node *)0 && action != (void (*)(const void *, VISIT, int))0)
117e728c442Sderaadt 	trecurse(root, action, 0);
118e728c442Sderaadt }
119