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