ArbreAVL
.wget http://cria2.uqam.ca/INF3105/lab6/lab6.zip unzip lab6.zip
Complétez les fonctions de base de la classe ArbreAVL
dans arbreavl.h
:
vide
contient
inserer
vider
L'objectif est de réussir les tests #1 à 6 dans testavl.cpp
.
Pour tester :
g++ -o testavl testavl.cpp ./testavl
Notez que la solution finale de arbreavl.h
ne sera pas fournie.
Une bonne partie du code de arbreavl.h
est fournie dans les notes de cours.
La partie la plus difficile est la rotation droite-gauche.
Le code de l'enlèvement n'a pas été fourni et est laissé en exercice. Tel qu'annoncé, l'enlèvement est plus difficile que l'insertion, car il y a plus de cas à gérer. Toutefois, il est possible d'implémenter un enlèvement simplifié.
L'enlèvement simplifié consiste à marquer les éléments enlevés, plutôt que de les enlever complètement de l'arbre, puis de les ignorer. L'avantage de cette méthode est sa simplicité. En effet, elle évite d'avoir à reconnecter des pointeurs, d'effectuer les rotations requises pour rééquilibrer l'arbre, etc. Le principal inconvénient est que l'arbre peut accumuler des éléments inutilisés. Ainsi, la hauteur de l'arbre peut être plus grande que nécessaire. Il y a aussi un gaspillage temporaire de mémoire pour garder ces éléments jusqu'au vidage de l'arbre.
Étapes pour implémenter l'enlèvement simplifié :bool enlevé
dans la structure Noeud
.false
(ex: dans le constructeur).contient
: si l'élément recherché est trouvé dans l'arbre, il faut retourner faux si le noeud a été marqué enlevé=true
.compter
: il ne faut pas compter les noeuds marqués par enlevé=true
.inserer
: si l'élément est déjà dans l'arbre, il faut réinitialiser enlevé=false
.L'objectif est de passer le test #7.
Ici, il s'agit du même problème qu'au Lab5 / Tâche 3. L'objectif est d'utiliser un arbre binaire de recherche pour améliorer l'efficacité du programme. En effet, plutôt que de parcourir une liste chaînée en temps O(n), on peut vérifier le numéro de la carte en temps O(log n).
1. Créer une File<PassageCarte> (ou liste) vide L. 2. Créer un ArbreAVL<int> vide A. 3. Tant que la lecture de l'entrée standard (std::cin
) n'est pas terminée : 4. | Lire un passage p. //Un passage est une paire d'entiers (temps, numéro_de_carte). 5. | Tant que L n'est pas vide ET L.premier().temps + 600 ≤ p.temps. 6. | | A.enlever(L.premier().numéro) 7. | | L.défiler (ou enlever début) 8. | Si A.contient(p.numéro) : 9. | | Afficher "Passage invalide !" // on pourrait améliorer pour afficher le temps dans A 10.| Sinon : 11.| | A.inserer(p.numéro) 12.| | L.enfiler(p)
Des fichiers de test sont dans les fichiers de départ du Lab5 : lab5.zip.
Il s'agit essentiellement de coder la fonction copier
utilisée par le constructeur par copie et l'opérateur d'affectation =.
Si vous avez implémenté l'enlèvement simplifié,
vous aurez une décision à prendre, soit comment traiter les éléments marqués enlevés (enlevé=true
).
Vaut-il mieux recopier l'arbre dans sa structure entière, ce qui inclut les éléments enlevés ?
Ou, vaut-il mieux insérer les éléments non enlevés, un à un, dans le nouvel arbre ?
Ébauche de l'enlèvement :
template <class T> void ArbreAVL<T>::enlever(const T& element) { enlever(racine, element); } template <class T> bool ArbreAVL<T>::enlever(Noeud*& noeud, const T& element) { if(element < noeud->contenu) { if(enlever(noeud->gauche, element)) { // ... } } else if(element > noeud->contenu) { if(enlever(noeud->droite, element)) { // ... } } else // if(element == noeud->contenu) { if (noeud->gauche==nullptr && noeud->droite==nullptr) { delete noeud; noeud = nullptr; return true; } else { // ... return true; } } }