| 227 |
dpurdie |
1 |
/*
|
|
|
2 |
* MS-DOS SHELL - TSEARCH functions
|
|
|
3 |
*
|
|
|
4 |
* MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited
|
|
|
5 |
*
|
|
|
6 |
* This code is subject to the following copyright restrictions. The
|
|
|
7 |
* code for the extended (non BASIC) tsearch.3 functions is based on code
|
|
|
8 |
* written by Peter Valkenburg & Michiel Huisjes. The following copyright
|
|
|
9 |
* conditions apply:
|
|
|
10 |
*
|
|
|
11 |
* 1. Redistribution and use in source and binary forms are permitted
|
|
|
12 |
* provided that the above copyright notice is duplicated in the
|
|
|
13 |
* source form and the copyright notice in file sh6.c is displayed
|
|
|
14 |
* on entry to the program.
|
|
|
15 |
*
|
|
|
16 |
* 2. The sources (or parts thereof) or objects generated from the sources
|
|
|
17 |
* (or parts of sources) cannot be sold under any circumstances.
|
|
|
18 |
*
|
|
|
19 |
* $Header: /cvsroot/device/DEVL/UTILS/SH/Sh12.c,v 1.1 2002/08/02 06:49:33 adamy Exp $
|
|
|
20 |
*
|
|
|
21 |
* $Log: Sh12.c,v $
|
|
|
22 |
* Revision 1.1 2002/08/02 06:49:33 adamy
|
|
|
23 |
* imported (reference only)
|
|
|
24 |
*
|
|
|
25 |
* Revision 1.1 2001/07/20 05:55:44 ayoung
|
|
|
26 |
* WIN32 support
|
|
|
27 |
*
|
|
|
28 |
* Revision 1.1.1.1 1999/12/02 01:11:12 gordonh
|
|
|
29 |
* UTIL
|
|
|
30 |
*
|
|
|
31 |
* Revision 2.7 1994/08/25 20:49:11 istewart
|
|
|
32 |
* MS Shell 2.3 Release
|
|
|
33 |
*
|
|
|
34 |
* Revision 2.6 1994/02/01 10:25:20 istewart
|
|
|
35 |
* Release 2.3 Beta 2, including first NT port
|
|
|
36 |
*
|
|
|
37 |
* Revision 2.5 1993/08/25 16:03:57 istewart
|
|
|
38 |
* Beta 225 - see Notes file
|
|
|
39 |
*
|
|
|
40 |
* Revision 2.4 1993/07/02 10:21:35 istewart
|
|
|
41 |
* 224 Beta fixes
|
|
|
42 |
*
|
|
|
43 |
* Revision 2.3 1993/06/02 09:52:35 istewart
|
|
|
44 |
* Beta 223 Updates - see Notes file
|
|
|
45 |
*
|
|
|
46 |
* Revision 2.2 1993/02/16 16:03:15 istewart
|
|
|
47 |
* Beta 2.22 Release
|
|
|
48 |
*
|
|
|
49 |
* Revision 2.1 1993/01/26 18:35:09 istewart
|
|
|
50 |
* Release 2.2 beta 0
|
|
|
51 |
*
|
|
|
52 |
* Revision 2.0 1992/07/10 10:52:48 istewart
|
|
|
53 |
* 211 Beta updates
|
|
|
54 |
*
|
|
|
55 |
*
|
|
|
56 |
* Start of original notes for the non-BASIC tsearch functions.
|
|
|
57 |
*
|
|
|
58 |
* "tsearch.c", Peter Valkenburg & Michiel Huisjes, november '89.
|
|
|
59 |
*
|
|
|
60 |
* Standard tsearch(3) compatible implementation of AVL height balanced trees.
|
|
|
61 |
* Performance is slightly better than SUN OS tsearch(3) for average case
|
|
|
62 |
* delete/add operations, but worst case behaviour (i.e. when ordinary trees
|
|
|
63 |
* get unbalanced) is much better. Tsearch/tdelete/tfind run in O(2log(n)),
|
|
|
64 |
* twalk in O(n), where n is the size of binary tree.
|
|
|
65 |
*
|
|
|
66 |
* Entry points:
|
|
|
67 |
*
|
|
|
68 |
* _ts_NODE_t *tsearch((void *)key, (_ts_NODE_t **)rootp, int (*compar)());
|
|
|
69 |
* _ts_NODE_t *tdelete((void *)key, (_ts_NODE_t **)rootp, int (*compar)());
|
|
|
70 |
* _ts_NODE_t *tfind((void *)key, (_ts_NODE_t **)rootp, int (*compar)());
|
|
|
71 |
* void twalk((_ts_NODE_t *root), void (*action)());
|
|
|
72 |
*
|
|
|
73 |
* Here key is a pointer to any datum (to be) held in the tree rooted by *rootp
|
|
|
74 |
* or root. Keys are compared by calling compar, which gets two key arguments
|
|
|
75 |
* and should return a value < 0, 0, or > 0, if the first parameter is to be
|
|
|
76 |
* considered less than , equal to, or greater than the second, respectively.
|
|
|
77 |
* Users can declare type (_ts_NODE_t *) as (char *) and (_ts_NODE_t **) as
|
|
|
78 |
* (char **). The return values of tsearch/tdelete/tfind can be used as
|
|
|
79 |
* pointers to the key pointers of their _ts_NODE_t, by casting them to
|
|
|
80 |
* (char **).
|
|
|
81 |
*
|
|
|
82 |
* See manual page tsearch(3) for more extensive user documentation.
|
|
|
83 |
*/
|
|
|
84 |
|
|
|
85 |
#include <sys/types.h>
|
|
|
86 |
#include <sys/stat.h>
|
|
|
87 |
#include <stdio.h>
|
|
|
88 |
#include <string.h>
|
|
|
89 |
#include <setjmp.h>
|
|
|
90 |
#include <unistd.h>
|
|
|
91 |
#include <limits.h>
|
|
|
92 |
#include "sh.h"
|
|
|
93 |
|
|
|
94 |
/*
|
|
|
95 |
* Type for doubly linked AVL tree.
|
|
|
96 |
*/
|
|
|
97 |
|
|
|
98 |
#ifndef BASIC
|
|
|
99 |
typedef struct node_s {
|
|
|
100 |
void *key; /* ptr to datum */
|
|
|
101 |
struct node_s *parent; /* ptr to parent ancestor */
|
|
|
102 |
struct node_s *sibls[2]; /* ptrs to L/R siblings */
|
|
|
103 |
int balance; /* balance value (-1, 0 or +1) */
|
|
|
104 |
} _ts_NODE_t;
|
|
|
105 |
|
|
|
106 |
typedef int _SibIndex_t; /* type for indexing siblings */
|
|
|
107 |
#define L ((_SibIndex_t) 0)
|
|
|
108 |
#define R ((_SibIndex_t) 1)
|
|
|
109 |
|
|
|
110 |
#define LEFT sibls[L]/* left sibling pointer _ts_NODE_t field */
|
|
|
111 |
#define RIGHT sibls[R]/* right sibling pointer _ts_NODE_t field */
|
|
|
112 |
|
|
|
113 |
/*
|
|
|
114 |
* Direction gives direction in which child _ts_NODE_t c is under parent
|
|
|
115 |
* _ts_NODE_t p.
|
|
|
116 |
*/
|
|
|
117 |
|
|
|
118 |
#define direction(p, c) ((_SibIndex_t) ((p)->RIGHT == (c)))
|
|
|
119 |
|
|
|
120 |
/*
|
|
|
121 |
* Cmp_dir gives direction corresponding with compare value v (R iff v > 0).
|
|
|
122 |
*/
|
|
|
123 |
|
|
|
124 |
#define cmp_dir(v) ((_SibIndex_t) ((v) > 0))
|
|
|
125 |
|
|
|
126 |
/*
|
|
|
127 |
* Siblingp yields ptr to left (d == L) or right (d == R) child of _ts_NODE_t n.
|
|
|
128 |
*/
|
|
|
129 |
|
|
|
130 |
#define siblingp(n, d) ((n)->sibls + (d))
|
|
|
131 |
|
|
|
132 |
/*
|
|
|
133 |
* Parentp yields ptr to parent's ptr to _ts_NODE_t n, or root ptr r if n is 0.
|
|
|
134 |
*/
|
|
|
135 |
|
|
|
136 |
#define parentp(r, n) ((n)->parent == (_ts_NODE_t *)NULL ? (r) : \
|
|
|
137 |
siblingp((n)->parent, direction((n)->parent, (n))))
|
|
|
138 |
|
|
|
139 |
/*
|
|
|
140 |
* Dir_bal yields balance value corresponding to _SibIndex_t d.
|
|
|
141 |
*/
|
|
|
142 |
|
|
|
143 |
#define dir_bal(d) ((d) == L ? -1 : 1)
|
|
|
144 |
|
|
|
145 |
static _ts_NODE_t *balance (_ts_NODE_t **, _ts_NODE_t *, int);
|
|
|
146 |
static _ts_NODE_t *single_rotation (_ts_NODE_t **, _ts_NODE_t *,
|
|
|
147 |
_ts_NODE_t *, _SibIndex_t);
|
|
|
148 |
static _ts_NODE_t *double_rotation (_ts_NODE_t **, _ts_NODE_t *,
|
|
|
149 |
_ts_NODE_t *, _SibIndex_t);
|
|
|
150 |
|
|
|
151 |
/*
|
|
|
152 |
* Tsearch adds node key to tree rooted by *rootp, using compar for
|
|
|
153 |
* comparing elements. It returns the pointer to the _ts_NODE_t in which
|
|
|
154 |
* the (possibly already existing) key pointer resides.
|
|
|
155 |
*/
|
|
|
156 |
|
|
|
157 |
void *
|
|
|
158 |
tsearch(void *key, void **root, int (*compar)(const void *, const void *) )
|
|
|
159 |
{
|
|
|
160 |
register _ts_NODE_t *parent, *child;
|
|
|
161 |
_ts_NODE_t *nnode;
|
|
|
162 |
register _SibIndex_t d;
|
|
|
163 |
register int cmp = 0;
|
|
|
164 |
register _ts_NODE_t **rootp = (_ts_NODE_t **)root;
|
|
|
165 |
|
|
|
166 |
if (rootp == (_ts_NODE_t **)NULL)
|
|
|
167 |
return (_ts_NODE_t *)NULL;
|
|
|
168 |
|
|
|
169 |
/* find place where key should go */
|
|
|
170 |
|
|
|
171 |
parent = (_ts_NODE_t *)NULL;
|
|
|
172 |
child = *rootp;
|
|
|
173 |
|
|
|
174 |
while (child != (_ts_NODE_t *)NULL)
|
|
|
175 |
{
|
|
|
176 |
if ((cmp = compar (key, child->key)) == 0)
|
|
|
177 |
return child;
|
|
|
178 |
|
|
|
179 |
parent = child;
|
|
|
180 |
child = *siblingp (child, cmp_dir (cmp));
|
|
|
181 |
}
|
|
|
182 |
|
|
|
183 |
/* create new node and set its parent's sibling pointer */
|
|
|
184 |
|
|
|
185 |
nnode = (_ts_NODE_t *) GetAllocatedSpace (sizeof (_ts_NODE_t));
|
|
|
186 |
|
|
|
187 |
if (nnode == (_ts_NODE_t *)NULL)
|
|
|
188 |
return (_ts_NODE_t *)NULL;
|
|
|
189 |
|
|
|
190 |
SetMemoryAreaNumber ((void *) nnode, 0);
|
|
|
191 |
nnode->key = key;
|
|
|
192 |
nnode->balance = 0;
|
|
|
193 |
nnode->parent = parent;
|
|
|
194 |
nnode->LEFT = nnode->RIGHT = (_ts_NODE_t *)NULL;
|
|
|
195 |
|
|
|
196 |
if (parent == (_ts_NODE_t *)NULL)
|
|
|
197 |
{
|
|
|
198 |
*rootp = nnode;
|
|
|
199 |
return nnode; /* just created tree */
|
|
|
200 |
}
|
|
|
201 |
|
|
|
202 |
*siblingp (parent, cmp_dir(cmp)) = nnode;
|
|
|
203 |
child = nnode;
|
|
|
204 |
|
|
|
205 |
/*
|
|
|
206 |
* Back up until tree is balanced. This is achieved when either
|
|
|
207 |
* the tree is balanced by rotation or a node's balance becomes 0.
|
|
|
208 |
*/
|
|
|
209 |
|
|
|
210 |
do
|
|
|
211 |
{
|
|
|
212 |
d = direction (parent, child);
|
|
|
213 |
|
|
|
214 |
if (parent->balance == dir_bal(d))
|
|
|
215 |
{
|
|
|
216 |
(void) balance (rootp, parent, d);
|
|
|
217 |
return nnode;
|
|
|
218 |
}
|
|
|
219 |
|
|
|
220 |
else if ((parent->balance += dir_bal(d)) == 0)
|
|
|
221 |
return nnode;
|
|
|
222 |
|
|
|
223 |
child = parent;
|
|
|
224 |
parent = parent->parent;
|
|
|
225 |
|
|
|
226 |
} while (parent != (_ts_NODE_t *)NULL);
|
|
|
227 |
|
|
|
228 |
return nnode;
|
|
|
229 |
}
|
|
|
230 |
|
|
|
231 |
/*
|
|
|
232 |
* Tdelete removes key from the tree rooted by *rootp, using compar for
|
|
|
233 |
* comparing elements. It returns the pointer to the _ts_NODE_t that was the
|
|
|
234 |
* parent of the _ts_NODE_t that contained the key pointer, 0 if it did not exist.
|
|
|
235 |
*/
|
|
|
236 |
|
|
|
237 |
void *
|
|
|
238 |
tdelete (void *key, void **root, int (*compar)(const void *, const void *))
|
|
|
239 |
{
|
|
|
240 |
register _ts_NODE_t *parent, *child;
|
|
|
241 |
_ts_NODE_t *dnode, *dparent;
|
|
|
242 |
register _SibIndex_t d;
|
|
|
243 |
register int cont_bal;
|
|
|
244 |
register int cmp;
|
|
|
245 |
register _ts_NODE_t **rootp = (_ts_NODE_t **)root;
|
|
|
246 |
|
|
|
247 |
if (rootp == (_ts_NODE_t **)NULL)
|
|
|
248 |
return (void *)NULL;
|
|
|
249 |
|
|
|
250 |
/* find node to delete */
|
|
|
251 |
|
|
|
252 |
child = *rootp;
|
|
|
253 |
|
|
|
254 |
while (child != (_ts_NODE_t *)NULL)
|
|
|
255 |
{
|
|
|
256 |
if ((cmp = compar (key, child->key)) == 0)
|
|
|
257 |
break;
|
|
|
258 |
|
|
|
259 |
child = *siblingp (child, cmp_dir (cmp));
|
|
|
260 |
}
|
|
|
261 |
|
|
|
262 |
if (child == (_ts_NODE_t *)NULL)
|
|
|
263 |
return (void *)NULL; /* key not in tree */
|
|
|
264 |
|
|
|
265 |
/* the node was found; get its successor (if any) to replace it */
|
|
|
266 |
|
|
|
267 |
dnode = child;
|
|
|
268 |
dparent = dnode->parent;
|
|
|
269 |
child = child->RIGHT;
|
|
|
270 |
|
|
|
271 |
if (child == (_ts_NODE_t *)NULL) /* no successor for key */
|
|
|
272 |
{
|
|
|
273 |
if ((child = dnode->LEFT) != (_ts_NODE_t *)NULL)
|
|
|
274 |
child->parent = dparent; /* set new parent */
|
|
|
275 |
|
|
|
276 |
if (dparent == (_ts_NODE_t *)NULL)
|
|
|
277 |
{
|
|
|
278 |
ReleaseMemoryCell ((void *) dnode);
|
|
|
279 |
*rootp = child;
|
|
|
280 |
return (void *)NULL; /* just deleted the root */
|
|
|
281 |
}
|
|
|
282 |
|
|
|
283 |
d = direction (dparent, dnode); /* for back up */
|
|
|
284 |
*siblingp(dparent, d) = child; /* replace by left child */
|
|
|
285 |
ReleaseMemoryCell ((void *) dnode);
|
|
|
286 |
parent = dparent;
|
|
|
287 |
}
|
|
|
288 |
|
|
|
289 |
else /* key's successor exists */
|
|
|
290 |
{
|
|
|
291 |
while (child->LEFT != (_ts_NODE_t *)NULL)
|
|
|
292 |
child = child->LEFT;
|
|
|
293 |
|
|
|
294 |
parent = child->parent;
|
|
|
295 |
d = direction(parent, child); /* for back up */
|
|
|
296 |
*siblingp(parent, d) = child->RIGHT;
|
|
|
297 |
|
|
|
298 |
if (child->RIGHT != (_ts_NODE_t *)NULL)
|
|
|
299 |
child->RIGHT->parent = parent; /* set new parent */
|
|
|
300 |
|
|
|
301 |
dnode->key = child->key; /* successor replaces key */
|
|
|
302 |
ReleaseMemoryCell ((void *) child);
|
|
|
303 |
}
|
|
|
304 |
|
|
|
305 |
/*
|
|
|
306 |
* Back up until tree is balanced. This is achieved when either the tree is
|
|
|
307 |
* balanced by rotation but not made shorter, or a node's balance was 0 before
|
|
|
308 |
* deletion.
|
|
|
309 |
*/
|
|
|
310 |
|
|
|
311 |
do
|
|
|
312 |
{
|
|
|
313 |
if (parent->balance == dir_bal(!d))
|
|
|
314 |
{
|
|
|
315 |
cont_bal = ((*siblingp(parent, !d))->balance != 0);
|
|
|
316 |
parent = balance(rootp, parent, !d);
|
|
|
317 |
}
|
|
|
318 |
|
|
|
319 |
else
|
|
|
320 |
{
|
|
|
321 |
cont_bal = (parent->balance != 0);
|
|
|
322 |
parent->balance += dir_bal(!d);
|
|
|
323 |
}
|
|
|
324 |
|
|
|
325 |
child = parent;
|
|
|
326 |
|
|
|
327 |
if ((parent = parent->parent) == (_ts_NODE_t *)NULL)
|
|
|
328 |
return dparent; /* we reached the root */
|
|
|
329 |
|
|
|
330 |
d = direction(parent, child);
|
|
|
331 |
|
|
|
332 |
} while (cont_bal);
|
|
|
333 |
|
|
|
334 |
return dparent;
|
|
|
335 |
}
|
|
|
336 |
|
|
|
337 |
/*
|
|
|
338 |
* Balance the subtree rooted at sb that has become to heavy on side d.
|
|
|
339 |
* Also adjusts sibling pointer of the parent of sb, or *rootp if sb is
|
|
|
340 |
* the top of the entire tree.
|
|
|
341 |
*/
|
|
|
342 |
|
|
|
343 |
static _ts_NODE_t *
|
|
|
344 |
balance(_ts_NODE_t **rootp, _ts_NODE_t *sb, _SibIndex_t d)
|
|
|
345 |
{
|
|
|
346 |
_ts_NODE_t *sb_next = *siblingp (sb, d);
|
|
|
347 |
|
|
|
348 |
if (sb_next->balance == -dir_bal(d))
|
|
|
349 |
return double_rotation (rootp, sb, sb_next, d);
|
|
|
350 |
|
|
|
351 |
else
|
|
|
352 |
return single_rotation (rootp, sb, sb_next, d);
|
|
|
353 |
}
|
|
|
354 |
|
|
|
355 |
/*
|
|
|
356 |
* Balance the subtree rooted at sb that has become to heavy on side d
|
|
|
357 |
* by single rotation of sb and sb_next.
|
|
|
358 |
* Also adjusts sibling pointer of the parent of sb, or *rootp if sb is
|
|
|
359 |
* the top of the entire tree.
|
|
|
360 |
*
|
|
|
361 |
* sb sb_next Single rotation: Adding x or
|
|
|
362 |
* / \ / \ deleting under 3 caused
|
|
|
363 |
* sb_next 3 1 sb rotation. Same holds for mirror
|
|
|
364 |
* / \ | / \ image. Single_rotation returns
|
|
|
365 |
* 1 2 ==> x 2 3 top of new balanced tree.
|
|
|
366 |
* | | |
|
|
|
367 |
* x y y
|
|
|
368 |
*/
|
|
|
369 |
|
|
|
370 |
static _ts_NODE_t *
|
|
|
371 |
single_rotation (
|
|
|
372 |
_ts_NODE_t **rootp,
|
|
|
373 |
register _ts_NODE_t *sb, register _ts_NODE_t *sb_next,
|
|
|
374 |
register _SibIndex_t d )
|
|
|
375 |
{
|
|
|
376 |
*siblingp (sb, d) = *siblingp(sb_next, !d);
|
|
|
377 |
*siblingp (sb_next, !d) = sb;
|
|
|
378 |
sb->balance -= sb_next->balance;
|
|
|
379 |
sb_next->balance = -sb->balance;
|
|
|
380 |
*parentp (rootp, sb) = sb_next;
|
|
|
381 |
sb_next->parent = sb->parent;
|
|
|
382 |
sb->parent = sb_next;
|
|
|
383 |
|
|
|
384 |
if (*siblingp (sb, d) != (_ts_NODE_t *)NULL)
|
|
|
385 |
(*siblingp (sb, d))->parent = sb;
|
|
|
386 |
|
|
|
387 |
return sb_next;
|
|
|
388 |
}
|
|
|
389 |
|
|
|
390 |
/*
|
|
|
391 |
* Balance the subtree rooted at sb that has become to heavy on side d
|
|
|
392 |
* by double rotation of sb and sb_next.
|
|
|
393 |
* Also adjusts sibling pointer of the parent of sb, or *rootp if sb is
|
|
|
394 |
* the top of the entire tree.
|
|
|
395 |
*
|
|
|
396 |
* sb sb_next2 Double rotation: Adding x or
|
|
|
397 |
* / \ / \ x', or deleting under 4
|
|
|
398 |
* sb_next \ sb_next sb caused rotation. Same holds
|
|
|
399 |
* / \ \ / \ / \ for the mirror image.
|
|
|
400 |
* 1 sb_next2 4 ==> 1 2 3 4 Double_rotation returns top
|
|
|
401 |
* / \ | | of new balanced tree.
|
|
|
402 |
* 2 3 x x'
|
|
|
403 |
* | |
|
|
|
404 |
* x x'
|
|
|
405 |
*/
|
|
|
406 |
|
|
|
407 |
static _ts_NODE_t *
|
|
|
408 |
double_rotation (
|
|
|
409 |
_ts_NODE_t **rootp,
|
|
|
410 |
register _ts_NODE_t *sb, register _ts_NODE_t *sb_next,
|
|
|
411 |
register _SibIndex_t d )
|
|
|
412 |
{
|
|
|
413 |
register _ts_NODE_t *sb_next2 = *siblingp(sb_next, !d);
|
|
|
414 |
|
|
|
415 |
*siblingp (sb_next, !d) = *siblingp (sb_next2, d);
|
|
|
416 |
*siblingp (sb, d) = *siblingp (sb_next2, !d);
|
|
|
417 |
*siblingp (sb_next2, d) = sb_next;
|
|
|
418 |
*siblingp (sb_next2, !d) = sb;
|
|
|
419 |
|
|
|
420 |
if (sb_next2->balance == sb_next->balance)
|
|
|
421 |
sb_next->balance = -sb_next->balance;
|
|
|
422 |
|
|
|
423 |
else
|
|
|
424 |
sb_next->balance = 0;
|
|
|
425 |
|
|
|
426 |
if (sb_next2->balance == sb->balance)
|
|
|
427 |
sb->balance = -sb->balance;
|
|
|
428 |
|
|
|
429 |
else
|
|
|
430 |
sb->balance = 0;
|
|
|
431 |
|
|
|
432 |
sb_next2->balance = 0;
|
|
|
433 |
*parentp (rootp, sb) = sb_next2;
|
|
|
434 |
sb_next2->parent = sb->parent;
|
|
|
435 |
sb->parent = sb_next->parent = sb_next2;
|
|
|
436 |
|
|
|
437 |
if (*siblingp (sb_next, !d) != (_ts_NODE_t *)NULL)
|
|
|
438 |
(*siblingp (sb_next, !d))->parent = sb_next;
|
|
|
439 |
|
|
|
440 |
if (*siblingp (sb, d) != (_ts_NODE_t *)NULL)
|
|
|
441 |
(*siblingp (sb, d))->parent = sb;
|
|
|
442 |
|
|
|
443 |
return sb_next2;
|
|
|
444 |
}
|
|
|
445 |
|
|
|
446 |
/*
|
|
|
447 |
* Tfind searches node key in the tree rooted by *rootp, using compar for
|
|
|
448 |
* comparing elements. It returns the pointer to the _ts_NODE_t in which
|
|
|
449 |
* the key pointer resides, or 0 if key is not present.
|
|
|
450 |
*/
|
|
|
451 |
|
|
|
452 |
void *
|
|
|
453 |
tfind(void *key, void **root, int (*compar)(const void *, const void *))
|
|
|
454 |
{
|
|
|
455 |
register _ts_NODE_t *node;
|
|
|
456 |
_ts_NODE_t **rootp = (_ts_NODE_t **)root;
|
|
|
457 |
register int cmp;
|
|
|
458 |
|
|
|
459 |
if (rootp == (_ts_NODE_t **)NULL)
|
|
|
460 |
return (void *)NULL;
|
|
|
461 |
|
|
|
462 |
node = *rootp;
|
|
|
463 |
while (node != (_ts_NODE_t *)NULL)
|
|
|
464 |
{
|
|
|
465 |
if ((cmp = compar (key, node->key)) == 0)
|
|
|
466 |
return node;
|
|
|
467 |
|
|
|
468 |
node = *siblingp (node, cmp_dir (cmp));
|
|
|
469 |
}
|
|
|
470 |
|
|
|
471 |
return (void *)NULL;
|
|
|
472 |
}
|
|
|
473 |
|
|
|
474 |
/*
|
|
|
475 |
* Twalk walks the tree rooted by node, from top to bottom and left to right,
|
|
|
476 |
* calling action with the _ts_NODE_t pointer, visit order, and level in the tree
|
|
|
477 |
* (0 is root). Leafs are visited only once and action is then called with
|
|
|
478 |
* `leaf' as the second parameter. For nodes with children action is called
|
|
|
479 |
* three times with visit order parameter `preorder' before, `postorder' in
|
|
|
480 |
* between, and `endorder' after visiting the nodes children.
|
|
|
481 |
*/
|
|
|
482 |
|
|
|
483 |
void
|
|
|
484 |
twalk (const void *start, register void (*action)(const void *, VISIT, int))
|
|
|
485 |
{
|
|
|
486 |
register VISIT visit;
|
|
|
487 |
register int level;
|
|
|
488 |
register _ts_NODE_t *node = (_ts_NODE_t *)start;
|
|
|
489 |
|
|
|
490 |
if ((node == (_ts_NODE_t *)NULL) || (action == 0))
|
|
|
491 |
return;
|
|
|
492 |
|
|
|
493 |
/* run down tree from top to bottom, left to right */
|
|
|
494 |
|
|
|
495 |
visit = preorder;
|
|
|
496 |
level = 0;
|
|
|
497 |
|
|
|
498 |
while (node != (_ts_NODE_t *)NULL)
|
|
|
499 |
{
|
|
|
500 |
if ((visit == preorder) &&
|
|
|
501 |
(node->LEFT == (_ts_NODE_t *)NULL) &&
|
|
|
502 |
(node->RIGHT == (_ts_NODE_t *)NULL))
|
|
|
503 |
visit = leaf; /* node turns out to be leaf */
|
|
|
504 |
|
|
|
505 |
action (node, visit, level);
|
|
|
506 |
|
|
|
507 |
switch (visit)
|
|
|
508 |
{
|
|
|
509 |
case preorder: /* before visiting left child */
|
|
|
510 |
if (node->LEFT != (_ts_NODE_t *)NULL)
|
|
|
511 |
{
|
|
|
512 |
node = node->LEFT;
|
|
|
513 |
level++;
|
|
|
514 |
}
|
|
|
515 |
|
|
|
516 |
else
|
|
|
517 |
visit = postorder;
|
|
|
518 |
|
|
|
519 |
break;
|
|
|
520 |
|
|
|
521 |
case postorder: /* between visiting children */
|
|
|
522 |
if (node->RIGHT != (_ts_NODE_t *)NULL)
|
|
|
523 |
{
|
|
|
524 |
node = node->RIGHT;
|
|
|
525 |
visit = preorder;
|
|
|
526 |
level++;
|
|
|
527 |
}
|
|
|
528 |
|
|
|
529 |
else
|
|
|
530 |
visit = endorder;
|
|
|
531 |
|
|
|
532 |
break;
|
|
|
533 |
|
|
|
534 |
case endorder: /* after visiting children */
|
|
|
535 |
case leaf: /* node has no children */
|
|
|
536 |
if (node->parent != (_ts_NODE_t *)NULL)
|
|
|
537 |
{
|
|
|
538 |
if (direction (node->parent, node) == L)
|
|
|
539 |
visit = postorder;
|
|
|
540 |
|
|
|
541 |
else
|
|
|
542 |
visit = endorder;
|
|
|
543 |
}
|
|
|
544 |
|
|
|
545 |
node = node->parent;
|
|
|
546 |
level--;
|
|
|
547 |
|
|
|
548 |
break;
|
|
|
549 |
}
|
|
|
550 |
}
|
|
|
551 |
}
|
|
|
552 |
#else
|
|
|
553 |
|
|
|
554 |
/*
|
|
|
555 |
* Definition for t.... functions
|
|
|
556 |
*/
|
|
|
557 |
|
|
|
558 |
typedef struct _t_node {
|
|
|
559 |
char *key;
|
|
|
560 |
struct _t_node *llink;
|
|
|
561 |
struct _t_node *rlink;
|
|
|
562 |
} _t_NODE;
|
|
|
563 |
|
|
|
564 |
static void _twalk (_t_NODE *,
|
|
|
565 |
void (*)(const void *, VISIT, int), int);
|
|
|
566 |
/*
|
|
|
567 |
* Basic Tree Processing Functions
|
|
|
568 |
*/
|
|
|
569 |
|
|
|
570 |
/*
|
|
|
571 |
* Delete node with key
|
|
|
572 |
*/
|
|
|
573 |
|
|
|
574 |
void *tdelete (key, rootcp, compar)
|
|
|
575 |
void *key;
|
|
|
576 |
void **rootcp;
|
|
|
577 |
int (*compar)(const void *, const void *);
|
|
|
578 |
{
|
|
|
579 |
_t_NODE *p; /* Parent of node to be deleted */
|
|
|
580 |
register _t_NODE *q; /* Successor node */
|
|
|
581 |
register _t_NODE *r; /* Right son node */
|
|
|
582 |
int ans; /* Result of comparison */
|
|
|
583 |
register _t_NODE **rootp = (_t_NODE **)rootcp;
|
|
|
584 |
|
|
|
585 |
if ((rootp == (_t_NODE **)NULL) || ((p = *rootp) == (_t_NODE *)NULL))
|
|
|
586 |
return (void *)NULL;
|
|
|
587 |
|
|
|
588 |
while ((ans = (*compar)(key, (*rootp)->key)) != 0)
|
|
|
589 |
{
|
|
|
590 |
p = *rootp;
|
|
|
591 |
rootp = (ans < 0) ? &(*rootp)->llink : &(*rootp)->rlink;
|
|
|
592 |
|
|
|
593 |
if (*rootp == (_t_NODE *)NULL)
|
|
|
594 |
return (void *)NULL;
|
|
|
595 |
}
|
|
|
596 |
|
|
|
597 |
r = (*rootp)->rlink;
|
|
|
598 |
|
|
|
599 |
if ((q = (*rootp)->llink) == (_t_NODE *)NULL)
|
|
|
600 |
q = r;
|
|
|
601 |
|
|
|
602 |
else if (r != (_t_NODE *)NULL)
|
|
|
603 |
{
|
|
|
604 |
if (r->llink == (_t_NODE *)NULL)
|
|
|
605 |
{
|
|
|
606 |
r->llink = q;
|
|
|
607 |
q = r;
|
|
|
608 |
}
|
|
|
609 |
|
|
|
610 |
else
|
|
|
611 |
{
|
|
|
612 |
for (q = r->llink; q->llink != (_t_NODE *)NULL; q = r->llink)
|
|
|
613 |
r = q;
|
|
|
614 |
|
|
|
615 |
r->llink = q->rlink;
|
|
|
616 |
q->llink = (*rootp)->llink;
|
|
|
617 |
q->rlink = (*rootp)->rlink;
|
|
|
618 |
}
|
|
|
619 |
}
|
|
|
620 |
|
|
|
621 |
ReleaseMemoryCell ((char *) *rootp);
|
|
|
622 |
*rootp = q;
|
|
|
623 |
return (void *)p;
|
|
|
624 |
}
|
|
|
625 |
|
|
|
626 |
/*
|
|
|
627 |
* Find node with key
|
|
|
628 |
*/
|
|
|
629 |
|
|
|
630 |
void *tfind (key, rootcp, compar)
|
|
|
631 |
void *key; /* Key to be located */
|
|
|
632 |
void **rootcp; /* Address of the root of the tree */
|
|
|
633 |
int (*compar)(const void *, const void *);
|
|
|
634 |
{
|
|
|
635 |
register _t_NODE **rootp = (_t_NODE **)rootcp;
|
|
|
636 |
|
|
|
637 |
if (rootp == (_t_NODE **)NULL)
|
|
|
638 |
return (void *)NULL;
|
|
|
639 |
|
|
|
640 |
while (*rootp != (_t_NODE *)NULL)
|
|
|
641 |
{
|
|
|
642 |
int r = (*compar)(key, (*rootp)->key);
|
|
|
643 |
|
|
|
644 |
if (r == 0)
|
|
|
645 |
return (void *)*rootp;
|
|
|
646 |
|
|
|
647 |
rootp = (r < 0) ? &(*rootp)->llink : &(*rootp)->rlink;
|
|
|
648 |
}
|
|
|
649 |
|
|
|
650 |
return (void *)NULL;
|
|
|
651 |
}
|
|
|
652 |
|
|
|
653 |
/*
|
|
|
654 |
* Search for a node with key key and add it if appropriate
|
|
|
655 |
*/
|
|
|
656 |
|
|
|
657 |
void *tsearch (key, rootcp, compar)
|
|
|
658 |
void *key; /* Key to be located */
|
|
|
659 |
void **rootcp; /* Address of the root of the tree */
|
|
|
660 |
int (*compar)(const void *, const void *);
|
|
|
661 |
{
|
|
|
662 |
register _t_NODE **rootp = (_t_NODE **)rootcp;
|
|
|
663 |
register _t_NODE *q; /* New node if key not found */
|
|
|
664 |
|
|
|
665 |
if (rootp == (_t_NODE **)NULL)
|
|
|
666 |
return (void *)NULL;
|
|
|
667 |
|
|
|
668 |
while (*rootp != (_t_NODE *)NULL)
|
|
|
669 |
{
|
|
|
670 |
int r = (*compar)(key, (*rootp)->key);
|
|
|
671 |
|
|
|
672 |
if (r == 0)
|
|
|
673 |
return (void *)*rootp;
|
|
|
674 |
|
|
|
675 |
rootp = (r < 0) ? &(*rootp)->llink : &(*rootp)->rlink;
|
|
|
676 |
}
|
|
|
677 |
|
|
|
678 |
q = (_t_NODE *) GetAllocatedSpace (sizeof (_t_NODE));
|
|
|
679 |
|
|
|
680 |
if (q != (_t_NODE *)NULL)
|
|
|
681 |
{
|
|
|
682 |
SetMemoryAreaNumber ((void *)q, 0);
|
|
|
683 |
*rootp = q;
|
|
|
684 |
q->key = key;
|
|
|
685 |
q->llink = q->rlink = (_t_NODE *)NULL;
|
|
|
686 |
}
|
|
|
687 |
|
|
|
688 |
return (void *)q;
|
|
|
689 |
}
|
|
|
690 |
|
|
|
691 |
|
|
|
692 |
/* Walk the nodes of a tree */
|
|
|
693 |
|
|
|
694 |
void twalk (root, action)
|
|
|
695 |
const void *root; /* Root of the tree to be walked */
|
|
|
696 |
void (*action)(const void *, VISIT, int);
|
|
|
697 |
{
|
|
|
698 |
if ((root != (char *)NULL) && (action != NULL))
|
|
|
699 |
_twalk (root, action, 0);
|
|
|
700 |
}
|
|
|
701 |
|
|
|
702 |
static void _twalk (root, action, level)
|
|
|
703 |
register _t_NODE *root;
|
|
|
704 |
register void (*action)(const void *, VISIT, int);
|
|
|
705 |
register int level;
|
|
|
706 |
{
|
|
|
707 |
if (root->llink == (_t_NODE *)NULL && root->rlink == NULL)
|
|
|
708 |
(*action)(root, leaf, level);
|
|
|
709 |
|
|
|
710 |
else
|
|
|
711 |
{
|
|
|
712 |
(*action)(root, preorder, level);
|
|
|
713 |
|
|
|
714 |
if (root->llink != (_t_NODE *)NULL)
|
|
|
715 |
_twalk (root->llink, action, level + 1);
|
|
|
716 |
|
|
|
717 |
(*action)(root, postorder, level);
|
|
|
718 |
|
|
|
719 |
if (root->rlink != (_t_NODE *)NULL)
|
|
|
720 |
_twalk (root->rlink, action, level + 1);
|
|
|
721 |
|
|
|
722 |
(*action)(root, endorder, level);
|
|
|
723 |
}
|
|
|
724 |
}
|
|
|
725 |
#endif
|