1
Les arbres généraux
1. Introduction
Comme mentionné au chapitre précédent, un arbre est général si les nombre d’enfants est variable
pour les nœuds. Dans ce chapitre, nous allons, dans un premier temps, discuter des différentes
implantations de ces arbres, et, dans un deuxième temps, étudier une classe particulière d’arbres
généraux: les B-arbres.
légende :
- Subtree rooted at V : sous-arbre enraciné à V
- Children of V: enfants de V
- Siblings of V: soeurs/frères de V
- Root : racine
2. Différentes implantations
Avant de discuter des différentes implémentations d’un arbre général, regardons d’abord les
différentes opérations que nous pourrions effectuer dans un arbre. La première étant d’accéder à
la racine. Une autre est d’accéder aux enfants d’un nœud. Dans un arbre binaire, cette dernière
opération est possible en utilisant des fonctions qui donnent des accès explicites à l’enfant gauche
et enfant droit de ce nœud. Malheureusement, cette manière de procéder n’est pas possible dans
le cas d’un arbre général, pour la simple raison que le nombre d’enfants n’est pas connu à priori.
Une alternative est d’avoir une fonction qui prend en paramètre l’indice de l’enfant à visiter
combinée à une autre fonction qui retourne le nombre d’enfants d’un nœud donnée est capable de
supporter l’accès à un nœud donné ou traiter tous les nœuds. Cette manière de faire favorise
l’utilisation d’un tableau (pourquoi?). En pratique, une implémentation basée sur les pointeurs est
2
souvent préférée. Une autre alternative consiste à avoir accès à l’enfant le plus à gauche d’un
nœud, et une autre fonction qui a accès au frère/sœur de droite d’un nœud. Ce qui suit montre la
déclaration de classes pour les arbres généraux et leur nœuds basée sur cette approche.
// classe nœud pour arbre général
template <class Elem>
class GTNode {
public:
GTNode(const Elem&); // Constructeur 1
GTNode(const Elem&, GTNode<Elem>*, GTNode<Elem>*, GTNode<Elem>*); //
Constructeur 2
~GTNode(); // Destructeur
Elem value(); // Retourne la valeur du noeud
bool isLeaf(); // VRAI si le nœud est une feuille
GTNode* parent(); // Retourne le parent
GTNode* leftmost_child(); // Retourne le premier enfant
GTNode* right_sibling(); // Retourne le frère de droite
void setValue(Elem&); // Assigne une valeur au noeud
void insert_first(GTNode<Elem>* n); // insère comme premier enfant
void insert_next(GTNode<Elem>* n); // insère comme frère de droite
void remove_first(); // Enlève le premier enfant
void remove_next(); // Enlève le frère de droite
};
// Classe arbre general
class GenTree {
private
void printhelp(GTNode*); // print helper function
public:
GenTree(); // Constructeur
~GenTree(); // Destructeur
void clear(); // libère les noeuds
GTNode* root(); // Retourne la racine
void newroot(Elem, GTNode*, GTNode*); // fusionne deux arbres
};
3
Parcours d’un arbre général
template <class Elem>
void GenTree<Elem>::
printhelp(GTNode<Elem>* subroot) {
if (subroot->isLeaf()) cout << "Leaf: ";
else cout << "Internal: ";
cout << subroot->value() << "\n";
for (GTNode<Elem>* temp = subroot->leftmost_child(); temp != NULL;
temp = temp-> right_sibling())
printhelp(temp);
}
Réponse : R A C D E B F
2.1. Implantation par le parent : Chaque nœud contient une valeur et un pointeur à son parent.
Les pointeurs parents sont représentés par la position du parent dans le tableau. Cette
représentation est souvent utilisée quand on veut savoir si deux objets sont dans le même arbre et
aussi fusionner deux arbres en un seul arbre.
4
?
bool Gentree::differ(int a, int b) {
// les noeuds a et b sont-ils dans es arbres différents?
GTNode* root1 = FIND(&array[a]); // trouve la racine de a
GTNode* root2 = FIND(&array[b]); // trouve la racine de b
return root1 != root2; // compare les raciness
}
class Gentree { // General tree: UNION/FIND
private:
GTNode* array; // Node array
int size; // Size of node array
GTNode* FIND(GTNode*) const; // trouver la racine
public:
Gentree(int); // Constructeur
~Gentree(); // Destructor
void UNION(int, int); // fusionner
bool differ(int, int); // TRUE si pas dans le même arbre
};
Gentree::Gentree(int sz) { // Constructeur
size = sz;
array = new GTNode[sz]; // Créer le noeud tableau
}
Gentree::~Gentree() { // Destructeur
delete [] array; // libérer le noeud tableau
}
bool Gentree::differ(int a, int b) {
// les noeuds a et b sont-ils dans des arbres différents ?
GTNode* root1 = FIND(&array[a]); // touver la racine de
GTNode* root2 = FIND(&array[b]); // trouver la racine de b
return root1 != root2; // Comparer les raciness
}
5
void Gentree::UNION(int a, int b) { // fusionner les sousarbres
GTNode* root1 = FIND(&array[a]); // trouver la racine de a
GTNode* root2 = FIND(&array[b]); // trouver la racine de b
if (root1 != root2) root2->par = root1; // fusionner
}
GTNode* Gentree::FIND(GTNode* curr) const {
while (curr->parent() != NULL) curr = curr->par;
return curr; // At root
}
2.2. Implantation par liste des enfants : La liste des nœuds est stockée dans un tableau. Chaque
élément de ce tableau contient, la valeur du nœud, un pointeur vers son parent et un autre
pointeur vers la liste de ses enfants de gauche vers la droite.
Remarque: la combinaison d’arbre avec cette implantation est plutôt difficile à réaliser si chaque
arbre est stocké dans un nœud tableau. Si les nœuds des arbres sont stockées dans un seul nœud
tableau, alors ajouter l’arbre T comme un sous arbre du nœud R est fait simplement en joutant la
racine de T à la liste des enfants de R
2.3. Implantation par enfant gauche – frère droit
L’inconvénient de l’implantation ci-dessus est qu’il est difficile d’accéder au nœud droit d’un
frère. La figure ci-dessous montre une implantation améliorée. Chaque élément du tableau stocke
la valeur du nœud et des pointeurs à son parent, l’enfant le plus à gauche et le frère droit . Donc,
chaque opération de ci-dessus peut être implantée en lisant la valeur directement du nœud.
1 / 23 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !