Les arbres généraux
Nœud pour arbres généraux template <class Elem> class GTNode { public: GTNode(const Elem&); ~GTNode(); Elem value(); bool isLeaf(); GTNode* parent(); GTNode* leftmost_child(); GTNode* right_sibling(); void setValue(Elem&); void insert_first(GTNode<Elem>* n); void insert_next(GTNode<Elem>* n); void remove_first(); void remove_next(); };
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); } Traversal: RACDEBF
Liste des enfants The next several slides show various possible implementations for general trees. A key gauge for the quality of these representations is how well they perform the key tasks of left-child, right-sibling, and parent. This representation is poor for finding the right sibling of a node.
Liste des enfants Problème pour trouver le frère de droite The next several slides show various possible implementations for general trees. A key gauge for the quality of these representations is how well they perform the key tasks of left-child, right-sibling, and parent. This representation is poor for finding the right sibling of a node.
Implémentation avec tableau (1) Note: Two trees share the same array.
Implémentation avec tableau (2) Joindre deux arbres Here, the two trees are joined together. Few links need to be adjusted in the implementation to support this join action.
Implémentation avec pointeur (1) Essentially an array-based list of children.
Implémentation avec pointeur (2) Essentially a linked list of children.
Nœud pour arbres généraux template <class Elem> class GTNode { private: Elem element; GTNode<Elem>* rent; // Parent GTNode<Elem>* leftchild; // Premier fils GTNode<Elem>* rightsib; // Frère de droite
Nœud pour arbres généraux public: GTNode(const Elem&); // Constructeur GTNode(const Elem&, GTNode<Elem>*, GTNode<Elem>*, GTNode<Elem>*); ~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 };
Implémentation template <class Elem> GTNode<Elem>::GTNode(const Elem& value) { rent = leftchild = rightsib = NULL; element = value; } GTNode<Elem>::GTNode(const Elem& value, GTNode<Elem>* par, GTNode<Elem>* leftc, GTNode<Elem>* rights) { rent = par; leftchild = leftc; rightsib = rights;
Implémentation template <class Elem> GTNode<Elem>::~GTNode() { } Elem GTNode<Elem>::value() { return element; } bool GTNode<Elem>::isLeaf() { return leftchild == NULL; } GTNode<Elem>* GTNode<Elem>::parent() { return rent; } GTNode<Elem>* GTNode<Elem>::leftmost_child() { return leftchild; }
Implémentation template <class Elem> GTNode<Elem>* GTNode<Elem>::right_sibling() { return rightsib; } void GTNode<Elem>::setValue(Elem& value) { element = value; } void GTNode<Elem>::insert_first(GTNode<Elem>* n) { n->rightsib = leftchild; n->rent = this; leftchild = n; }
Implémentation template <class Elem> void GTNode<Elem>::insert_next(GTNode<Elem>* n) { n->rightsib = rightsib; n->rent = rent; rightsib = n; } void GTNode<Elem>::remove_first() { if (leftchild == NULL) return; GTNode<Elem>* temp = leftchild; leftchild = leftchild->rightsib; delete temp; // BAD -- lose all its subtree!
Implémentation template <class Elem> void GTNode<Elem>::remove_next() { if (rightsib == NULL) return; GTNode<Elem>* temp = rightsib; rightsib = rightsib->rightsib; delete temp; // BAD -- lose all its subtree! }
Implémentation séquentielle (1) On énumère les nœuds dans l’ordre qu’ils apparaissent lors d’un recherche en préordre. Sauve de l’espace mais ne permet que des accès séquentielles. Doit préserver la structure de l’arbre. Exemple: Pour les arbres binaires, on utilise un symbole pour indiquer les liens nuls: AB/D//CEG///FH//I// This example refers to the tree of Figure 6.16.
Implémentation séquentielle (2) Exemple: Pour les arbres binaires, on utilise un symbole pour indiquer les liens nuls: AB/D//CEG///FH//I// This example refers to the tree of Figure 6.16.
Implémentation séquentielle (3) Exemple: Arbres binaires: indiquer si les nœuds sont internes ou des feuilles. A’B’/DC’E’G/F’HI The first example includes two “/” marks because the example tree is not full. Cost is one additional bit per node. The second example refers to the general tree of Figure 6.3.
Implémentation séquentielle (3) Exemple: Arbres généraux: indiquer la fin de chaque sous arbre: RAC)D)E))BF))) Les parenthèses indiquent la fin d’une liste d’enfants The first example includes two “/” marks because the example tree is not full. Cost is one additional bit per node. The second example refers to the general tree of Figure 6.3.