1 /****************************************************************
2 Copyright (C) 2007 David M. Gay
3 
4 Permission to use, copy, modify, and distribute this software and its
5 documentation for any purpose and without fee is hereby granted,
6 
7 provided that the above copyright notice appear in all copies and that
8 both that the copyright notice and this permission notice and warranty
9 disclaimer appear in supporting documentation.
10 
11 The author disclaims all warranties with regard to this software,
12 including all implied warranties of merchantability and fitness.
13 In no event shall the author be liable for any special, indirect or
14 consequential damages or any damages whatsoever resulting from loss of
15 use, data or profits, whether in an action of contract, negligence or
16 other tortious action, arising out of or in connection with the use or
17 performance of this software.
18 ****************************************************************/
19 
20 #include "avltree.h"
21 #include <stdlib.h> /* for free() */
22 #include <string.h>
23 
24 #ifndef AVL_memgulp
25 #define AVL_memgulp 256
26 #endif
27 
28  typedef struct AVL_Mblk AVL_Mblk;
29  typedef struct Node Node;
30 
31  struct
32 Node {
33 	const Element *elem;
34 	Node *left, *right;
35 	int height;
36 	};
37 
38  struct
39 AVL_Mblk {
40 	AVL_Mblk *next;
41 	Node x[AVL_memgulp];
42 	};
43 
44  struct
45 AVL_Tree {
46 	Node *Top;
47 	Node *efree;
48 	AVL_Mblk *mb;
49 	size_t nelem;
50 	AVL_Elcomp cmp;
51 	void *v;
52 	void *(*Malloc)(size_t);
53 	void (*Free)(void*);
54 	};
55 
56 #ifndef AVL_TREE_JUST_IMPL_DECLS
57 
58  AVL_Tree*
AVL_Tree_alloc2(void * v,AVL_Elcomp cmp,void * (* Malloc)(size_t),void (* Free)(void *))59 AVL_Tree_alloc2(void *v, AVL_Elcomp cmp, void *(*Malloc)(size_t), void (*Free)(void*))
60 {
61 	AVL_Mblk *mb;
62 	AVL_Tree *T;
63 	Node *N, *Ne;
64 	size_t L;
65 
66 	mb = (AVL_Mblk*)Malloc(L = sizeof(AVL_Tree) + sizeof(AVL_Mblk));
67 	memset(mb, 0, L);
68 	T = (AVL_Tree*)(mb + 1);
69 	T->cmp = cmp;
70 	T->v = v;
71 	T->mb = mb;
72 	T->efree = N = mb->x;
73 	Ne = N + AVL_memgulp - 1;
74 	while(N < Ne)
75 		N = N->left = N + 1;
76 	T->Malloc = Malloc;
77 	T->Free = Free;
78 	return T;
79 	}
80 
81  AVL_Tree*
AVL_Tree_alloc(void * v,AVL_Elcomp cmp,void * (* Malloc)(size_t))82 AVL_Tree_alloc(void *v, AVL_Elcomp cmp, void *(*Malloc)(size_t))
83 { return AVL_Tree_alloc2(v, cmp, Malloc, free); }
84 
85  void
AVL_Tree_free(AVL_Tree ** Tp)86 AVL_Tree_free(AVL_Tree **Tp)
87 {
88 	AVL_Mblk *mb, *mb1;
89 	AVL_Tree *T;
90 
91 	if ((T = *Tp)) {
92 		*Tp = 0;
93 		mb1 = T->mb;
94 		while((mb = mb1)) {
95 			mb1 = mb->next;
96 			T->Free(mb);
97 			}
98 		}
99 	}
100 
101  static Node *
Node_alloc(AVL_Tree * T)102 Node_alloc(AVL_Tree *T)
103 {
104 	AVL_Mblk *mb;
105 	Node *N, *Ne, *Nrv;
106 
107 	mb = (AVL_Mblk*)T->Malloc(sizeof(AVL_Mblk));
108 	memset(mb, 0, sizeof(AVL_Mblk));
109 	mb->next = T->mb;
110 	T->mb = mb;
111 	N = Nrv = mb->x;
112 	Ne = N++ + AVL_memgulp - 1;
113 	T->efree = N;
114 	while(N < Ne)
115 		N = N->left = N + 1;
116 	return Nrv;
117 	}
118 
119  const Element *
AVL_find(const Element * e,AVL_Tree * T)120 AVL_find(const Element *e, AVL_Tree *T)
121 {
122 	Node *N;
123 	int c;
124 
125 	if ((N = T->Top)) {
126  top:
127 		if (!(c = (*T->cmp)(T->v, e, N->elem)))
128 			return N->elem;
129 		if (c < 0) {
130 			if ((N = N->left))
131 				goto top;
132 			return 0;
133 			}
134 		if ((N = N->right))
135 			goto top;
136 		}
137 	return 0;
138 	}
139 
140  void *
AVL_setv(AVL_Tree * T,void * v)141 AVL_setv(AVL_Tree *T, void *v)
142 {
143 	void *rv = T->v;
144 	T->v = v;
145 	return rv;
146 	}
147 
148  static int
avl_findins(const Element * e,Node ** pThis,AVL_Tree * T,const Element ** found)149 avl_findins(const Element *e, Node **pThis, AVL_Tree *T, const Element **found)
150 {
151 	/* return 1 if height increases, else 0 */
152 	/* *pThis = this node (possibly NULL). */
153 	/* *found is set to 0 if e does not occur in the tree, */
154 	/* and is otherwise set to the matching element. */
155 
156 	Node *A, *B, *C, *D, *E, *N;
157 	int c, hB, hC, hD, hE;
158 
159 	if (!(A = *pThis)) {
160 		if ((N = T->efree)) {
161 			T->efree = N->left;
162 			N->left = 0;
163 			}
164 		else
165 			N = Node_alloc(T);
166 		N->elem = e;
167 		*pThis = N;
168 		return 0;
169 		}
170 	c = (*T->cmp)(T->v, e, A->elem);
171 	if (c < 0) {
172 		if (!A->left) {
173 			if ((N = T->efree)) {
174 				T->efree = N->left;
175 				N->left = 0;
176 				}
177 			else
178 				N = Node_alloc(T);
179 			N->elem = e;
180 			A->left = N;
181 			if (A->right)
182 				return 0;
183 			return A->height = 1;
184 			}
185 		if (!avl_findins(e, &A->left, T, found))
186 			return 0;
187 		C = A->left;
188 		hC = C->height;
189 		hB = 0;
190 		if ((B = A->right))
191 			hB = B->height;
192 		if (hC <= hB)
193 			return 0;
194 		if (hC == hB + 1) {
195 			A->height = hB + 2;
196 			return 1;
197 			}
198 		hD = hE = 0;
199 		if ((D = C->right))
200 			hD = D->height;
201 		if ((E = C->left))
202 			hE = E->height;
203 		if (hE > hD) {
204 			/* easy rotation */
205 			C->right = A;
206 			A->left = D;
207 			A->height = hD + 1;
208 			*pThis = C;
209 			return 0;
210 			}
211 		/* hard rotation */
212 		A->left = D->right;
213 		A->height = hB + 1;
214 		C->right = D->left;
215 		C->height = D->height++;
216 		D->left = C;
217 		D->right = A;
218 		*pThis = D;
219 		}
220 	else if (c > 0) {
221 		if (!A->right) {
222 			if ((N = T->efree)) {
223 				T->efree = N->left;
224 				N->left = 0;
225 				}
226 			else
227 				N = Node_alloc(T);
228 			N->elem = e;
229 			A->right = N;
230 			if (A->left)
231 				return 0;
232 			return A->height = 1;
233 			}
234 		if (!avl_findins(e, &A->right, T, found))
235 			return 0;
236 		C = A->right;
237 		hC = C->height;
238 		hB = 0;
239 		if ((B = A->left))
240 			hB = B->height;
241 		if (hC <= hB)
242 			return 0;
243 		if (hC == hB + 1) {
244 			A->height = hB + 2;
245 			return 1;
246 			}
247 		hD = hE = 0;
248 		if ((D = C->left))
249 			hD = D->height;
250 		if ((E = C->right))
251 			hE = E->height;
252 		if (hE > hD) {
253 			/* easy rotation */
254 			C->left = A;
255 			A->right = D;
256 			A->height = hD + 1;
257 			*pThis = C;
258 			return 0;
259 			}
260 		/* hard rotation */
261 		A->right = D->left;
262 		A->height = hB + 1;
263 		C->left = D->right;
264 		C->height = D->height++;
265 		D->right = C;
266 		D->left = A;
267 		*pThis = D;
268 		}
269 	else /* c == 0 */
270 		*found = A->elem;
271 	return 0;
272 	}
273 
274  const Element *
AVL_insert(const Element * e,AVL_Tree * T)275 AVL_insert(const Element *e, AVL_Tree *T)
276 {
277 	const Element *rv;
278 
279 	rv = 0;
280 	avl_findins(e, &T->Top, T, &rv);
281 	if (!rv)
282 		++T->nelem;
283 	return rv;
284 	}
285 
286  size_t
AVL_Tree_size(AVL_Tree * T)287 AVL_Tree_size(AVL_Tree *T)
288 {
289 	return T->nelem;
290 	}
291 
292  static int
avl_visit1(void * v,Node * N,AVL_Visitor V)293 avl_visit1(void *v, Node *N, AVL_Visitor V)
294 {
295 	Node *N1;
296 	int rv;
297  top:
298 	if ((N1 = N->left))
299 		avl_visit1(v, N1, V);
300 	if ((rv = (*V)(v, N->elem)))
301 		return rv;
302 	if ((N = N->right))
303 		goto top;
304 	return 0;
305 	}
306 
307  int
AVL_visit(void * v,AVL_Tree * T,AVL_Visitor V)308 AVL_visit(void *v, AVL_Tree *T, AVL_Visitor V)
309 {
310 	if (!T->Top)
311 		return 0;
312 	return avl_visit1(v, T->Top, V);
313 	}
314 
315 #endif /*AVL_TREE_JUST_IMPL_DECLS*/
316