1
/* $Id: avl_Base.cpp.h 4071 2007-08-07 17:07:59Z vboxsync $ */
3
* kAVLBase - basic routines for all AVL trees.
7
* Copyright (C) 2001-2002 knut st. osmundsen (bird-src-spam@anduin.net)
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License as published by the Free Software Foundation,
13
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14
* distribution. VirtualBox OSE is distributed in the hope that it will
15
* be useful, but WITHOUT ANY WARRANTY of any kind.
22
/** @page pg_rt_kAVL kAVL Template configuration.
25
* This is a template made to implement multiple AVL trees. The differences
26
* among the implementations are related to the key used.
29
* Use this to alter the names of the AVL functions.
32
* \#define KAVL_EQUAL_ALLOWED
33
* Define this to tell us that equal keys are allowed.
34
* Then Equal keys will be put in a list pointed to by pList in the KAVLNODECORE.
35
* This is by default not defined.
37
* \#define KAVL_CHECK_FOR_EQUAL_INSERT
38
* Define this to enable insert check for equal nodes.
39
* This is by default not defined.
41
* \#define KAVL_MAX_STACK
42
* Use this to specify the number of stack entries the stack will use when inserting
43
* and removing nodes from the tree. I think the size should be about
44
* log2(<max nodes>) + 3
49
/*******************************************************************************
50
* Defined Constants And Macros *
51
*******************************************************************************/
52
#define AVL_HEIGHTOF(pNode) ((unsigned char)((pNode) != NULL ? pNode->uchHeight : 0))
54
/** @def KAVL_GET_POINTER
55
* Reads a 'pointer' value.
57
* @returns The native pointer.
58
* @param pp Pointer to the pointer to read.
61
/** @def KAVL_GET_POINTER_NULL
62
* Reads a 'pointer' value which can be KAVL_NULL.
64
* @returns The native pointer.
65
* @returns NULL pointer if KAVL_NULL.
66
* @param pp Pointer to the pointer to read.
69
/** @def KAVL_SET_POINTER
70
* Writes a 'pointer' value.
71
* For offset-based schemes offset relative to pp is calculated and assigned to *pp.
73
* @returns stored pointer.
74
* @param pp Pointer to where to store the pointer.
75
* @param p Native pointer to assign to *pp.
78
/** @def KAVL_SET_POINTER_NULL
79
* Writes a 'pointer' value which can be KAVL_NULL.
81
* For offset-based schemes offset relative to pp is calculated and assigned to *pp,
82
* if p is not KAVL_NULL of course.
84
* @returns stored pointer.
85
* @param pp Pointer to where to store the pointer.
86
* @param pp2 Pointer to where to pointer to assign to pp. This can be KAVL_NULL
89
#ifndef KAVL_GET_POINTER
91
# define KAVL_GET_POINTER(pp) ( (PKAVLNODECORE)((intptr_t)(pp) + *(pp)) )
92
# define KAVL_GET_POINTER_NULL(pp) ( *(pp) != KAVL_NULL ? KAVL_GET_POINTER(pp) : NULL )
93
# define KAVL_SET_POINTER(pp, p) ( (*(pp)) = ((intptr_t)(p) - (intptr_t)(pp)) )
94
# define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) != KAVL_NULL ? (intptr_t)KAVL_GET_POINTER(pp2) - (intptr_t)(pp) : KAVL_NULL )
96
# define KAVL_GET_POINTER(pp) ( *(pp) )
97
# define KAVL_GET_POINTER_NULL(pp) ( *(pp) )
98
# define KAVL_SET_POINTER(pp, p) ( (*(pp)) = (p) )
99
# define KAVL_SET_POINTER_NULL(pp, pp2) ( (*(pp)) = *(pp2) )
105
* The NULL 'pointer' equivalent.
111
# define KAVL_NULL NULL
116
# define KAVL_R_IS_INTERSECTING(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B)
117
# define KAVL_R_IS_IDENTICAL(key1B, key2B, key1E, key2E) KAVL_E(key1B, key2B)
122
/*******************************************************************************
123
* Structures and Typedefs *
124
*******************************************************************************/
126
* A stack used to avoid recursive calls...
128
typedef struct _kAvlStack
131
PPKAVLNODECORE aEntries[KAVL_MAX_STACK];
132
} KAVLSTACK, *PKAVLSTACK;
134
typedef struct _kAvlStack2
137
PKAVLNODECORE aEntries[KAVL_MAX_STACK];
138
char achFlags[KAVL_MAX_STACK];
139
} KAVLSTACK2, *PLAVLSTACK2;
144
* Rewinds a stack of pointers to pointers to nodes, rebalancing the tree.
145
* @param pStack Pointer to stack to rewind.
146
* @sketch LOOP thru all stack entries
148
* Get pointer to pointer to node (and pointer to node) from the stack.
149
* IF 2 higher left subtree than in right subtree THEN
151
* IF higher (or equal) left-sub-subtree than right-sub-subtree THEN
154
* n+2 n ==> n+1 n+1|n+2
184
* ELSE IF 2 higher in right subtree than in left subtree THEN
186
* Same as above but left <==> right. (invert the picture)
188
* IF correct height THEN break
189
* ELSE correct height.
192
DECLINLINE(void) KAVL_FN(Rebalance)(PKAVLSTACK pStack)
194
while (pStack->cEntries > 0)
196
/** @todo Perhaps some of these KAVL_SET_POINTER_NULL() cases could be optimized away.. */
197
PPKAVLNODECORE ppNode = pStack->aEntries[--pStack->cEntries];
198
PKAVLNODECORE pNode = KAVL_GET_POINTER(ppNode);
199
PKAVLNODECORE pLeftNode = KAVL_GET_POINTER_NULL(&pNode->pLeft);
200
unsigned char uchLeftHeight = AVL_HEIGHTOF(pLeftNode);
201
PKAVLNODECORE pRightNode = KAVL_GET_POINTER_NULL(&pNode->pRight);
202
unsigned char uchRightHeight = AVL_HEIGHTOF(pRightNode);
204
if (uchRightHeight + 1 < uchLeftHeight)
206
PKAVLNODECORE pLeftLeftNode = KAVL_GET_POINTER_NULL(&pLeftNode->pLeft);
207
PKAVLNODECORE pLeftRightNode = KAVL_GET_POINTER_NULL(&pLeftNode->pRight);
208
unsigned char uchLeftRightHeight = AVL_HEIGHTOF(pLeftRightNode);
210
if (AVL_HEIGHTOF(pLeftLeftNode) >= uchLeftRightHeight)
212
KAVL_SET_POINTER_NULL(&pNode->pLeft, &pLeftNode->pRight);
213
KAVL_SET_POINTER(&pLeftNode->pRight, pNode);
214
pLeftNode->uchHeight = (unsigned char)(1 + (pNode->uchHeight = (unsigned char)(1 + uchLeftRightHeight)));
215
KAVL_SET_POINTER(ppNode, pLeftNode);
219
KAVL_SET_POINTER_NULL(&pLeftNode->pRight, &pLeftRightNode->pLeft);
220
KAVL_SET_POINTER_NULL(&pNode->pLeft, &pLeftRightNode->pRight);
221
KAVL_SET_POINTER(&pLeftRightNode->pLeft, pLeftNode);
222
KAVL_SET_POINTER(&pLeftRightNode->pRight, pNode);
223
pLeftNode->uchHeight = pNode->uchHeight = uchLeftRightHeight;
224
pLeftRightNode->uchHeight = uchLeftHeight;
225
KAVL_SET_POINTER(ppNode, pLeftRightNode);
228
else if (uchLeftHeight + 1 < uchRightHeight)
230
PKAVLNODECORE pRightLeftNode = KAVL_GET_POINTER_NULL(&pRightNode->pLeft);
231
unsigned char uchRightLeftHeight = AVL_HEIGHTOF(pRightLeftNode);
232
PKAVLNODECORE pRightRightNode = KAVL_GET_POINTER_NULL(&pRightNode->pRight);
234
if (AVL_HEIGHTOF(pRightRightNode) >= uchRightLeftHeight)
236
KAVL_SET_POINTER_NULL(&pNode->pRight, &pRightNode->pLeft);
237
KAVL_SET_POINTER(&pRightNode->pLeft, pNode);
238
pRightNode->uchHeight = (unsigned char)(1 + (pNode->uchHeight = (unsigned char)(1 + uchRightLeftHeight)));
239
KAVL_SET_POINTER(ppNode, pRightNode);
243
KAVL_SET_POINTER_NULL(&pRightNode->pLeft, &pRightLeftNode->pRight);
244
KAVL_SET_POINTER_NULL(&pNode->pRight, &pRightLeftNode->pLeft);
245
KAVL_SET_POINTER(&pRightLeftNode->pRight, pRightNode);
246
KAVL_SET_POINTER(&pRightLeftNode->pLeft, pNode);
247
pRightNode->uchHeight = pNode->uchHeight = uchRightLeftHeight;
248
pRightLeftNode->uchHeight = uchRightHeight;
249
KAVL_SET_POINTER(ppNode, pRightLeftNode);
254
register unsigned char uchHeight = (unsigned char)(KMAX(uchLeftHeight, uchRightHeight) + 1);
255
if (uchHeight == pNode->uchHeight)
257
pNode->uchHeight = uchHeight;
267
* Inserts a node into the AVL-tree.
268
* @returns TRUE if inserted.
269
* FALSE if node exists in tree.
270
* @param ppTree Pointer to the AVL-tree root node pointer.
271
* @param pNode Pointer to the node which is to be added.
272
* @sketch Find the location of the node (using binary tree algorithm.):
273
* LOOP until KAVL_NULL leaf pointer
275
* Add node pointer pointer to the AVL-stack.
276
* IF new-node-key < node key THEN
281
* Fill in leaf node and insert it.
282
* Rebalance the tree.
284
RTDECL(bool) KAVL_FN(Insert)(PPKAVLNODECORE ppTree, PKAVLNODECORE pNode)
287
PPKAVLNODECORE ppCurNode = ppTree;
288
register KAVLKEY Key = pNode->Key; NOREF(Key);
290
register KAVLKEY KeyLast = pNode->KeyLast; NOREF(KeyLast);
292
register PKAVLNODECORE pCurNode;
294
AVLStack.cEntries = 0;
303
if (*ppCurNode != KAVL_NULL)
304
pCurNode = KAVL_GET_POINTER(ppCurNode);
308
kASSERT(AVLStack.cEntries < KAVL_MAX_STACK);
309
AVLStack.aEntries[AVLStack.cEntries++] = ppCurNode;
310
#ifdef KAVL_EQUAL_ALLOWED
311
if (KAVL_R_IS_IDENTICAL(pCurNode->Key, Key, pCurNode->KeyLast, KeyLast))
314
* If equal then we'll use a list of equal nodes.
316
pNode->pLeft = pNode->pRight = KAVL_NULL;
317
pNode->uchHeight = 0;
318
KAVL_SET_POINTER_NULL(&pNode->pList, &pCurNode->pList);
319
KAVL_SET_POINTER(&pCurNode->pList, pNode);
323
#ifdef KAVL_CHECK_FOR_EQUAL_INSERT
324
if (KAVL_R_IS_INTERSECTING(pCurNode->Key, Key, pCurNode->KeyLast, KeyLast))
327
if (KAVL_G(pCurNode->Key, Key))
328
ppCurNode = &pCurNode->pLeft;
330
ppCurNode = &pCurNode->pRight;
333
pNode->pLeft = pNode->pRight = KAVL_NULL;
334
#ifdef KAVL_EQUAL_ALLOWED
335
pNode->pList = KAVL_NULL;
337
pNode->uchHeight = 1;
338
KAVL_SET_POINTER(ppCurNode, pNode);
340
KAVL_FN(Rebalance)(SSToDS(&AVLStack));
346
* Removes a node from the AVL-tree.
347
* @returns Pointer to the node.
348
* @param ppTree Pointer to the AVL-tree root node pointer.
349
* @param Key Key value of the node which is to be removed.
350
* @sketch Find the node which is to be removed:
351
* LOOP until not found
353
* Add node pointer pointer to the AVL-stack.
354
* IF the keys matches THEN break!
355
* IF remove key < node key THEN
362
* IF left node not empty THEN
364
* Find the right most node in the left tree while adding the pointer to the pointer to it's parent to the stack:
365
* Start at left node.
366
* LOOP until right node is empty
371
* Link out the found node.
372
* Replace the node which is to be removed with the found node.
373
* Correct the stack entry for the pointer to the left tree.
377
* Move up right node.
378
* Remove last stack entry.
380
* Balance tree using stack.
382
* return pointer to the removed node (if found).
384
RTDECL(PKAVLNODECORE) KAVL_FN(Remove)(PPKAVLNODECORE ppTree, KAVLKEY Key)
387
PPKAVLNODECORE ppDeleteNode = ppTree;
388
register PKAVLNODECORE pDeleteNode;
390
AVLStack.cEntries = 0;
394
if (*ppDeleteNode != KAVL_NULL)
395
pDeleteNode = KAVL_GET_POINTER(ppDeleteNode);
399
kASSERT(AVLStack.cEntries < KAVL_MAX_STACK);
400
AVLStack.aEntries[AVLStack.cEntries++] = ppDeleteNode;
401
if (KAVL_E(pDeleteNode->Key, Key))
404
if (KAVL_G(pDeleteNode->Key, Key))
405
ppDeleteNode = &pDeleteNode->pLeft;
407
ppDeleteNode = &pDeleteNode->pRight;
410
if (pDeleteNode->pLeft != KAVL_NULL)
412
/* find the rightmost node in the left tree. */
413
const unsigned iStackEntry = AVLStack.cEntries;
414
PPKAVLNODECORE ppLeftLeast = &pDeleteNode->pLeft;
415
register PKAVLNODECORE pLeftLeast = KAVL_GET_POINTER(ppLeftLeast);
417
while (pLeftLeast->pRight != KAVL_NULL)
419
kASSERT(AVLStack.cEntries < KAVL_MAX_STACK);
420
AVLStack.aEntries[AVLStack.cEntries++] = ppLeftLeast;
421
ppLeftLeast = &pLeftLeast->pRight;
422
pLeftLeast = KAVL_GET_POINTER(ppLeftLeast);
425
/* link out pLeftLeast */
426
KAVL_SET_POINTER_NULL(ppLeftLeast, &pLeftLeast->pLeft);
428
/* link it in place of the delete node. */
429
KAVL_SET_POINTER_NULL(&pLeftLeast->pLeft, &pDeleteNode->pLeft);
430
KAVL_SET_POINTER_NULL(&pLeftLeast->pRight, &pDeleteNode->pRight);
431
pLeftLeast->uchHeight = pDeleteNode->uchHeight;
432
KAVL_SET_POINTER(ppDeleteNode, pLeftLeast);
433
AVLStack.aEntries[iStackEntry] = &pLeftLeast->pLeft;
437
KAVL_SET_POINTER_NULL(ppDeleteNode, &pDeleteNode->pRight);
441
KAVL_FN(Rebalance)(SSToDS(&AVLStack));