void rbtreeInsert(RBTree tree, void *data) { /* ============ Phase 1 : ajout classique ============ */ Node added = (Node)malloc(sizeof(struct _node)); added->key = data; added->left = added->right = tree->nil; added->color = red; rbtreeClassicTreeInsert(tree, added); Node uncle; /* ============ Phase 2 : gestion des clashs ============ */ while(added->father->color == red) { /* on remonte deux generations à chaque fois */ if(added->father == added->father->father->left) { /* ==== CAS GAUCHE ==== */ uncle = rbgrandpa(added)->right; /* ============ Cas 1 : l'oncle est rouge, on recolorie ============ */ if(uncle->color == red) { added->father->color = uncle->color = black; rbgrandpa(added)->color = red; added = rbgrandpa(added); /* on remonte de deux generations car c'est clean */ } else { /* ============ Cas 3 : l'oncle est noir, on revient sur Cas 2 ============ */ if(added == added->father->right) { added = added->father; rbtreeRotateLeft(tree,added); /* added est de nouveau petit fils */ } /* ============ Cas 2 : l'oncle est noir, coloriage+rota============ */ added->father->color = black; /* on echange les couleurs */ rbgrandpa(added)->color = red; rbtreeRotateRight(tree,rbgrandpa(added)); } } else { /* ==== CAS DROIT ==== */ uncle = rbgrandpa(added)->left; if(uncle->color == red) { added->father->color = uncle->color = black; rbgrandpa(added)->color = red; added = rbgrandpa(added); /* on remonte de deux generations car c'est clean */ } else { if(added == added->father->left) { added = added->father; rbtreeRotateRight(tree,added); } added->father->color = black; rbgrandpa(added)->color = red; rbtreeRotateLeft(tree,rbgrandpa(added)); } } } rbfirst(tree)->color = black; }
/* * Look for a node matching key in tree. * Returns a pointer to the node if found, else NULL. */ struct rbnode * rbfind(struct rbtree *tree, void *key) { struct rbnode *node = rbfirst(tree); int res; while (node != rbnil(tree)) { if ((res = tree->compar(key, node->data)) == 0) return node; node = res < 0 ? node->left : node->right; } return NULL; }
void rbtreeMapDebug(RBTree tree) { assert(!rbtreeEmpty(tree)); Node node; QUEUE queue; queueCreate(&queue); queueAdd(queue,rbfirst(tree)); printf("\033[01;35m==== Début de l'arbre ====\n\033[0m"); do { node = queueRemove(queue); if(rbExists(node->left) || rbExists(node->right) || rbfirst(tree)==node) { if(node->father != tree->root) printf("(pere: %d)",keyPut(node->father->key)); if(node->color==red) printf("\033[01;31m"); if(rbfirst(tree)==node) printf("\033[01;32m"); printf("Noeud %d\033[0m",keyPut(node->key)); if(rbExists(node->left)) { if(node->left->color==red) printf("\033[01;31m"); printf(", "); if(node->left->father != tree->root) printf("(pere: %d) ",keyPut(node->left->father->key)); printf("%d fils gauche\033[0m",keyPut(node->left->key)); } if(rbExists(node->right)) { printf(", "); if(node->right->color==red) printf("\033[01;31m"); if(node->right->father != tree->root) printf("(pere: %d) ",keyPut(node->right->father->key)); printf("%d fils droit\033[0m",keyPut(node->right->key)); } printf("\n"); } if(node->left != tree->nil) queueAdd(queue,node->left); if(node->right != tree->nil) queueAdd(queue,node->right); } while(!queueEmpty(queue)); printf("\n"); }
/* * Look for a node matching key in tree. * Returns a pointer to the node if found, else NULL. */ struct rbnode * rbfind(struct rbtree *tree, void *key) { struct rbnode *node = rbfirst(tree); int res; debug_decl(rbfind, SUDO_DEBUG_RBTREE) while (node != rbnil(tree)) { if ((res = tree->compar(key, node->data)) == 0) debug_return_ptr(node); node = res < 0 ? node->left : node->right; } debug_return_ptr(NULL); }
void rbtreeToDot(RBTree tree, const char* racine, const char* dossier) { assert(!rbtreeEmpty(tree)); static int numerofichier=0; char final[30]; sprintf(final,"%s/%s%d.dot",dossier,racine,numerofichier++); FILE*fd = fopen(final,"wt"); fprintf(fd,"digraph G { \n"); Node node; QUEUE queue; queueCreate(&queue); queueAdd(queue,rbfirst(tree)); do { node = queueRemove(queue); if(node->color==red) fprintf(fd,"\t%d [color=red];\n",keyPut(node->key)); else fprintf(fd,"\t%d [color=black];\n",keyPut(node->key)); if(node->left != tree->nil) { fprintf(fd,"\t%d -> %d;\n",keyPut(node->key),keyPut(node->left->key)); if(node->left->color==red) fprintf(fd,"\t%d [color=red];\n",keyPut(node->left->key)); else fprintf(fd,"\t%d [color=black];\n",keyPut(node->left->key)); } if(node->right != tree->nil) { fprintf(fd,"\t%d -> %d;\n",keyPut(node->key),keyPut(node->right->key)); if(node->right->color==red) fprintf(fd,"\t%d [color=red];\n",keyPut(node->right->key)); else fprintf(fd,"\t%d [color=black];\n",keyPut(node->right->key)); } if(node->left != tree->nil) queueAdd(queue,node->left); if(node->right != tree->nil) queueAdd(queue,node->right); } while(!queueEmpty(queue)); fprintf(fd,"}\n"); fclose(fd); }
/* * Delete node 'z' from the tree and return its data pointer. */ void *rbdelete(struct rbtree *tree, struct rbnode *z) { struct rbnode *x, *y; void *data = z->data; if (z->left == rbnil(tree) || z->right == rbnil(tree)) y = z; else y = rbsuccessor(tree, z); x = (y->left == rbnil(tree)) ? y->right : y->left; if ((x->parent = y->parent) == rbroot(tree)) { rbfirst(tree) = x; } else { if (y == y->parent->left) y->parent->left = x; else y->parent->right = x; } if (y->color == black) rbrepair(tree, x); if (y != z) { y->left = z->left; y->right = z->right; y->parent = z->parent; y->color = z->color; z->left->parent = z->right->parent = y; if (z == z->parent->left) z->parent->left = y; else z->parent->right = y; } free(z); return data; }
/* * Destroy the specified tree, calling the destructor destroy * for each node and then freeing the tree itself. */ void rbdestroy(struct rbtree *tree, void (*destroy)(void *)) { _rbdestroy(tree, rbfirst(tree), destroy); efree(tree); }
/* * Insert data pointer into a redblack tree. * Returns a NULL pointer on success. If a node matching "data" * already exists, a pointer to the existant node is returned. */ struct rbnode * rbinsert(struct rbtree *tree, void *data) { struct rbnode *node = rbfirst(tree); struct rbnode *parent = rbroot(tree); int res; /* Find correct insertion point. */ while (node != rbnil(tree)) { parent = node; if ((res = tree->compar(data, node->data)) == 0) return node; node = res < 0 ? node->left : node->right; } node = (struct rbnode *) emalloc(sizeof(*node)); node->data = data; node->left = node->right = rbnil(tree); node->parent = parent; if (parent == rbroot(tree) || tree->compar(data, parent->data) < 0) parent->left = node; else parent->right = node; node->color = red; /* * If the parent node is black we are all set, if it is red we have * the following possible cases to deal with. We iterate through * the rest of the tree to make sure none of the required properties * is violated. * * 1) The uncle is red. We repaint both the parent and uncle black * and repaint the grandparent node red. * * 2) The uncle is black and the new node is the right child of its * parent, and the parent in turn is the left child of its parent. * We do a left rotation to switch the roles of the parent and * child, relying on further iterations to fixup the old parent. * * 3) The uncle is black and the new node is the left child of its * parent, and the parent in turn is the left child of its parent. * We switch the colors of the parent and grandparent and perform * a right rotation around the grandparent. This makes the former * parent the parent of the new node and the former grandparent. * * Note that because we use a sentinel for the root node we never * need to worry about replacing the root. */ while (node->parent->color == red) { struct rbnode *uncle; if (node->parent == node->parent->parent->left) { uncle = node->parent->parent->right; if (uncle->color == red) { node->parent->color = black; uncle->color = black; node->parent->parent->color = red; node = node->parent->parent; } else /* if (uncle->color == black) */ { if (node == node->parent->right) { node = node->parent; rotate_left(tree, node); } node->parent->color = black; node->parent->parent->color = red; rotate_right(tree, node->parent->parent); } } else { /* if (node->parent == node->parent->parent->right) */ uncle = node->parent->parent->left; if (uncle->color == red) { node->parent->color = black; uncle->color = black; node->parent->parent->color = red; node = node->parent->parent; } else /* if (uncle->color == black) */ { if (node == node->parent->left) { node = node->parent; rotate_right(tree, node); } node->parent->color = black; node->parent->parent->color = red; rotate_left(tree, node->parent->parent); } } } rbfirst(tree)->color = black; /* first node is always black */ return NULL; }
void rbSolveUnbalancedTree(RBTree tree, Node replace, Node replacefather) { /* Soient : * y : replace, le noeud remplacé * p : replacefather, le pere du noeud remplacé * f : frere de y * g : fils gauche de f * d : fils droit de f * */ int isdoubleblack = 1; /* etat de replace */ while(replace != rbfirst(tree) && isdoubleblack) { /* on s'arretera à la racine */ if(replace == replacefather->left) { /* CAS GAUCHE */ if(replacefather->right->color == black) { /* f est noir */ if(replacefather->right->right->color == black && replacefather->right->left->color == black) {/* CAS 1.A */ /*(g et d sont noirs)*/ //printf("Cas 1.A gauche\n"); replace->color = black; /* y devient simple noir */ replacefather->right->color = red; /* f devient rouge */ addBlack(replacefather,&isdoubleblack); /* p devient double noir */ replace = replacefather; /* y devient p */ replacefather = replace->father; } else if(replacefather->right->right->color == red) { /* CAS 1.B */ //printf("Cas 1.B gauche\n"); swapColors(replacefather,replacefather->right); /* f prend la couleur de p */ replacefather->right->right->color = black; /* d devient noir */ replacefather->color = black; /* p devient noir */ rbtreeRotateLeft(tree,replacefather); /* rotation gauche en p */ isdoubleblack = 0; /* y devient noir */ mendSentinels(tree); return; } else if(replacefather->right->left->color == red && replacefather->right->right->color == black) { /* CAS 1.C */ //printf("Cas 1.C gauche\n"); /* f est noir, g est rouge, d est noir */ swapColors(replacefather->right->left,replacefather->right);/* g devient noir, f rouge */ rbtreeRotateRight(tree,replacefather->right); /* rotation droite en f */ /* la prochaine boucle retournera sur 1.B */ } } else { /* f est rouge */ //printf("Cas 2 gauche\n"); swapColors(replacefather,replacefather->right); /* on echange les couleurs de p et f */ rbtreeRotateLeft(tree,replacefather); /* rotation gauche en p */ /* on revient au cas 1 */ } } else { /* CAS DROIT */ if(replacefather->left->color == black) { /* f est noir */ if(replacefather->left->left->color == black && replacefather->left->right->color == black) {/* CAS 1.A */ /*(g et d sont noirs)*/ //printf("Cas 1.A droit\n"); replace->color = black; /* y devient simple noir */ replacefather->left->color = red; /* f devient rouge */ addBlack(replacefather,&isdoubleblack); /* p devient double noir */ replace = replacefather; /* y devient p */ replacefather = replace->father; } else if(replacefather->left->left->color == red) { /* CAS 1.B */ //printf("Cas 1.B droit\n"); swapColors(replacefather,replacefather->left); /* f prend la couleur de p */ replacefather->left->left->color = black; /* d devient noir */ replacefather->color = black; /* p devient noir */ rbtreeRotateRight(tree,replacefather); /* rotation gauche en p */ isdoubleblack = 0; /* y devient noir */ mendSentinels(tree); return; } else if(replacefather->left->right->color == red && replacefather->left->left->color == black) { /* CAS 1.C */ //printf("Cas 1.C droit\n"); /* f est noir, g est rouge, d est noir */ swapColors(replacefather->left->right,replacefather->left);/* g devient noir, f rouge */ rbtreeRotateLeft(tree,replacefather->left); /* rotation droite en f */ /* la prochaine boucle retournera sur 1.B */ } } else { /* f est rouge */ //printf("Cas 2 droit\n"); swapColors(replacefather,replacefather->left); /* on echange les couleurs de p et f */ rbtreeRotateRight(tree,replacefather); /* rotation gauche en p */ /* on revient au cas 1 en ne changeant rien */ } } } mendSentinels(tree); }
/* retourne si le noeud supprime etait rouge ET le noeud remplacant*/ void rbtreeRemove(RBTree tree, void* data) { Node replace, replacefather; Node node = rbfirst(tree); while(!(*tree->equal)(node->key,data)) { node = (*tree->cmp)(node->key,data)?node->right:node->left; } /* node est le noeud à supprimer */ if(rbIsLeaf(node)) { if(node->father->right == node) node->father->right = tree->nil; else node->father->left = tree->nil; replacefather = node->father; replace = tree->nil; } else { /* Ce noeud n'est pas une feuille */ if(node->left == tree->nil) { /* unique noeud à droite */ /* FIXME */ if(node == node->father->right) /* droit en premier pour le cas de la racine */ node->father->right = node->right; else node->father->left = node->right; if(rbExists(node->right)) node->right->father = node->father; /* XXX AJOUTE */ replacefather = node->father; replace = node->right; } else if(node->right == tree->nil) { /* unique noeud à gauche */ if(node == node->father->right) /* droit en premier pour le cas de la racine */ node->father->right = node->left; else node->father->left = node->left; if(rbExists(node->left)) node->left->father = node->father; /* XXX AJOUTE */ replacefather = node->father; replace = node->left; } else { /* ==== deux noeuds ==== */ Node temp = node->right; while(temp->left != tree->nil) /* une fois à droite puis tout à gauche */ temp = temp->left; node->key = temp->key; if(temp->father->left == temp) { temp->father->left = temp->right; /* on raccroche l'hypothetique fils droit de temp */ if(rbExists(temp->right)) temp->right->father = temp->father; } else { temp->father->right = temp->right; /* si temp est juste à droite de node, on raccroche */ if(rbExists(temp->right)) temp->right->father = temp->father; } replacefather = temp->father; replace = temp->right; node = temp; /* histoire d'avoir le meme node que dans le reste du code */ } } /* (x) node est le noeud qui a ete supprime, il devra etre free() XXX */ /* (y_father) node->father == replacefather == replace->father (à tous les coups) */ /* (y) replace est le noeud qui remplace celui qui a ete supprime */ replacefather = node->father; if(node->color == black) { if(replace->color == red) replace->color = black; else rbSolveUnbalancedTree(tree,replace,replacefather); } free(node); }