Accueil > > > ARBRE BINAIRE (NON-EQUILIBRE)
ARBRE BINAIRE (NON-EQUILIBRE)
Information sur la source
Description
programme qui montre comment programmer les operations usuelles sur les arbres binaires equilibres
Source
- //----------------------------------------------------------
- // TREE
- //----------------------------------------------------------
- //
- // permet de gerer les arbres non-equilibres
- // les operations possibles sur les arbres sont :
- //
- // * InitTree : initialise un arbre
- // * SetKeyNodeTree : attribu une cle
- // * GetKeyNodeTree : donne la valeur une cle
- // * IsEmptyTree : est-ce-que l'arbre est vide
- // * CloseTree : ferme un arbre
- // * NextNodeTree : l'element suivant (plus grand), le successeur
- // * PrevNodeTree : l'element precedant (plus petit), le predecesseur
- // * MinNodeTree : l'element le plus petit
- // * MaxNodeTree : l'element le plus grand
- // * InsertNodeTree : insert un nouvel element
- // * RemoveNodeTree : enleve un element
- // * SearchNodeTree : recherche un element
- // * LeftRotationNodeTree : rotation gauche sur un noeud
- // * RightRotationNodeTree : rotation droite sur un noeud
- //
- typedef struct tagNODE_TREE
- {
- struct tagNODE_TREE *parent; // parent
- struct tagNODE_TREE *left; // fils de gauche
- struct tagNODE_TREE *right; // fils de droite
- void *key; // cle de tri
- }NODE_TREE,*P_NODE_TREE,**PP_NODE_TREE;
-
- typedef struct tagTREE
- {
- int nElem; // nombre d'elements
- CMP_FUNC cmpFunc; // fonction de comparaison
- void *param; // parametre pour la fonction de comparaison
- P_NODE_TREE root; // racine de l'arbre
- }TREE,*P_TREE,**PP_TREE;
-
- //----------------------------------------------------------
- // TREE
- //----------------------------------------------------------
- #if DBG_LIB_DATA_TREE == DBG_ON
- static int checkTree(P_TREE tree,P_NODE_TREE node)
- {
- int n; // le nombre de noeuds
- AssertNodeTree(tree,node); // verification du noeud
- n = 1; // on compte le noeud courant
- if(NULL != node->left ) // on verifie l'arboresence gauche
- n += checkTree(tree,node->left);
- if(NULL != node->right) // on verifie l'arboresence droite
- n += checkTree(tree,node->right);
-
- // on verifie que l'ordre est repecte
- if(NULL != node->left && NULL != node->right)
- Assert(CMP_LESS == tree->cmpFunc(node->left->key,node->right->key,tree->param));
-
- // on retourne le nombre de noeuds
- return n;
- } // checkTree()
-
- void _AssertTree(P_TREE tree,BOOL bWholeChecking)
- {
- AssertPointer(tree);
- AssertPointer(tree->cmpFunc);
-
- if(0 == tree->nElem)
- {
- Assert(NULL == tree->root);
- }
- else
- {
- int rnd;
- Assert(tree->nElem > 0);
- // la verification doit etre en O(1)
- // donc on l'effectue de temps en temps i.e. tout les 1 fois sur n
- // or la verification de l'arbre est en O(n), donc globalement
- // c'est en O(1)
- rnd = RandomInt(1,tree->nElem);
- if(bWholeChecking || (1 == rnd))
- {
- int n;
- n = checkTree(tree,tree->root);
- Assert(tree->nElem == n);
- }
- }
- PopErrorMacro();
- } // _AssertTree()
- #endif // DBG_LIB_DATA_TREE == DBG_ON
-
-
- //----------------------------------------------------------
- #if DBG_LIB_DATA_TREE == DBG_ON
- void _AssertNodeTree(P_TREE tree,P_NODE_TREE node)
- {
- AssertPointer(node); // verification du noeud
- if(NULL != node->parent) AssertPointer(node->parent); // verification du parent
- if(NULL != node->left ) AssertPointer(node->left ); // verification du fils gauche
- if(NULL != node->right ) AssertPointer(node->right ); // verification du fils droit
-
- if(NULL != node->parent) // est-il bien le fils de son pere ?
- Assert(node->parent->left == node || node->parent->right == node);
-
- if(NULL != node->right && NULL != node->left)
- {
- Assert(node->left != node->right); // les jumeaux sont interdits !
- Assert(node->parent != node->left); // le fils (gauche) ne peut etre le pere
- Assert(node->parent != node->right); // le fils (droit) ne peut etre le pere
- }
- PopErrorMacro();
- } // _AssertNodeTree()
- #endif // DBG_LIB_DATA_TREE == DBG_ON
-
-
- //----------------------------------------------------------
- // fonction en interne
- // calcul le minimum a partir d'un noeud
- static P_NODE_TREE minNode(P_NODE_TREE root)
- {
- P_NODE_TREE min;
- min = root;
- if(NULL != min)
- {
- // les elements plus petits sont a gauche de l'arbre
- while(NULL != min->left)
- {
- min = min->left;
- }
- }
- return min;
- } // minNode()
-
-
- //----------------------------------------------------------
- // fonction en interne
- // calcul le maximum a partir d'un noeud
- static P_NODE_TREE maxNode(P_NODE_TREE root)
- {
- P_NODE_TREE max;
- max = root;
- if(NULL != max)
- {
- // les elements plus petits sont a droite de l'arbre
- while(NULL != max->right)
- {
- max = max->right;
- }
- }
- return max;
- } // maxNode()
-
-
- //----------------------------------------------------------
- // fonction en interne
- // retourne l'adresse du pointeur qui pointe sur le noeud
- static PP_NODE_TREE holdNode(P_TREE tree,P_NODE_TREE node)
- {
- P_NODE_TREE parent;
-
- AssertNodeTree(tree,node);
-
- parent = node->parent;
-
- if(NULL == node->parent) // si le parent n'existe pas, alors c'est la racine de l'arbre
- {
- return &tree->root;
- }
- else if(node == parent->left) // si c'est le fils gauche de son pere
- {
- return &parent->left;
- }
- else // sinon c'est forcement le fils droit de son pere
- {
- Assert(node == parent->right);
- return &parent->right;
- }
-
- } // holdNode()
-
- //----------------------------------------------------------
- P_TREE _InitTree(P_TREE tree,CMP_FUNC cmpFunc,void *param)
- {
- AssertPointer(tree);
- AssertPointer(cmpFunc);
-
- tree->cmpFunc = cmpFunc;
- tree->param = param;
- tree->nElem = 0;
- tree->root = NULL;
-
- PopErrorMacro();
- return tree;
- } // _InitTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _SetKeyNodeTree(P_NODE_TREE node,void *key)
- {
- AssertPointer(node);
- node->key = key;
- PopErrorMacro();
- return node;
- } // _SetKeyNodeTree()
-
-
- //----------------------------------------------------------
- void *_GetKeyNodeTree(P_NODE_TREE node)
- {
- AssertPointer(node);
- PopErrorMacro();
- return node->key;
- } // _GetKeyNodeTree()
-
-
- //----------------------------------------------------------
- BOOL _IsEmptyTree(P_TREE tree)
- {
- AssertTree(tree,FALSE);
- PopErrorMacro();
- return NULL == tree->root;
- } // _IsEmptyTree()
-
-
-
- //----------------------------------------------------------
- P_TREE _CloseTree(P_TREE tree)
- {
- AssertTree(tree,FALSE);
- Assert(0 == tree->nElem);
- Assert(NULL == tree->root);
- PopErrorMacro();
- return tree;
- } // _CloseTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _NextNodeTree(P_TREE tree,P_NODE_TREE node)
- {
- P_NODE_TREE next;
-
- AssertTree(tree,FALSE);
- AssertNodeTree(tree,node);
-
- // s'il y a un fiston droit, alors il existe des elements
- // plus grands que le noeud courant, et plus petits que
- // son pere, le plus petit des noeuds ayants cette
- // propriete est le successeur du noeud courant
- if(NULL != node->right)
- {
- next = minNode(node->right);
- }
- // s'il n'y a pas de fiston droit, le successeur ne se trouve
- // pas a gauche car le successeur est plus grand que le noeud
- //
- // pour comprendre la logique, voici l'arbre suivant avec
- // les petites lettres sont les noeuds dont on cherche leurs
- // successeurs respectifs notes en majuscules :
- //
- // D
- // / \
- // / \
- // / \
- // / \
- // / \
- // B F
- // / \ / \
- // / \ / \
- // A C E G
- // / \ / \ / \ / \
- // a b c d e f g h (H n'existe pas)
- //
- // la logique est alors tres simple, le successeur est parmi
- // ses ancetres (pere, grand-pere, ou arrier-grand-pere
- // dans l'exemple ci-dessus)
- // le successeur est le plus jeune des ancetres dont
- // son fils (qui appartient aux ancetres) est un fils gauche
- // mais s'il n'y a plus de parent, alors il n'y a pas de successeur
- //
- // c'est par cette logique que l'on construit l'exemple du dessus
- // et maintenant il est facile de trouve le successeur
- //
- else
- {
- P_NODE_TREE x; // x represente l'ancetre fils
- P_NODE_TREE y; // x represente l'ancetre pere
-
- x = node;
- y = node->parent;
-
- // tant que l'on est dans la configuration ci-dessous
- // on remonte dans l'arbre genealogique
- //
- // y
- // / \
- // ? x
- //
- while(
- (NULL != y) // s'il y a un pere
- &&
- (x == y->right) // si c'est le fils droit
- )
- {
- // on remonte dans l'arbre genealogique
- x = y;
- y = y->parent;
- AssertNodeTree(tree,x);
- AssertNodeTree(tree,y);
- }
-
- // le successeur est le pere, et le fils est un fils gauche
- //
- // y <------ successeur
- // / \
- // x ?
- // / \
- // ? ... <------ chemin qui mene au noeud dont on cherche le successeur
- next = y;
- }
-
- Assert(NULL == next || (AssertNodeTree(tree,next),TRUE));
- PopErrorMacro();
- return next;
- } // _NextNodeTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _PrevNodeTree(P_TREE tree,P_NODE_TREE node)
- {
- P_NODE_TREE prev;
-
- AssertTree(tree,FALSE);
- AssertNodeTree(tree,node);
-
- // s'il y a un fiston gauche, alors il existe des elements
- // plus petits que le noeud courant, et plus grands que
- // son pere, le plus grand des noeuds ayants cette
- // propriete est le predecesseur du noeud courant
- if(NULL != node->left)
- {
- prev = maxNode(node->left);
- }
- // s'il n'y a pas de fiston gauche, le predecesseur ne se trouve
- // pas a droite car le predecesseur est plus petit que le noeud
- //
- // pour comprendre la logique, voici l'arbre suivant avec
- // les petites lettres sont les noeuds dont on cherche leurs
- // predecesseur respectifs notes en majuscules :
- //
- // E
- // / \
- // / \
- // / \
- // / \
- // / \
- // C G
- // / \ / \
- // / \ / \
- // B D F H
- // / \ / \ / \ / \
- // a b c d e f g h (A n'existe pas)
- //
- // la logique est alors tres simple, le predecesseur est parmi
- // ses ancetres (pere, grand-pere, ou arrier-grand-pere
- // dans l'exemple ci-dessus)
- // le predecesseur est le plus jeune des ancetres dont
- // son fils (qui appartient aux ancetres) est un fils droit
- // mais s'il n'y a plus de parent, alors il n'y a pas de predecesseur
- //
- // c'est par cette logique que l'on construit l'exemple du dessus
- // et maintenant il est facile de trouve le predecesseur
- //
- else
- {
- P_NODE_TREE x; // x represente l'ancetre fils
- P_NODE_TREE y; // x represente l'ancetre pere
-
- x = node;
- y = node->parent;
-
- // tant que l'on est dans la configuration ci-dessous
- // on remonte dans l'arbre genealogique
- //
- // y
- // / \
- // x ?
- //
- while(
- (NULL != y) // s'il y a un pere
- &&
- (x == y->left) // si c'est le fils gauche
- )
- {
- // on remonte dans l'arbre genealogique
- x = y;
- y = y->parent;
- AssertNodeTree(tree,x);
- AssertNodeTree(tree,y);
- }
-
- // le predecesseur est le pere, et le fils est un fils gauche
- //
- // y <------ predecesseur
- // / \
- // ? x
- // / \
- // ? ... <------ chemin qui mene au noeud dont on cherche le predecesseur
- prev = y;
- }
-
- Assert(NULL == prev || (AssertNodeTree(tree,prev),TRUE));
- PopErrorMacro();
- return prev;
- } // _PrevNodeTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _MinNodeTree(P_TREE tree)
- {
- P_NODE_TREE min;
- AssertTree(tree,FALSE);
- min = minNode(tree->root);
- Assert(NULL == min || (AssertNodeTree(tree,min),TRUE));
- PopErrorMacro();
- return min;
- } // _MinNodeTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _MaxNodeTree(P_TREE tree)
- {
- P_NODE_TREE max;
- AssertTree(tree,FALSE);
- max = maxNode(tree->root);
- Assert(NULL == max || (AssertNodeTree(tree,max),TRUE));
- PopErrorMacro();
- return max;
- } // _MaxNodeTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _InsertNodeTree(P_TREE tree,P_NODE_TREE ins)
- {
-
- AssertTree(tree,FALSE);
- AssertPointer(ins);
-
- // le nouvel element n'aura pas de fistons
- ins->left = NULL;
- ins->right = NULL;
-
- // si l'arbre est vide, alors
- if(NULL == tree->root)
- {
- tree->root = ins;
- ins->parent = NULL;
- }
- // on met nouvel element tout en bas de l'arbre
- // comme une "feuille", mais on doit choisir la
- // position suivant ca cle, pour cela on calcule
- // quel element sera le parent que nouveau element
- else
- {
- P_NODE_TREE parent; // le parent
- int r; // resultat des comparaisons
-
- parent = tree->root;
- while(TRUE)
- {
- AssertNodeTree(tree,parent);
-
- r = tree->cmpFunc(ins->key,parent->key,tree->param);
-
- // l'element se trouvera a gauche car il est plus petit
- if(CMP_LESS == r)
- {
- // on a trouve
- if(NULL == parent->left)
- {
- ins->parent = parent;
- parent->left = ins;
- break;
- }
- // on continue
- else
- {
- parent = parent->left;
- }
- }
- // l'element se trouvera a droite car il est plus grand
- else
- {
- Assert(CMP_MORE == r);
- // on a trouve
- if(NULL == parent->right)
- {
- ins->parent = parent;
- parent->right = ins;
- break;
- }
- // on continue
- else
- {
- parent = parent->right;
- }
- }
- }
- }
-
- tree->nElem ++;
-
- AssertTree(tree,FALSE);
-
- PopErrorMacro();
- return ins;
- } // _InsertNodeTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _RemoveNodeTree(P_TREE tree,P_NODE_TREE rem)
- {
- P_NODE_TREE parent; // le parent
- P_NODE_TREE left; // le fils de gauche
- P_NODE_TREE right; // le fils de droite
- PP_NODE_TREE pHold; // celui qui pointe sur <rem>
-
-
- AssertTree(tree,FALSE);
- AssertNodeTree(tree,rem);
-
- // pour la suppression d'un element on distingue
- // trois cas :
- // cas #1 : l'element n'a aucun fils
- // cas #2 : l'element n'a qu'un fils
- // cas #3 : l'element a deux fils
- //
-
- left = rem->left;
- right = rem->right;
- parent = rem->parent;
- pHold = holdNode(tree,rem);
- // il n'y a aucun fils
- if(NULL == left && NULL == right)
- {
- *pHold = NULL;
- }
- // il n'y a que le fils gauche (cas #2)
- else if(NULL != left && NULL == right)
- {
- AssertNodeTree(tree,left);
- left->parent = parent;
- *pHold = left;
- }
- // il n'y a que le fils droit (cas #2)
- else if(NULL == left && NULL != right)
- {
- AssertNodeTree(tree,right);
- right->parent = parent;
- *pHold = right;
- }
- // il y a les deux fils (cas #3)
- else
- {
- P_NODE_TREE next; // le successeur
-
- AssertNodeTree(tree,left);
- AssertNodeTree(tree,right);
- // ce cas est le plus difficile
- // on supprime le successeur qui existe
- // forcement car il a un fils droit
- // donc le successeur est le minimum
- // du fils droit (la suppression
- // releve du cas #1 ou cas #2 car
- // le minimum ne peut avoir un fils gauche)
- // apres il suffit de substituer le successeur
- // a l'element sans modifier la validite de l'arbre
- next = minNode(rem->right);
- AssertNodeTree(tree,next);
- Assert(NULL == next->left);
- RemoveNodeTree(tree,next);
-
- // le membre de droite a peut-etre change
- // et est peut-etre nul
- // en revanche le membre de gauche est non-nul
- right = rem->right;
-
- if(NULL != right)
- right->parent = next; // nouveau parent pour le fils droit
- left->parent = next; // nouveau parent pour le fils gauche
- next->parent = parent; // nouveau parent pour le successeur
- *pHold = next; // nouveau fils pour le pere du successeur
- next->left = left; // nouveau fils gauche pour le successeur
- next->right = right; // nouveau fils droit pour le successeur
- tree->nElem ++;
- }
-
- tree->nElem --;
-
- AssertTree(tree,FALSE);
-
- PopErrorMacro();
- return rem;
- } // _RemoveNodeTree()
-
-
- //----------------------------------------------------------
- P_NODE_TREE _SearchNodeTree(P_TREE tree,void *key)
- {
- P_NODE_TREE res,cur;
-
- AssertTree(tree,FALSE);
-
- res = NULL;
- cur = tree->root;
-
- while(NULL != cur)
- {
- int r;
-
- AssertNodeTree(tree,cur);
-
- r = tree->cmpFunc(key,cur->key,tree->param);
- // BINGO !
- if(CMP_EQUAL == r)
- {
- res = cur;
- break;
- }
- // l'element que l'on recherche est plus petit que l'element courant
- // donc celui que l'on recherche est necessairement a gauche
- else if(CMP_LESS == r)
- {
- cur = cur->left;
- }
- // l'element que l'on recherche est plus grand que l'element courant
- // donc celui que l'on recherche est necessairement a droite
- else
- {
- Assert(CMP_MORE == r);
- cur = cur->right;
- }
- }
-
- PopErrorMacro();
- return res;
- } // _SearchNodeTree()
-
-
- //----------------------------------------------------------
- //
- // x y
- // / \ / \
- // a y ==> x c
- // / \ / \
- // b c a b
- //
- P_NODE_TREE _LeftRotationNodeTree(P_TREE tree,P_NODE_TREE x)
- {
- P_NODE_TREE y;
- P_NODE_TREE b;
- PP_NODE_TREE pHold;
-
- AssertTree(tree,FALSE);
- AssertNodeTree(tree,x);
-
- y = x->right;
- AssertNodeTree(tree,y);
-
- b = y->left;
- Assert(NULL == b || (AssertNodeTree(tree,b),TRUE));
-
- pHold = holdNode(tree,x); // le pointeur qui pointe sur <x>
- *pHold = y; // maintenant on le remplace pas <y>
- y->parent = x->parent; // le parent de <y> est l'ancien parent de <x>
- y->left = x; // le fils gauche de <y> est <x>
- x->parent = y; // le parent de <x> est <y>
- x->right = b; // <b> est maintenant le fils droit de <x>
- if(NULL != b) b->parent = x; // le nouveau pere de <b> est <x>
-
- PopErrorMacro();
- return y;
- } // _LeftRotationNodeTree()
-
-
- //----------------------------------------------------------
- //
- // y x
- // / \ / \
- // x c ==> a y
- // / \ / \
- // a b b c
- //
- P_NODE_TREE _RightRotationNodeTree(P_TREE tree,P_NODE_TREE y)
- {
- P_NODE_TREE x;
- P_NODE_TREE b;
- PP_NODE_TREE pHold;
-
- AssertTree(tree,FALSE);
- AssertNodeTree(tree,y);
-
- x = y->left;
- AssertNodeTree(tree,x);
-
- b = x->right;
- Assert(NULL == b || (AssertNodeTree(tree,b),TRUE));
-
- pHold = holdNode(tree,y); // le pointeur qui pointe sur <y>
- *pHold = x; // maintenant on le remplace pas <x>
- x->parent = y->parent; // le parent de <x> est l'ancien parent de <y>
- x->right = y; // le fils droit de <x> est <y>
- y->parent = x; // le parent de <y> est <x>
- y->left = b; // <b> est maintenant le fils gauche de <y>
- if(NULL != b) b->parent = y; // le nouveau pere de <b> est <y>
-
- PopErrorMacro();
- return x;
- } // _RightRotationNodeTree()
-
-
//----------------------------------------------------------
// TREE
//----------------------------------------------------------
//
// permet de gerer les arbres non-equilibres
// les operations possibles sur les arbres sont :
//
// * InitTree : initialise un arbre
// * SetKeyNodeTree : attribu une cle
// * GetKeyNodeTree : donne la valeur une cle
// * IsEmptyTree : est-ce-que l'arbre est vide
// * CloseTree : ferme un arbre
// * NextNodeTree : l'element suivant (plus grand), le successeur
// * PrevNodeTree : l'element precedant (plus petit), le predecesseur
// * MinNodeTree : l'element le plus petit
// * MaxNodeTree : l'element le plus grand
// * InsertNodeTree : insert un nouvel element
// * RemoveNodeTree : enleve un element
// * SearchNodeTree : recherche un element
// * LeftRotationNodeTree : rotation gauche sur un noeud
// * RightRotationNodeTree : rotation droite sur un noeud
//
typedef struct tagNODE_TREE
{
struct tagNODE_TREE *parent; // parent
struct tagNODE_TREE *left; // fils de gauche
struct tagNODE_TREE *right; // fils de droite
void *key; // cle de tri
}NODE_TREE,*P_NODE_TREE,**PP_NODE_TREE;
typedef struct tagTREE
{
int nElem; // nombre d'elements
CMP_FUNC cmpFunc; // fonction de comparaison
void *param; // parametre pour la fonction de comparaison
P_NODE_TREE root; // racine de l'arbre
}TREE,*P_TREE,**PP_TREE;
//----------------------------------------------------------
// TREE
//----------------------------------------------------------
#if DBG_LIB_DATA_TREE == DBG_ON
static int checkTree(P_TREE tree,P_NODE_TREE node)
{
int n; // le nombre de noeuds
AssertNodeTree(tree,node); // verification du noeud
n = 1; // on compte le noeud courant
if(NULL != node->left ) // on verifie l'arboresence gauche
n += checkTree(tree,node->left);
if(NULL != node->right) // on verifie l'arboresence droite
n += checkTree(tree,node->right);
// on verifie que l'ordre est repecte
if(NULL != node->left && NULL != node->right)
Assert(CMP_LESS == tree->cmpFunc(node->left->key,node->right->key,tree->param));
// on retourne le nombre de noeuds
return n;
} // checkTree()
void _AssertTree(P_TREE tree,BOOL bWholeChecking)
{
AssertPointer(tree);
AssertPointer(tree->cmpFunc);
if(0 == tree->nElem)
{
Assert(NULL == tree->root);
}
else
{
int rnd;
Assert(tree->nElem > 0);
// la verification doit etre en O(1)
// donc on l'effectue de temps en temps i.e. tout les 1 fois sur n
// or la verification de l'arbre est en O(n), donc globalement
// c'est en O(1)
rnd = RandomInt(1,tree->nElem);
if(bWholeChecking || (1 == rnd))
{
int n;
n = checkTree(tree,tree->root);
Assert(tree->nElem == n);
}
}
PopErrorMacro();
} // _AssertTree()
#endif // DBG_LIB_DATA_TREE == DBG_ON
//----------------------------------------------------------
#if DBG_LIB_DATA_TREE == DBG_ON
void _AssertNodeTree(P_TREE tree,P_NODE_TREE node)
{
AssertPointer(node); // verification du noeud
if(NULL != node->parent) AssertPointer(node->parent); // verification du parent
if(NULL != node->left ) AssertPointer(node->left ); // verification du fils gauche
if(NULL != node->right ) AssertPointer(node->right ); // verification du fils droit
if(NULL != node->parent) // est-il bien le fils de son pere ?
Assert(node->parent->left == node || node->parent->right == node);
if(NULL != node->right && NULL != node->left)
{
Assert(node->left != node->right); // les jumeaux sont interdits !
Assert(node->parent != node->left); // le fils (gauche) ne peut etre le pere
Assert(node->parent != node->right); // le fils (droit) ne peut etre le pere
}
PopErrorMacro();
} // _AssertNodeTree()
#endif // DBG_LIB_DATA_TREE == DBG_ON
//----------------------------------------------------------
// fonction en interne
// calcul le minimum a partir d'un noeud
static P_NODE_TREE minNode(P_NODE_TREE root)
{
P_NODE_TREE min;
min = root;
if(NULL != min)
{
// les elements plus petits sont a gauche de l'arbre
while(NULL != min->left)
{
min = min->left;
}
}
return min;
} // minNode()
//----------------------------------------------------------
// fonction en interne
// calcul le maximum a partir d'un noeud
static P_NODE_TREE maxNode(P_NODE_TREE root)
{
P_NODE_TREE max;
max = root;
if(NULL != max)
{
// les elements plus petits sont a droite de l'arbre
while(NULL != max->right)
{
max = max->right;
}
}
return max;
} // maxNode()
//----------------------------------------------------------
// fonction en interne
// retourne l'adresse du pointeur qui pointe sur le noeud
static PP_NODE_TREE holdNode(P_TREE tree,P_NODE_TREE node)
{
P_NODE_TREE parent;
AssertNodeTree(tree,node);
parent = node->parent;
if(NULL == node->parent) // si le parent n'existe pas, alors c'est la racine de l'arbre
{
return &tree->root;
}
else if(node == parent->left) // si c'est le fils gauche de son pere
{
return &parent->left;
}
else // sinon c'est forcement le fils droit de son pere
{
Assert(node == parent->right);
return &parent->right;
}
} // holdNode()
//----------------------------------------------------------
P_TREE _InitTree(P_TREE tree,CMP_FUNC cmpFunc,void *param)
{
AssertPointer(tree);
AssertPointer(cmpFunc);
tree->cmpFunc = cmpFunc;
tree->param = param;
tree->nElem = 0;
tree->root = NULL;
PopErrorMacro();
return tree;
} // _InitTree()
//----------------------------------------------------------
P_NODE_TREE _SetKeyNodeTree(P_NODE_TREE node,void *key)
{
AssertPointer(node);
node->key = key;
PopErrorMacro();
return node;
} // _SetKeyNodeTree()
//----------------------------------------------------------
void *_GetKeyNodeTree(P_NODE_TREE node)
{
AssertPointer(node);
PopErrorMacro();
return node->key;
} // _GetKeyNodeTree()
//----------------------------------------------------------
BOOL _IsEmptyTree(P_TREE tree)
{
AssertTree(tree,FALSE);
PopErrorMacro();
return NULL == tree->root;
} // _IsEmptyTree()
//----------------------------------------------------------
P_TREE _CloseTree(P_TREE tree)
{
AssertTree(tree,FALSE);
Assert(0 == tree->nElem);
Assert(NULL == tree->root);
PopErrorMacro();
return tree;
} // _CloseTree()
//----------------------------------------------------------
P_NODE_TREE _NextNodeTree(P_TREE tree,P_NODE_TREE node)
{
P_NODE_TREE next;
AssertTree(tree,FALSE);
AssertNodeTree(tree,node);
// s'il y a un fiston droit, alors il existe des elements
// plus grands que le noeud courant, et plus petits que
// son pere, le plus petit des noeuds ayants cette
// propriete est le successeur du noeud courant
if(NULL != node->right)
{
next = minNode(node->right);
}
// s'il n'y a pas de fiston droit, le successeur ne se trouve
// pas a gauche car le successeur est plus grand que le noeud
//
// pour comprendre la logique, voici l'arbre suivant avec
// les petites lettres sont les noeuds dont on cherche leurs
// successeurs respectifs notes en majuscules :
//
// D
// / \
// / \
// / \
// / \
// / \
// B F
// / \ / \
// / \ / \
// A C E G
// / \ / \ / \ / \
// a b c d e f g h (H n'existe pas)
//
// la logique est alors tres simple, le successeur est parmi
// ses ancetres (pere, grand-pere, ou arrier-grand-pere
// dans l'exemple ci-dessus)
// le successeur est le plus jeune des ancetres dont
// son fils (qui appartient aux ancetres) est un fils gauche
// mais s'il n'y a plus de parent, alors il n'y a pas de successeur
//
// c'est par cette logique que l'on construit l'exemple du dessus
// et maintenant il est facile de trouve le successeur
//
else
{
P_NODE_TREE x; // x represente l'ancetre fils
P_NODE_TREE y; // x represente l'ancetre pere
x = node;
y = node->parent;
// tant que l'on est dans la configuration ci-dessous
// on remonte dans l'arbre genealogique
//
// y
// / \
// ? x
//
while(
(NULL != y) // s'il y a un pere
&&
(x == y->right) // si c'est le fils droit
)
{
// on remonte dans l'arbre genealogique
x = y;
y = y->parent;
AssertNodeTree(tree,x);
AssertNodeTree(tree,y);
}
// le successeur est le pere, et le fils est un fils gauche
//
// y <------ successeur
// / \
// x ?
// / \
// ? ... <------ chemin qui mene au noeud dont on cherche le successeur
next = y;
}
Assert(NULL == next || (AssertNodeTree(tree,next),TRUE));
PopErrorMacro();
return next;
} // _NextNodeTree()
//----------------------------------------------------------
P_NODE_TREE _PrevNodeTree(P_TREE tree,P_NODE_TREE node)
{
P_NODE_TREE prev;
AssertTree(tree,FALSE);
AssertNodeTree(tree,node);
// s'il y a un fiston gauche, alors il existe des elements
// plus petits que le noeud courant, et plus grands que
// son pere, le plus grand des noeuds ayants cette
// propriete est le predecesseur du noeud courant
if(NULL != node->left)
{
prev = maxNode(node->left);
}
// s'il n'y a pas de fiston gauche, le predecesseur ne se trouve
// pas a droite car le predecesseur est plus petit que le noeud
//
// pour comprendre la logique, voici l'arbre suivant avec
// les petites lettres sont les noeuds dont on cherche leurs
// predecesseur respectifs notes en majuscules :
//
// E
// / \
// / \
// / \
// / \
// / \
// C G
// / \ / \
// / \ / \
// B D F H
// / \ / \ / \ / \
// a b c d e f g h (A n'existe pas)
//
// la logique est alors tres simple, le predecesseur est parmi
// ses ancetres (pere, grand-pere, ou arrier-grand-pere
// dans l'exemple ci-dessus)
// le predecesseur est le plus jeune des ancetres dont
// son fils (qui appartient aux ancetres) est un fils droit
// mais s'il n'y a plus de parent, alors il n'y a pas de predecesseur
//
// c'est par cette logique que l'on construit l'exemple du dessus
// et maintenant il est facile de trouve le predecesseur
//
else
{
P_NODE_TREE x; // x represente l'ancetre fils
P_NODE_TREE y; // x represente l'ancetre pere
x = node;
y = node->parent;
// tant que l'on est dans la configuration ci-dessous
// on remonte dans l'arbre genealogique
//
// y
// / \
// x ?
//
while(
(NULL != y) // s'il y a un pere
&&
(x == y->left) // si c'est le fils gauche
)
{
// on remonte dans l'arbre genealogique
x = y;
y = y->parent;
AssertNodeTree(tree,x);
AssertNodeTree(tree,y);
}
// le predecesseur est le pere, et le fils est un fils gauche
//
// y <------ predecesseur
// / \
// ? x
// / \
// ? ... <------ chemin qui mene au noeud dont on cherche le predecesseur
prev = y;
}
Assert(NULL == prev || (AssertNodeTree(tree,prev),TRUE));
PopErrorMacro();
return prev;
} // _PrevNodeTree()
//----------------------------------------------------------
P_NODE_TREE _MinNodeTree(P_TREE tree)
{
P_NODE_TREE min;
AssertTree(tree,FALSE);
min = minNode(tree->root);
Assert(NULL == min || (AssertNodeTree(tree,min),TRUE));
PopErrorMacro();
return min;
} // _MinNodeTree()
//----------------------------------------------------------
P_NODE_TREE _MaxNodeTree(P_TREE tree)
{
P_NODE_TREE max;
AssertTree(tree,FALSE);
max = maxNode(tree->root);
Assert(NULL == max || (AssertNodeTree(tree,max),TRUE));
PopErrorMacro();
return max;
} // _MaxNodeTree()
//----------------------------------------------------------
P_NODE_TREE _InsertNodeTree(P_TREE tree,P_NODE_TREE ins)
{
AssertTree(tree,FALSE);
AssertPointer(ins);
// le nouvel element n'aura pas de fistons
ins->left = NULL;
ins->right = NULL;
// si l'arbre est vide, alors
if(NULL == tree->root)
{
tree->root = ins;
ins->parent = NULL;
}
// on met nouvel element tout en bas de l'arbre
// comme une "feuille", mais on doit choisir la
// position suivant ca cle, pour cela on calcule
// quel element sera le parent que nouveau element
else
{
P_NODE_TREE parent; // le parent
int r; // resultat des comparaisons
parent = tree->root;
while(TRUE)
{
AssertNodeTree(tree,parent);
r = tree->cmpFunc(ins->key,parent->key,tree->param);
// l'element se trouvera a gauche car il est plus petit
if(CMP_LESS == r)
{
// on a trouve
if(NULL == parent->left)
{
ins->parent = parent;
parent->left = ins;
break;
}
// on continue
else
{
parent = parent->left;
}
}
// l'element se trouvera a droite car il est plus grand
else
{
Assert(CMP_MORE == r);
// on a trouve
if(NULL == parent->right)
{
ins->parent = parent;
parent->right = ins;
break;
}
// on continue
else
{
parent = parent->right;
}
}
}
}
tree->nElem ++;
AssertTree(tree,FALSE);
PopErrorMacro();
return ins;
} // _InsertNodeTree()
//----------------------------------------------------------
P_NODE_TREE _RemoveNodeTree(P_TREE tree,P_NODE_TREE rem)
{
P_NODE_TREE parent; // le parent
P_NODE_TREE left; // le fils de gauche
P_NODE_TREE right; // le fils de droite
PP_NODE_TREE pHold; // celui qui pointe sur <rem>
AssertTree(tree,FALSE);
AssertNodeTree(tree,rem);
// pour la suppression d'un element on distingue
// trois cas :
// cas #1 : l'element n'a aucun fils
// cas #2 : l'element n'a qu'un fils
// cas #3 : l'element a deux fils
//
left = rem->left;
right = rem->right;
parent = rem->parent;
pHold = holdNode(tree,rem);
// il n'y a aucun fils
if(NULL == left && NULL == right)
{
*pHold = NULL;
}
// il n'y a que le fils gauche (cas #2)
else if(NULL != left && NULL == right)
{
AssertNodeTree(tree,left);
left->parent = parent;
*pHold = left;
}
// il n'y a que le fils droit (cas #2)
else if(NULL == left && NULL != right)
{
AssertNodeTree(tree,right);
right->parent = parent;
*pHold = right;
}
// il y a les deux fils (cas #3)
else
{
P_NODE_TREE next; // le successeur
AssertNodeTree(tree,left);
AssertNodeTree(tree,right);
// ce cas est le plus difficile
// on supprime le successeur qui existe
// forcement car il a un fils droit
// donc le successeur est le minimum
// du fils droit (la suppression
// releve du cas #1 ou cas #2 car
// le minimum ne peut avoir un fils gauche)
// apres il suffit de substituer le successeur
// a l'element sans modifier la validite de l'arbre
next = minNode(rem->right);
AssertNodeTree(tree,next);
Assert(NULL == next->left);
RemoveNodeTree(tree,next);
// le membre de droite a peut-etre change
// et est peut-etre nul
// en revanche le membre de gauche est non-nul
right = rem->right;
if(NULL != right)
right->parent = next; // nouveau parent pour le fils droit
left->parent = next; // nouveau parent pour le fils gauche
next->parent = parent; // nouveau parent pour le successeur
*pHold = next; // nouveau fils pour le pere du successeur
next->left = left; // nouveau fils gauche pour le successeur
next->right = right; // nouveau fils droit pour le successeur
tree->nElem ++;
}
tree->nElem --;
AssertTree(tree,FALSE);
PopErrorMacro();
return rem;
} // _RemoveNodeTree()
//----------------------------------------------------------
P_NODE_TREE _SearchNodeTree(P_TREE tree,void *key)
{
P_NODE_TREE res,cur;
AssertTree(tree,FALSE);
res = NULL;
cur = tree->root;
while(NULL != cur)
{
int r;
AssertNodeTree(tree,cur);
r = tree->cmpFunc(key,cur->key,tree->param);
// BINGO !
if(CMP_EQUAL == r)
{
res = cur;
break;
}
// l'element que l'on recherche est plus petit que l'element courant
// donc celui que l'on recherche est necessairement a gauche
else if(CMP_LESS == r)
{
cur = cur->left;
}
// l'element que l'on recherche est plus grand que l'element courant
// donc celui que l'on recherche est necessairement a droite
else
{
Assert(CMP_MORE == r);
cur = cur->right;
}
}
PopErrorMacro();
return res;
} // _SearchNodeTree()
//----------------------------------------------------------
//
// x y
// / \ / \
// a y ==> x c
// / \ / \
// b c a b
//
P_NODE_TREE _LeftRotationNodeTree(P_TREE tree,P_NODE_TREE x)
{
P_NODE_TREE y;
P_NODE_TREE b;
PP_NODE_TREE pHold;
AssertTree(tree,FALSE);
AssertNodeTree(tree,x);
y = x->right;
AssertNodeTree(tree,y);
b = y->left;
Assert(NULL == b || (AssertNodeTree(tree,b),TRUE));
pHold = holdNode(tree,x); // le pointeur qui pointe sur <x>
*pHold = y; // maintenant on le remplace pas <y>
y->parent = x->parent; // le parent de <y> est l'ancien parent de <x>
y->left = x; // le fils gauche de <y> est <x>
x->parent = y; // le parent de <x> est <y>
x->right = b; // <b> est maintenant le fils droit de <x>
if(NULL != b) b->parent = x; // le nouveau pere de <b> est <x>
PopErrorMacro();
return y;
} // _LeftRotationNodeTree()
//----------------------------------------------------------
//
// y x
// / \ / \
// x c ==> a y
// / \ / \
// a b b c
//
P_NODE_TREE _RightRotationNodeTree(P_TREE tree,P_NODE_TREE y)
{
P_NODE_TREE x;
P_NODE_TREE b;
PP_NODE_TREE pHold;
AssertTree(tree,FALSE);
AssertNodeTree(tree,y);
x = y->left;
AssertNodeTree(tree,x);
b = x->right;
Assert(NULL == b || (AssertNodeTree(tree,b),TRUE));
pHold = holdNode(tree,y); // le pointeur qui pointe sur <y>
*pHold = x; // maintenant on le remplace pas <x>
x->parent = y->parent; // le parent de <x> est l'ancien parent de <y>
x->right = y; // le fils droit de <x> est <y>
y->parent = x; // le parent de <y> est <x>
y->left = b; // <b> est maintenant le fils gauche de <y>
if(NULL != b) b->parent = y; // le nouveau pere de <b> est <y>
PopErrorMacro();
return x;
} // _RightRotationNodeTree()
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
AVL : Abre binaire équilibré [ par Sebest ]
Bonsoir, Je recherche un algorithme qui équilibre un arbre binaire après l'ajout d'un nouvel élément. C'est la technique où on regarde la hauteur et o
Arbre Binaire [ par Fury_Vash ]
je souhaite savoir si il y a pas de code pour chercher le niveau d'un element dans un arbre j'ai tout essayer mais je ne suis pas parvenu a trouver
Arbre Binaire Equilibré [ par messier79 ]
BonjourJe voudrais savoir comment implémenter un arbre Binaire de Recherche (ou un Arbre Equilibré) en utilisant la STL.Si possible avec un exemple...
arbre binaire [ par moltese ]
Salut, je cherche à savoir si il est possible de créer un arbre binaire par itération? Et si oui est-il possible d'en avoir le code? Merci
expression mathematique sous forme d'arbre binaire [ par Milhouse57 ]
Je recherche un code qui transformerait une expression mathematique (donnée par l'utilisateur sous forme de chaine de charactere) en un arbre binaire
arbre binaire de recherche equilibrée [ par mrihab ]
salut je suis une etudiante en informatique je veux savoir comment realiser une interface graphique representant cette arbre binaire equilibrée
arbre binaire [ par ghounaya ]
je cherche une simulation graphique des arbres binaires :recherche,ajout et suppression d'un élément.
arbre binaire [ par stephanelin ]
Bonsoir,comment créer un tableau qui effectue un tri décroissant (d'entiers), en utilisant la notion d'arbre binaire ?MerciStéphane
Arbre binaire profondeur hauteur [ par ecolopolo ]
BonjourJe chercher à savoir ce que représente exatement tout ce qui concerne les arbres binaire, par exemple la différence entre la hau
arbre binaire itératif [ par fred100582 ]
Salut, je travaille en ce moment sur un arbre binaire mais je ne dois utiliser ni la récursivité ni les pointeurs pour les sous-arbres et je
|
Derniers Blogs
IMAGINE CUP 2012, MAKE A SIGN EN FINALEIMAGINE CUP 2012, MAKE A SIGN EN FINALE par junarnoalg
Voilà qui est fait, la nouvelle est officielle ! L'équipe belge "Make a Sign" va au pays des kangourous défendre son projet dans la catégorie Software Design. http://www.imaginecup.com/CompetitionsContent/Competition/WorldwideFinalists.aspx V...
Cliquez pour lire la suite de l'article par junarnoalg KINECT 1.5 IS OUT !KINECT 1.5 IS OUT ! par Vko
La version 1.5 du Kinect For Microsoft vient tout juste de sortir ! Plein de nouveautés: Tracking de squelette en Near Mode Détection en position assise Détection faciale avec un SDK dédié Documentation et des guideline (enfin) Un out...
Cliquez pour lire la suite de l'article par Vko LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) LES ACTUALITéS DE LA SEMAINE SUR C2I.FR (14 MAI - 20 MAI) par richardc
Mise à jour des Web API du 14 Mai
Réservez dès maintenant votre journée du 20 juin pour le Windows Azure Dev Camp 2012 à Paris
Mise à jour de Team Foundation Service
MechCommander 2 sur Windows 8
Entity Framework 5 Release Candidate e...
Cliquez pour lire la suite de l'article par richardc REACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITERREACTIVE EXTENSIONS : CONSOMMER DES SERVICES AVEC RX PARTIE 3, LES PIèGES à éVITER par Groc
Une mauvaise utilisation de rx lors de l'écriture d'une couche d'accès à des services peut conduire à des cas embarassants avec des erreurs mal gérées, des appels qui ne partent lorsqu'ils le devraient, et même des résultats incorrects . le tout nuis...
Cliquez pour lire la suite de l'article par Groc SHAREPOINT BLOG SITE, PROBLèME D'ARCHIVESSHAREPOINT BLOG SITE, PROBLèME D'ARCHIVES par junarnoalg
Dernièrement, nous avons migré le site
myTIC
vers un nouveau serveur SharePoint 2010. Dans les contenus que nous vouloins récupérer, nous avions un certain nombre de blogs.
Nous avons utilisé les commandes Power...
Cliquez pour lire la suite de l'article par junarnoalg
Forum
MATRICE TEMPLATEMATRICE TEMPLATE par hjr2610
Cliquez pour lire la suite par hjr2610 RE : SAC A DOS RE : SAC A DOS par hadjkaddour
Cliquez pour lire la suite par hadjkaddour
Logiciels
sDEVIS-FACTURES vlPRO (8.1.0.3)SDEVIS-FACTURES VLPRO (8.1.0.3)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO 974 Application Server (12.2.4.6)974 APPLICATION SERVER (12.2.4.6)Développez de puissantes applications dans un environnement de 'cloud computing', clusterisé, séc... Cliquez pour télécharger 974 Application Server vPicture (1.4.2.1)VPICTURE (1.4.2.1)Avec vPicture, hébergez vos images facilement et rapidement.
vPicture est un utilitaire simple, ... Cliquez pour télécharger vPicture Easy-Planning (2.2.1.6)EASY-PLANNING (2.2.1.6)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté au... Cliquez pour télécharger Easy-Planning COM-BACKUP (2.0)COM-BACKUP (2.0)
COM-BACKUP est un logiciel de sauvegarde qui permet de planifier les sauvegardes de vos dossiers ...
Cliquez pour télécharger COM-BACKUP
|