📄 rbtree.c
字号:
/* * Dynamips * Copyright (c) 2005 Christophe Fillot. * E-mail: cf@utc.fr * * rbtree.c: Red/Black Trees. */static const char rcsid[] = "$Id$";#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <unistd.h>#include <errno.h>#include <signal.h>#include <fcntl.h>#include <ctype.h>#include "utils.h"#include "rbtree.h"#define rbtree_nil(tree) (&(tree)->nil)#define NIL(tree,x) (((x) == rbtree_nil(tree)) || !x)/* Allocate memory for a new node */static rbtree_node *rbtree_node_alloc(rbtree_tree *tree,void *key,void *value){ rbtree_node *node; if (!(node = mp_alloc_n0(&tree->mp,sizeof(*node)))) return NULL; node->key = key; node->value = value; node->left = rbtree_nil(tree); node->right = rbtree_nil(tree); node->parent = rbtree_nil(tree); node->color = -1; return node;}/* Free memory used by a node */static inline void rbtree_node_free(rbtree_tree *tree,rbtree_node *node){ mp_free(node);}/* Returns the node which represents the minimum value */static inline rbtree_node *rbtree_min(rbtree_tree *tree,rbtree_node *x){ while(!NIL(tree,x->left)) x = x->left; return(x);}/* Returns the node which represents the maximum value */static inline rbtree_node *rbtree_max(rbtree_tree *tree,rbtree_node *x){ while(!NIL(tree,x->right)) x = x->right; return(x);}/* Returns the successor of a node */static inline rbtree_node *rbtree_successor(rbtree_tree *tree,rbtree_node *x){ rbtree_node *y; if (!NIL(tree,x->right)) return(rbtree_min(tree,x->right)); y = x->parent; while(!NIL(tree,y) && (x == y->right)) { x = y; y = y->parent; } return(y);}/* Left rotation */static inline void rbtree_left_rotate(rbtree_tree *tree,rbtree_node *x){ rbtree_node *y; y = x->right; x->right = y->left; if (!NIL(tree,x->right)) x->right->parent = x; y->parent = x->parent; if (NIL(tree,x->parent)) tree->root = y; else { if (x == x->parent->left) x->parent->left = y; else x->parent->right = y; } y->left = x; x->parent = y;}/* Right rotation */static inline void rbtree_right_rotate(rbtree_tree *tree,rbtree_node *y){ rbtree_node *x; x = y->left; y->left = x->right; if (!NIL(tree,y->left)) y->left->parent = y; x->parent = y->parent; if (NIL(tree,y->parent)) tree->root = x; else { if (y->parent->left == y) y->parent->left = x; else y->parent->right = x; } x->right = y; y->parent = x;}/* insert a new node */static rbtree_node *rbtree_insert_new(rbtree_tree *tree,void *key,void *value, int *exists){ rbtree_node *parent,*node,*new_node,**nodeplace; int comp; nodeplace = &tree->root; parent = NULL; *exists = FALSE; for(;;) { node = *nodeplace; if (NIL(tree,node)) break; comp = tree->key_cmp(key,node->key,tree->opt_data); if (!comp) { *exists = TRUE; node->value = value; return node; } parent = node; nodeplace = (comp > 0) ? &node->right : &node->left; } /* create a new node */ if (!(new_node = rbtree_node_alloc(tree,key,value))) return NULL; *nodeplace = new_node; new_node->parent = parent; tree->node_count++; return new_node;}/* Insert a node in a Red/Black Tree */int rbtree_insert(rbtree_tree *tree,void *key,void *value){ rbtree_node *x,*y; int exists; /* insert a new node (if necessary) */ x = rbtree_insert_new(tree,key,value,&exists); if (exists) return(0); if (!x) return(-1); tree->node_count++; /* maintains red-black properties */ x->color = RBTREE_RED; while((x != tree->root) && (x->parent->color == RBTREE_RED)) { if (x->parent == x->parent->parent->left) { y = x->parent->parent->right; if (y->color == RBTREE_RED) { x->parent->color = RBTREE_BLACK; y->color = RBTREE_BLACK; x->parent->parent->color = RBTREE_RED; x = x->parent->parent; } else { if (x == x->parent->right) { x = x->parent; rbtree_left_rotate(tree,x); } x->parent->color = RBTREE_BLACK; x->parent->parent->color = RBTREE_RED; rbtree_right_rotate(tree,x->parent->parent); } } else { y = x->parent->parent->left; if (y->color == RBTREE_RED) { x->parent->color = RBTREE_BLACK; y->color = RBTREE_BLACK; x->parent->parent->color = RBTREE_RED; x = x->parent->parent; } else { if (x == x->parent->left) { x = x->parent; rbtree_right_rotate(tree,x); } x->parent->color = RBTREE_BLACK; x->parent->parent->color = RBTREE_RED; rbtree_left_rotate(tree,x->parent->parent); } } } tree->root->color = RBTREE_BLACK; return(0);}/* Lookup for a node corresponding to "key" */static inline rbtree_node *rbtree_lookup_node(rbtree_tree *tree,void *key){ rbtree_node *node; int comp; node = tree->root; for (;;) { if (NIL(tree,node)) /* key not found */ break; if (!(comp = tree->key_cmp(key,node->key,tree->opt_data))) break; /* exact match */ node = (comp > 0) ? node->right : node->left; } return(node);}/* * Lookup for a node corresponding to "key". If node does not exist, * function returns null pointer. */void *rbtree_lookup(rbtree_tree *tree,void *key){ return(rbtree_lookup_node(tree,key)->value);}/* Restore Red/black tree properties after a removal */static void rbtree_removal_fixup(rbtree_tree *tree,rbtree_node *x){ rbtree_node *w; while((x != tree->root) && (x->color == RBTREE_BLACK)) { if (x == x->parent->left) { w = x->parent->right; if (w->color == RBTREE_RED) { w->color = RBTREE_BLACK; x->parent->color = RBTREE_RED; rbtree_left_rotate(tree,x->parent); w = x->parent->right; } if ((w->left->color == RBTREE_BLACK) && (w->right->color == RBTREE_BLACK)) { w->color = RBTREE_RED; x = x->parent; } else { if (w->right->color == RBTREE_BLACK) { w->left->color = RBTREE_BLACK; w->color = RBTREE_RED; rbtree_right_rotate(tree,w); w = x->parent->right; } w->color = x->parent->color; x->parent->color = RBTREE_BLACK; w->right->color = RBTREE_BLACK; rbtree_left_rotate(tree,x->parent); x = tree->root; } } else { w = x->parent->left; if (w->color == RBTREE_RED) { w->color = RBTREE_BLACK; x->parent->color = RBTREE_RED; rbtree_right_rotate(tree,x->parent); w = x->parent->left; } if ((w->right->color == RBTREE_BLACK) && (w->left->color == RBTREE_BLACK)) { w->color = RBTREE_RED; x = x->parent; } else { if (w->left->color == RBTREE_BLACK) { w->right->color = RBTREE_BLACK; w->color = RBTREE_RED; rbtree_left_rotate(tree,w); w = x->parent->left; } w->color = x->parent->color; x->parent->color = RBTREE_BLACK; w->left->color = RBTREE_BLACK; rbtree_right_rotate(tree,x->parent); x = tree->root; } } } x->color = RBTREE_BLACK;}/* Removes a node out of a tree */void *rbtree_remove(rbtree_tree *tree,void *key){ rbtree_node *z = rbtree_lookup_node(tree,key); rbtree_node *x,*y; void *value; if (NIL(tree,z)) return NULL; value = z->value; if (NIL(tree,z->left) || NIL(tree,z->right)) y = z; else y = rbtree_successor(tree,z); if (!NIL(tree,y->left)) x = y->left; else x = y->right; x->parent = y->parent; if (NIL(tree,y->parent)) tree->root = x; else { if (y == y->parent->left) y->parent->left = x; else y->parent->right = x; } if (y != z) { z->key = y->key; z->value = y->value; } if (y->color == RBTREE_BLACK) rbtree_removal_fixup(tree,x); rbtree_node_free(tree,y); tree->node_count++; return(value);}static void rbtree_foreach_node(rbtree_tree *tree,rbtree_node *node, tree_fforeach user_fn,void *opt){ if (!NIL(tree,node)) { rbtree_foreach_node(tree,node->left,user_fn,opt); user_fn(node->key,node->value,opt); rbtree_foreach_node(tree,node->right,user_fn,opt); }}/* Call the specified function for each node */int rbtree_foreach(rbtree_tree *tree,tree_fforeach user_fn,void *opt){ if (!tree) return(-1); rbtree_foreach_node(tree,tree->root,user_fn,opt); return(0);}/* Returns the maximum height of the right and left sub-trees */static int rbtree_height_node(rbtree_tree *tree,rbtree_node *node){ int lh,rh; lh = (!NIL(tree,node->left)) ? rbtree_height_node(tree,node->left) : 0; rh = (!NIL(tree,node->right)) ? rbtree_height_node(tree,node->right) : 0; return(1 + m_max(lh,rh));}/* Compute the height of a Red/Black tree */int rbtree_height(rbtree_tree *tree){ return(!NIL(tree,tree->root) ? rbtree_height_node(tree,tree->root) : 0);}/* Returns the number of nodes */int rbtree_node_count(rbtree_tree *tree){ return(tree->node_count);}/* Purge all nodes */void rbtree_purge(rbtree_tree *tree){ mp_free_all_blocks(&tree->mp); tree->node_count = 0; /* just in case */ memset(rbtree_nil(tree),0,sizeof(rbtree_node)); rbtree_nil(tree)->color = RBTREE_BLACK; /* reset root */ tree->root = rbtree_nil(tree);}/* Check a node */static int rbtree_check_node(rbtree_tree *tree,rbtree_node *node){ if (!NIL(tree,node)) return(0); if (!NIL(tree,node->left)) { if (tree->key_cmp(node->key,node->left->key,tree->opt_data) <= 0) return(-1); if (rbtree_check_node(tree,node->left) == -1) return(-1); } if (!NIL(tree,node->right)) { if (tree->key_cmp(node->key,node->right->key,tree->opt_data) >= 0) return(-1); if (rbtree_check_node(tree,node->right) == -1) return(-1); } return(0);}/* Check tree consistency */int rbtree_check(rbtree_tree *tree){ return(rbtree_check_node(tree,tree->root));}/* Create a new Red/Black tree */rbtree_tree *rbtree_create(tree_fcompare key_cmp,void *opt_data){ rbtree_tree *tree; if (!(tree = malloc(sizeof(*tree)))) return NULL; memset(tree,0,sizeof(*tree)); /* initialize the memory pool */ if (!mp_create_fixed_pool(&tree->mp,"Red-Black Tree")) { free(tree); return NULL; } /* initialize the "nil" pointer */ memset(rbtree_nil(tree),0,sizeof(rbtree_node)); rbtree_nil(tree)->color = RBTREE_BLACK; tree->key_cmp = key_cmp; tree->opt_data = opt_data; tree->root = rbtree_nil(tree); return tree;}/* Delete a Red/Black tree */void rbtree_delete(rbtree_tree *tree){ if (tree) { mp_free_pool(&tree->mp); free(tree); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -