/* splay.c - code for splay trees Version of August 18, 2001. * Author: Brendan McKay bdm@cs.anu.edu.au This file is not meant to be compiled separately, but to be #included into other programs. Use it like this: 1. Define a node type SPLAYNODE. It must be a structure that contains at least the pointer fields left, right and parent of type SPLAYNODE*. Also define a macro SPLAYNODESIZE giving the size of an object of type SPLAYNODE, unless sizeof(SPLAYNODE) is adequate. 2. Declare a variable of type SPLAYNODE* to point to the root of the tree, and initialise it to NULL. 3. Declare SCAN_ARGS to be the additional arguments needed for splay_scan(), including a leading comma. 4. Declare ACTION(p) for what splay_scan() should do for node p. 5. Declare INSERT_ARGS to be the additional arguments needed for splay_insert(), including a leading comma. 6. Declare COMPARE(p) to compare INSERT_ARGS or LOOKUP_ARGS to the contents of node p. <0, 0, >0 if INSERT_ARGS is greater, equal, less, than p. This has to be an expression with a value, so you will need to make it a procedure call if the comparison is complicated. If you are using something like strcmp, the correct order is strcmp( INSERT_ARGS, p ). 7. Declare PRESENT(p) for what to do if INSERT_ARGS is already present, in node p. There is a spare int variable i available. Typically, this might update some data in the node p. 8. Declare NOT_PRESENT(p) for what to do if INSERT_ARGS is not in the tree and p is a fresh node to hold it. No need to set the left, right, and parent fields. Use i here too if you like. Typically, this might initialise the data in node p. PRESENT(p) and NOT_PRESENT(p) should not manipulate the tree pointers. However, each of them can include a return if you don't want to change the tree. In the case of NOT_PRESENT(p), do free(p) before returning. In the case of PRESENT(p), it is also legal to delete the node from the tree using SCAN_DELETE(to_root,p). In that case you MUST return immediately afterwards. 9. Declare LOOKUP_ARGS to be the additional arguments needed for splay_lookup(), including a leading comma. The default for LOOKUP_ARGS is to be the same as INSERT_ARGS. 10. #include "splay.c" Calls: Suppose "root" is name of the variable described in step 2. There is no need to initialise the tree. Step 2 did that already. To insert something in the tree: splay_insert(&root, ...stuff...) where "stuff" is the stuff you want to insert, declared as INSERT_ARGS. If the key (some part of the stuff decided by you) is present in an existing tree node p, PRESENT(p) is executed. Otherwise, a new tree node p is created and NOT_PRESENT(p) is executed. To look up something in the tree: splay_lookup(&root, ...stuff...) where "stuff" is the stuff you want to find, declared as LOOKUP_ARGS. It will return a pointer to the tree node with the right key, or NULL if there is no such tree node. To do something for each node of the tree: splay_scan(root, ...stuff...) where "stuff" is anything you like (including nothing). This will execute ACTION(p) for each node p in inorder. To delete the node p (which MUST be in the tree: splay_delete(&root, p) Nothing happens if p is NULL, so you can use splay_delete(&root, splay_lookup(&root, ...stuff...)) to delete a node, if any, containing stuff. It is possible to have splay trees of several types in the same program. Just include "splay.c" several times, with the procedure names SPLAY, SPLAY_SCAN, SPLAY_LOOKUP, SPLAY_INSERT, SPLAY_DELETE defined to distinct names. You have to redefine them all even if you aren't using them all. */ #define S_A 0 #define S_L 1 #define S_R 2 #define S_LL 3 #define S_LR 4 #define S_RL 5 #define S_RR 6 #ifndef SPLAYNODESIZE #define SPLAYNODESIZE sizeof(SPLAYNODE) #endif #ifndef LOOKUP_ARGS #define LOOKUP_ARGS INSERT_ARGS #endif #ifndef SPLAY #define SPLAY splay #define SPLAY_SCAN splay_scan #define SPLAY_LOOKUP splay_lookup #define SPLAY_INSERT splay_insert #define SPLAY_DELETE splay_delete #endif /*********************************************************************/ void SPLAY_SCAN(SPLAYNODE *root SCAN_ARGS) /* Do ACTION(p) for each node of the tree, in inorder. Nonrecursive! */ { int code; SPLAYNODE *p; p = root; code = S_A; while (p) { switch (code) /* deliberate flow-ons */ { case S_A: if (p->left) { p = p->left; break; } case S_L: ACTION(p); if (p->right) { p = p->right; code = S_A; break; } case S_R: if (p->parent && p->parent->left == p) code = S_L; else code = S_R; p = p->parent; break; } } } /*********************************************************************/ static void SPLAY(SPLAYNODE *p) /* Splay the node p. It becomes the new root. */ { SPLAYNODE *q,*r,*s; SPLAYNODE *a,*b,*c; int code; #define LCHILD(x,y) {(x)->left = y; if (y) (y)->parent = x;} #define RCHILD(x,y) {(x)->right = y; if (y) (y)->parent = x;} while (p->parent) { a = p->left; b = p->right; q = p->parent; if (q->left == p) { code = S_L; c = q->right; } else { code = S_R; c = q->left; } r = q->parent; if (r) { if (r->left == q) code = (code == S_L ? S_LL : S_LR); else code = (code == S_L ? S_RL : S_RR); s = r->parent; p->parent = s; if (s) { if (s->left == r) s->left = p; else s->right = p; } } else { p->parent = NULL; } switch (code) { case S_L: RCHILD(p,q); LCHILD(q,b); break; case S_R: LCHILD(p,q); RCHILD(q,a); break; case S_LL: RCHILD(p,q); RCHILD(q,r); LCHILD(q,b); LCHILD(r,c); break; case S_RR: LCHILD(p,q); LCHILD(q,r); RCHILD(r,c); RCHILD(q,a); break; case S_LR: LCHILD(p,q); RCHILD(p,r); RCHILD(q,a); LCHILD(r,b); break; case S_RL: LCHILD(p,r); RCHILD(p,q); RCHILD(r,a); LCHILD(q,b); break; } } } /*********************************************************************/ void SPLAY_INSERT(SPLAYNODE **to_root INSERT_ARGS) /* Do insertion operation. On return, the object being inserted is at the root of the tree regardless of whether a new node needed to be created for it. */ { int i,cmp; SPLAYNODE *p,*ppar,*new_node; p = *to_root; cmp = 0; while (p != NULL) { cmp = COMPARE(p); if (cmp == 0) { PRESENT(p); SPLAY(p); *to_root = p; return; } else if (cmp < 0) { ppar = p; p = p->left; } else { ppar = p; p = p->right; } } if ((new_node = (SPLAYNODE*)malloc(SPLAYNODESIZE)) == NULL) { fprintf(stderr,">E malloc failed in splay_insert()\n"); exit(1); } NOT_PRESENT(new_node); new_node->left = new_node->right = NULL; if (cmp == 0) { *to_root = new_node; new_node->parent = NULL; } else if (cmp < 0) { ppar->left = new_node; new_node->parent = ppar; } else { ppar->right = new_node; new_node->parent = ppar; } SPLAY(new_node); *to_root = new_node; } /*********************************************************************/ SPLAYNODE* SPLAY_LOOKUP(SPLAYNODE **to_root LOOKUP_ARGS) /* Do a look-up operation. If found, return a pointer to the node containing it. If not, return NULL. */ { int i,cmp; /* i is available for COMPARE */ SPLAYNODE *p; p = *to_root; cmp = 0; while (p != NULL) { cmp = COMPARE(p); if (cmp == 0) { SPLAY(p); *to_root = p; return p; } else if (cmp < 0) p = p->left; else p = p->right; } return NULL; } /*********************************************************************/ void SPLAY_DELETE(SPLAYNODE **to_root, SPLAYNODE *p) /* Remove node p from the tree and free it. */ { SPLAYNODE *q; if (p == NULL) return; SPLAY(p); *to_root = p; /* Now we have to delete the root. */ /* No right child (includes no children). */ if (!p->right) { *to_root = p->left; if (p->left) p->left->parent = NULL; free(p); return; } /* right child but no left child */ if (!p->left) { *to_root = p->right; p->right->parent = NULL; free(p); return; } /* both children exist */ for (q = p->left; q->right; q = q->right) {} if (q->left) q->left->parent = q->parent; if (q->parent == p) q->parent->left = q->left; else q->parent->right = q->left; q->left = p->left; q->right = p->right; q->parent = NULL; if (p->left) p->left->parent = q; if (p->right) p->right->parent = q; *to_root = q; free(p); } /*********************************************************************/ /* The following shows the tree structure for debugging purposes. If you define SPLAY_DUMP you must also define DUMP_ARGS, DUMP_LEFT, DUMP_RIGHT and DUMP_ACTION(p). */ #ifdef SPLAY_DUMP void SPLAY_DUMP(SPLAYNODE *p DUMP_ARGS) { int i; if (p == NULL) return; if (p->right && p->right->parent != p) fprintf(stderr,"parent misaligned at %p-%p ************\n",p,p->right); if (p->left && p->left->parent != p) fprintf(stderr,"parent misaligned at %p-%p ************\n",p,p->left); SPLAY_DUMP(p->right DUMP_RIGHT); DUMP_ACTION(p); SPLAY_DUMP(p->left DUMP_LEFT); } #endif