#include #include "splay.h" static void rotate(Splay *node) { Splay *parent, *grandparent; if (node->parent->is_sentinel) return; parent = node->parent; grandparent = parent->parent; if (parent->left == node) { parent->left = node->right; if (parent->left != NULL) parent->left->parent = parent; node->right = parent; } else if (parent->right == node) { parent->right = node->left; if (parent->right != NULL) parent->right->parent = parent; node->left = parent; } else { fprintf(stderr, "rotate: error: parent's children are not right\n"); exit(1); } parent->parent = node; node->parent = grandparent; if (grandparent->is_sentinel) { grandparent->parent = node; } else if (grandparent->left == parent) { grandparent->left = node; } else if (grandparent->right == parent) { grandparent->right = node; } else { fprintf(stderr, "rotate: error: grandparent's children are not right\n"); exit(1); } } static void splay(Splay *node) { Splay *parent, *grandparent; if (node->is_sentinel) return; while(1) { if (node->parent->is_sentinel) return; parent = node->parent; grandparent = parent->parent; /* If the node's parent is the root of the tree, do one rotation */ if (grandparent->is_sentinel) { rotate(node); /* If we have a zig-zig, then rotate my parent, then rotate me */ } else if ((parent->left == node && grandparent->left == parent) || (parent->right == node && grandparent->right == parent)) { rotate(parent); rotate(node); /* If we have a zig-zag, then rotate me twice */ } else { rotate(node); rotate(node); } } } Splay *new_splay() { Splay *tree; tree = (Splay *) malloc(sizeof(struct splay)); tree->key = new_jval_v(NULL); tree->val = new_jval_v(NULL); tree->is_sentinel = 1; tree->flink = tree; tree->blink = tree; tree->left = NULL; tree->right = NULL; tree->parent = NULL; return tree; } Splay *splay_root(Splay *tree) { return tree->parent; } Splay *splay_first(Splay *tree) { return tree->flink; } Splay *splay_last(Splay *tree) { return tree->blink; } Splay *splay_next(Splay *node) { return node->flink; } Splay *splay_prev(Splay *node) { return node->blink; } Splay *splay_nil(Splay *tree) { return tree; } void free_splay(Splay *tree) { Splay *ptr; while (1) { ptr = splay_first(tree); if (!ptr->is_sentinel) { splay_delete_node(ptr); } else { free(ptr); return; } } } static Splay *splay_find_nearest_str(Splay *tree, char *key, int *cmpval) { Splay *s, *last; int cmp; last = tree; s = splay_root(tree); cmp = 1; while(s != NULL) { last = s; cmp = strcmp(key, jval_s(s->key)); if (cmp == 0) { *cmpval = 0; return s; } else if (cmp < 0) { s = s->left; } else { s = s->right; } } *cmpval = cmp; return last; } static Splay *splay_find_nearest_gen(Splay *tree, Jval key, int *cmpval, int (*func)(Jval, Jval)) { Splay *s, *last; int cmp; last = tree; s = splay_root(tree); cmp = 1; while(s != NULL) { last = s; cmp = (*func)(key, s->key); if (cmp == 0) { *cmpval = 0; return s; } else if (cmp < 0) { s = s->left; } else { s = s->right; } } *cmpval = cmp; return last; } static Splay *splay_find_nearest_int(Splay *tree, int key, int *cmpval) { Splay *s, *last; int cmp; last = tree; s = splay_root(tree); cmp = 1; while(s != NULL) { last = s; if (key == jval_i(s->key)) { *cmpval = 0; return s; } else if (key < jval_i(s->key)) { s = s->left; cmp = -1; } else { s = s->right; cmp = 1; } } *cmpval = cmp; return last; } static Splay *splay_find_nearest_dbl(Splay *tree, double key, int *cmpval) { Splay *s, *last; int cmp; last = tree; s = splay_root(tree); cmp = 1; while(s != NULL) { last = s; if (key == jval_d(s->key)) { *cmpval = 0; return s; } else if (key < jval_d(s->key)) { s = s->left; cmp = -1; } else { s = s->right; cmp = 1; } } *cmpval = cmp; return last; } Splay *splay_find_str(Splay *tree, char *key) { int cmpval; Splay *s; s = splay_find_nearest_str(tree, key, &cmpval); splay(s); if (cmpval == 0) return s; else return NULL; } Splay *splay_find_gen(Splay *tree, Jval key, int (*func)(Jval, Jval)) { int cmpval; Splay *s; s = splay_find_nearest_gen(tree, key, &cmpval, func); splay(s); if (cmpval == 0) return s; else return NULL; } Splay *splay_find_int(Splay *tree, int key) { int cmpval; Splay *s; s = splay_find_nearest_int(tree, key, &cmpval); splay(s); if (cmpval == 0) return s; else return NULL; } Splay *splay_find_dbl(Splay *tree, double key) { int cmpval; Splay *s; s = splay_find_nearest_dbl(tree, key, &cmpval); splay(s); if (cmpval == 0) return s; else return NULL; } Splay *splay_insert(Splay *tree, Jval key, Jval val, Splay *parent, int cmpval) { Splay *s; s = (Splay *) malloc(sizeof(struct splay)); s->is_sentinel = 0; s->parent = parent; s->left = NULL; s->right = NULL; s->key = key; s->val = val; /* Set the parent's correct child pointer. The only subtle case here is when the key is already in the tree -- then we need to find a leaf node to use as a parent */ /* When we're done here, parent should point to the new node's successor in the linked list */ if (parent->is_sentinel) { parent->parent = s; } else { if (cmpval == 0) { /* If the key is already in the tree, try to insert a new one as the node's right child. If the node already has a right child, then try to insert the new one as a left child. If there is already a left child, then go to parent-flink and insert the node as its left child. */ if (parent->right == NULL) { cmpval = 1; } else if (parent->left == NULL) { cmpval = -1; } else { parent = parent->flink; s->parent = parent; cmpval = -1; } } if (cmpval > 0) { /* Insert as right child */ if (parent->right != NULL) { fprintf(stderr, "splay_insert error: parent->right != NULL"); exit(1); } parent->right = s; parent = parent->flink; } else { if (parent->left != NULL) { fprintf(stderr, "splay_insert error: parent->left != NULL"); exit(1); } parent->left = s; } } s->flink = parent; s->blink = parent->blink; s->flink->blink = s; s->blink->flink = s; splay(s); return s; } Splay *splay_insert_str(Splay *tree, char *key, Jval val) { Splay *parent, *s; int cmpval; parent = splay_find_nearest_str(tree, key, &cmpval); return splay_insert(tree, new_jval_s(key), val, parent, cmpval); } Splay *splay_insert_gen(Splay *tree, Jval key, Jval val, int (*func)(Jval, Jval)) { Splay *parent, *s; int cmpval; parent = splay_find_nearest_gen(tree, key, &cmpval, func); return splay_insert(tree, key, val, parent, cmpval); } Splay *splay_insert_int(Splay *tree, int key, Jval val) { Splay *parent, *s; int cmpval; parent = splay_find_nearest_int(tree, key, &cmpval); return splay_insert(tree, new_jval_i(key), val, parent, cmpval); } Splay *splay_insert_dbl(Splay *tree, double key, Jval val) { Splay *parent, *s; int cmpval; parent = splay_find_nearest_dbl(tree, key, &cmpval); return splay_insert(tree, new_jval_d(key), val, parent, cmpval); } extern void splay_delete_node(Splay *node) { Splay *left, *right, *tree, *newroot; splay(node); tree = node->parent; left = node->left; right = node->right; newroot = node->flink; node->flink->blink = node->blink; node->blink->flink = node->flink; free(node); if (right == NULL && left == NULL) { tree->parent = NULL; } else if (right == NULL) { tree->parent = left; left->parent = tree; } else if (left == NULL) { tree->parent = right; right->parent = tree; } else { tree->parent = right; right->parent = tree; splay(newroot); newroot->left = left; left->parent = newroot; } } static Splay *finish_gte(int cmpval, Splay *s, int *found) { if (cmpval == 0) { *found = 1; return s; } else if (cmpval < 0) { *found = 0; return s; } else { *found = 1; return s->flink; } } Splay *splay_find_gte_str(Splay *tree, char *key, int *found) { int cmpval; Splay *s; s = splay_find_nearest_str(tree, key, &cmpval); return finish_gte(cmpval, s, found); } Splay *splay_find_gte_int(Splay *tree, int key, int *found) { int cmpval; Splay *s; s = splay_find_nearest_int(tree, key, &cmpval); return finish_gte(cmpval, s, found); } Splay *splay_find_gte_dbl(Splay *tree, double key, int *found) { int cmpval; Splay *s; s = splay_find_nearest_dbl(tree, key, &cmpval); return finish_gte(cmpval, s, found); } Splay *splay_find_gte_gen(Splay *tree, Jval key, int *found, int (*func)(Jval, Jval)) { int cmpval; Splay *s; s = splay_find_nearest_gen(tree, key, &cmpval, func); return finish_gte(cmpval, s, found); }