wget http://cria2.uqam.ca/INF3105/lab8/lab8.zip unzip lab8.zip
Remplacez le fichier arbreavl.h par votre plus récente version réalisée au Lab7.
Il est important de compléter les Lab6 et Lab7 avant d'amorcer le Lab8.
g++ -o test_arbremap test_arbremap.cpp.
Complétez le programme lab8_ip.cpp qui compte le nombre d'adresses IP différentes ayant accédé aux fichiers PDF dans le site Web du cours. Un squelette de départ est fourni dans lab8_ip.cpp.
Voici un extrait du fichier journal fourni apachelogs.txt:
... 218.156.26.2 01/Sep/2023:08:58:35 GET /INF3105/diapos/00-debut.pdf 198.96.185.2 01/Sep/2023:15:43:36 GET /INF3105/diapos/00-debut.pdf 95.168.175.169 01/Sep/2023:16:36:49 GET /INF3105/diapos/00-debut.pdf 95.168.175.169 01/Sep/2023:16:36:54 GET /INF3105/diapos/00-debut.pdf 95.168.175.169 01/Sep/2023:16:37:02 GET /INF3105/diapos/00-debut.pdf 95.168.175.169 01/Sep/2023:16:37:06 GET /INF3105/diapos/00-debut.pdf 87.110.154.48 01/Sep/2023:19:22:58 GET /INF3105/diapos/00-debut.pdf 113.47.35.134 01/Sep/2023:19:23:30 GET /INF3105/diapos/00-debut.pdf 113.47.35.134 01/Sep/2023:19:23:30 GET /INF3105/diapos/00-debut.pdf 198.96.185.2 02/Sep/2023:10:07:17 GET /INF3105/diapos/00-debut.pdf 20.242.215.79 02/Sep/2023:11:38:14 GET /INF3105/diapos/00-debut.pdf ...
Notez que le fichier a été simplifié et que les adresses IP ont été anonymisées.
Le présent exercice est légèrement plus complexe que l'exercice 1 présenté dans
les diapositives sur ArbreMap.
L'exercice dans les diapositives demande d'associer chaque chaîne de caractères avec un entier servant de compteur.
Ici, l'astuce consiste à associer chaque nom de fichier à un ensemble d'adresses IPs.
Cela demande l'imbrication de deux arbres, le premier étant un dictionnaire et le deuxième un arbre binaire de recherche.
Pour la syntaxe, cela ressemble à l'imbrication d'un tableau de listes : Tableau< Liste<int> > tab;
.
La représentation d'un ArbreMap<K,V>::Iterateur est tout simplement un autre itérateur de type ArbreAVL<Entree>::Iterateur. La déclaration d'un itérateur devrait ressembler à cela.
class ArbreMap { // ... public: class Iterateur { public: Iterateur(const ArbreMap& a) : iter(a.entrees.debut()) {} Iterateur(typename ArbreAVL<Entree>::Iterateur i) : iter(i) {} operator bool() const; bool operator!() const; Iterateur& operator++(); Iterateur operator++(int); const K& cle() const; const V& valeur() const; // constant ou non ? private: typename ArbreAVL<Entree>::Iterateur iter; }; // ... Iterateur debut() const; Iterateur fin() const; Iterateur rechercher(const K& cle) const; Iterateur rechercherEgalOuSuivant(const K& cle) const; Iterateur rechercherEgalOuPrecedent(const K& cle) const; };
Il ne faut pas perdre de vue qu'on peut utiliser des itérateurs d'ArbreMap sur des dictionnaires constants ou non constants. Voici deux cas d'utilisation.
Cas #1 : ArbreMap constant :
void fonction(const ArbreMap<string, int>& dictionnaire) { ArbreMap<string, int>::Iterateur iter = dictionnaire.debut(); const string& cle = iter.cle(); const int& v = iter.valeur(); ... }
Cas #2 : ArbreMap non constant :
void fonction(ArbreMap<string, int>& dictionnaire) { ArbreMap<string, int>::Iterateur iter = dictionnaire.debut(); const string& cle = iter.cle(); int& v = iter.valeur(); v++; ... }
Il y a plusieurs façons de bien gérer les const. En voici deux :
L'option B est plus simple à implémenter. L'option A peut être plus conviviale pour l'utilisateur. À vous de choisir!
Enfin, décommentez les fonctions test3() et test4() dans test_arbremap.cpp et les appels de ces fonctions dans main(), et assurez-vous que ces tests réussissent.
Vous devez écrire un programme qui reçoit en entrée des lectures de température. Chaque ligne comporte une date exprimée en heure et une température en Celsius séparées d’un espace blanc. Tous les nombres sont des nombres réels (float). Les données sont dans l’ordre chronologique. Voici un exemple d’entrée.
0.00 9.0 1.00 10.0 2.00 10.4 3.00 11.0 4.00 12.5 5.00 13.7 6.05 14.7 7.00 13.4 8.10 11.5
Complétez le programme lab8_temperature.cpp
qui permet :
On suppose que la température varie de façon linéaire entres deux dates pour lesquelles la température est connue. Exemples:
Votre solution doit être construite autour d’une classe Historique
qui permet de stocker l’historique des températures en mémoire.
Vous devez compléter la représentation de la classe Historique
et coder les fonctions estimeTemperature(...)
et calculeMoyenne(...)
.
class Historique { private: // Représentation public: Historique(); ~Historique(); void ajouter(float date, float temperature); float estimeTemperature(float date) const; float calculeMoyenne(float datedebut, float datefin) const; };
Modifiez votre programme (si nécessaire) pour traiter le cas où les données n’arriveraient pas en ordre chronologique.
Si vous jugez qu’aucune modification n’est requise, expliquez pourquoi la solution en A est «parfaite». Si vous jugez que des modifications sont requises, expliquez pourquoi la solution en A demeure pertinente dans le cas où les données seraient en ordre chronologique.
Évaluez la complexité temporelle des fonctions estimeTemperature(...)
et calculeMoyenne(...)
en A et B.