blob: 21dd98cac3c4d77c21c35f71286077e97798c134 [file] [log] [blame]
// Note: This file is obtained from
// http://www.cs.utk.edu/~cs140/spring-2005/notes/Splay/
// FIXME: This may not be the most efficient version of splay implementation
// This may be updated with a different splay implementation in near future
#include <stdio.h>
#include "splay.h"
#include <stdlib.h>
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);
}
}
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 = 0;
tree->val = 0;
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;
}
}
}
Splay *splay_find_nearest_ptr(Splay *tree, unsigned long key, int *cmpval)
{
Splay *s, *last;
int cmp;
last = tree;
s = splay_root(tree);
cmp = 1;
while(s != NULL) {
last = s;
if (key == s->key) {
*cmpval = 0;
return s;
} else if (key < (s->key)) {
s = s->left;
cmp = -1;
} else {
if (key < (s->val + s->key)) {
*cmpval = 0;
return s;
}
s = s->right;
cmp = 1;
}
}
*cmpval = cmp;
return last;
}
Splay *splay_find_ptr(Splay *tree, unsigned long key)
{
int cmpval;
Splay *s;
s = splay_find_nearest_ptr(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_ptr(Splay *tree, unsigned long key, Jval val)
{
Splay *parent, *s;
int cmpval;
parent = splay_find_nearest_ptr(tree, key, &cmpval);
return splay_insert(tree, 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;
}
}
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_ptr(Splay *tree, unsigned long key, int *found)
{
int cmpval;
Splay *s;
s = splay_find_nearest_ptr(tree, key, &cmpval);
return finish_gte(cmpval, s, found);
}