TP1 : C++ une amélioration du C
Transcription
TP1 : C++ une amélioration du C
TP1 : C++ une amélioration du C En utilisant les nouvelles conventions et possibilités du C++ en particulier le passage d’argument par référence, l’affichage à l’aide de l’opérateur de flux 1) Ecrire une structure point de dimension 3 et une fonction affichant les coordonnées d’un point sous la forme : (x, y, z) et écrire une fonction de comparaison de deux points. 2) On souhaite gérer des listes de points de taille quelconque avec les possibilités suivantes : • Initialisation et remise à zéro (init,reset) • Affichage d’une liste de points (print) • Ajout d’un point à la liste avec redimensionnement automatique si nécessaire (add) • Suppression d’un point de la liste (remove) Une liste sera une structure contenant un tableau de pointeur sur des points (Points), le nombre de points (nb points) et le nombre maximal de points (max points) : la taille du tableau. On aura besoin d’une fonction resize pour augmenter la taille du tableau si besoin. 3) Faire une liste avec les mêmes fonctionnalités ne s’appuyant pas sur un tableau mais sur un chaı̂nage des points. On ne considérera que le chaı̂nage sur le point suivant en ajoutant à la structure de point un pointeur sur le point suivant (next) qui est NULL si c’est le dernier! 4) Comparer les vitesses d’exécution de add et remove en utilisant la fonction time() définie dans time.h time t t1=time(NULL); bloc de programme time t t2=time(NULL); t2-t1 contient le temps d’éxécution en seconde du bloc de code. Attention prévoyez un nombre conséquent d’opérations, au besoin faire une boucle autour d’un même calcul, afin que le temps soit significatif (plusieurs secondes). 5) Ecrire la fusion de deux listes de points (produit une nouvelle liste) en prévoyant l’élimination des doublons (union stricte) 1 Correction //=========================================================================== // TP1 Programmation Scientifique mars 2005 //=========================================================================== // structure point (3D) // structure liste_points (tableau de pointeurs de point) // structure liste_chaine_points (chainage "suivant") // // fonctionnalités : // // point : affichage et comparaison de deux points // liste : initialisation et réinitialisation de la liste // affichage de la liste // ajout, suprresion d’un point de la liste // appartenance d’un point à la liste // fusion de listes sans doublon (union) // //=========================================================================== //définition système //-----------------#include #include #include #include <time.h> <iostream> <algorithm> <fstream> using namespace std; //variable globale //---------------ofstream out; //=========================================================================== //structure Point (dimension 3) //=========================================================================== struct point {float x,y,z; //coordonnées des points point * next; //pointeur sur le point suivant (liste chain\’{e}e) }; //égalité de deux points //---------------------bool equal(const point & P1,const point & P2) {return((P1.x==P2.x) && (P1.y==P2.y) && (P1.z==P2.z)); } //affichage d’un point //-------------------void print(const point & P) {out<<"("<<P.x<<","<<P.y<<","<<P.z<<")"<<endl;} //=========================================================================== //liste de points (à l’aide d’un tableau) //=========================================================================== struct liste_points {int nb_points; //nombre de points int max_points; //nombre maximum de points point ** Points; //pointeur sur un tableau de pointeur de points }; //initialisation de la structure (par défaut de longueur 10) //---------------------------------------------------------void init(liste_points & L,int n=10) {L.nb_points=0; L.max_points=n; L.Points=new point*[n]; } //libération mémoire //-----------------void reset(liste_points & L) {for(int i=0;i<L.nb_points;i++) delete L.Points[i]; delete [] L.Points; //suppression du tableau L.nb_points=0; //suppression des points 2 L.max_points=0; } //Redimensionnement //----------------void resize(liste_points & L,int n) {//création d’une nouvelle liste point** newliste=new point*[n]; //recopie for(int i=0;i<L.nb_points;i++) newliste[i]=L.Points[i]; L.max_points=n; L.nb_points=min(L.nb_points,L.max_points); delete [] L.Points; L.Points=newliste; } //Affichage de la liste //--------------------void print(const liste_points & L) {for(int i=0;i<L.nb_points;i++) print(*L.Points[i]); } //Ajout d’un point P à la liste L //------------------------------void add(liste_points & L, const point & P) {if(L.nb_points==L.max_points) {//redimensionnement, on augmente de 10 resize(L,L.max_points+10); } point *Q=new point(P); //recopie de P L.Points[L.nb_points]=Q; L.nb_points++; } //appartenance d’un point à une liste (retourne la position) //----------------------------------int in_liste(const liste_points & L,const point & P) {for(int i=0;i<L.nb_points;i++) if(equal(*L.Points[i],P)) return i; return -1; } //Suppression du n ème point de la liste L //---------------------------------------void remove(liste_points & L, int n) {if(n<0 || n>L.nb_points) return; //en dehors de la liste delete L.Points[n]; //destruction du point //décalage vers la gauche for(int i=n;i<L.nb_points;i++) L.Points[i]=L.Points[i+1]; if(L.nb_points>0) L.nb_points--; } //Suppression d’un point de la liste L //-----------------------------------void remove(liste_points & L, const point & P) {int n=in_liste(L,P); remove(L,n); } //fusion de deux listes de points (non trié : tres couteux O(nm)) //--------------------------------------------------------------liste_points merge(const liste_points & L1,const liste_points & L2) {//nouvelle liste liste_points L12; init(L12,L1.nb_points+L2.nb_points); //allocation for(int i=0;i<L1.nb_points;i++) add(L12,*L1.Points[i]); //recopie de L1 for(int i=0;i<L2.nb_points;i++) //ajout de L2 if(in_liste(L1,*L2.Points[i])==-1) add(L12,*L2.Points[i]); return L12; } //=========================================================================== //liste chainée de points //=========================================================================== struct liste_chaine_points {int nb_points; //nombre de points point *first; //pointeur sur le premier point de la liste 3 point *last; }; //pointeur sur le dernier point de la liste //initialisation de la liste chainée //---------------------------------void init(liste_chaine_points & L) {L.nb_points=0; L.first=NULL; L.last=NULL; } //libération mémoire //-----------------void reset(liste_chaine_points & L) {point *P=L.first; //pointeur sur le premier point de la liste point *Q=P; while(P!=NULL) {Q=P->next;delete P;P=Q;} init(L); } //affichage de la liste de point //-----------------------------void print(const liste_chaine_points & L) {point *P=L.first; //pointeur sur le premier point de la liste while(P!=NULL) {print(*P);P=P->next;} } //appartenance d’un point à une liste (retourne la position) //----------------------------------int in_liste(const liste_chaine_points & L,const point & P) {point *Q=L.first; for(int i=0;i<L.nb_points;i++) {if(equal(*Q,P)) return i; Q=Q->next; } return -1; } //ajout d’un point à la liste //--------------------------void add(liste_chaine_points & L, const point & P) {point *Q=new point(P); //création d’une copie de P sur le tas Q->next=NULL; //P peut etre détruit par la suite! if(L.nb_points==0) L.first=Q; //liste vide else L.last->next=Q; L.last=Q; L.nb_points++; } //suppression du n-ème point de la liste //--------------------------------------void remove(liste_chaine_points & L, int n) {if(n<0 || n>L.nb_points) return; //en dehors de la liste //d\’{e}placement point *P=L.first; if(n==0) //suppression du premier point {L.first=P->next; L.nb_points--; return; } //positionnement sur le précédent for(int i=0;i<n-1;i++) P=P->next; if(n==L.nb_points-1) //suppression du dernier point {L.last=P; P->next=NULL; } else P->next=P->next->next; L.nb_points--; return; } //suppression du point P (non optimal!) //---------------------void remove(liste_chaine_points & L, const point & P) {int n=in_liste(L,P); remove(L,n); } 4 //fusion de deux listes de points (non trié : tres couteux O(nm)) //--------------------------------------------------------------liste_chaine_points merge(const liste_chaine_points & L1,const liste_chaine_points & L2) {//nouvelle liste liste_chaine_points L12;init(L12); point *P=L1.first; for(int i=0;i<L1.nb_points;i++) //recopie de L1 {point *Q=new point(*P); //création d’une copie du point add(L12,*Q); P=P->next; } P=L2.first; for(int i=0;i<L2.nb_points;i++) //ajout de L2 {if(in_liste(L1,*P)==-1) {point *Q=new point(*P); //création d’une copie du point add(L12,*Q); } P=P->next; } return L12; } //=========================================================================== //programme principal //=========================================================================== int main() {//fichier de sortie //----------------out.open("out"); //test construction de points et affichage //---------------------------------------point O;O.x=0;O.y=0;O.z=0; point A;A.x=1;A.y=1;A.z=1; point B;B.x=1;B.y=0;B.z=0; point C=A; point D;D.x=2;D.y=2;D.z=2; out<<"points O A B C :"<<endl; print(O);print(A);print(B);print(C); //test liste de points //-------------------liste_points L1; init(L1,5); add(L1,O); add(L1,A); add(L1,B); out<<"liste de points L1"<<endl; print(L1); liste_points L2; init(L2); add(L2,C); add(L2,D); out<<"liste de points L2"<<endl; print(L2); //test de fusion liste_points L12=merge(L1,L2); out<<"liste de points L12 "<<endl; print(L12); //temps calcul add point U;U.x=3;U.y=3;U.z=3; time_t t0=time(NULL); for(int i=0;i<100000;i++) {add(L12,U); } time_t tf=time(NULL); out<<"temps calcul add liste = "<<100*(tf-t0)<<endl; //temps calcul remove t0=time(NULL); for(int i=0;i<100000;i++) 5 {remove(L12,U); } tf=time(NULL); out<<"temps calcul remove liste = "<<100*(tf-t0)<<endl; //test des listes chainées de points //---------------------------------liste_chaine_points LC1;init(LC1); add(LC1,O); add(LC1,A); add(LC1,B); out<<"liste de points LC1"<<endl; print(LC1); liste_chaine_points LC2;init(LC2); add(LC2,C); add(LC2,D); out<<"liste de points LC2"<<endl; print(LC2); //test de fusion liste_chaine_points LC12=merge(LC1,LC2); out<<"liste de points LC12"<<endl; print(LC12); //temps calcul add t0=time(NULL); for(int i=0;i<10000000;i++) {add(LC12,U); } tf=time(NULL); out<<"temps calcul add liste chainée = "<<tf-t0<<endl; //temps calcul remove t0=time(NULL); for(int i=0;i<10000000;i++) {remove(LC12,U); } tf=time(NULL); out<<"temps calcul remove liste chainée = "<<tf-t0<<endl; out.close(); cout<<"programme terminé ...."; system("PAUSE"); return 0; } //--------------------------------------------------------------------------- Remarques: • lors de l’ajout d’un point on fait systématiquement une recopie du point et non une affectation du pointeur du point car ce dernier pourrait être supprimé par ailleurs laissant ainsi un pointeur ne pointant plus sur rien. Seule la liste a le contrôle des copies des points, ils ne peuvent donc pas être détruit par inadvertance. • la suppression d’un point est une opération couteuse car il faut rechercher le point dans une liste non triée (recherche séquentielle en O(n)!) • il n’est pas possible de faire un tableau de références sur des points au lieu d’un tableau de pointeurs sur des points, car on ne peut pas initialiser une référence vide. Une référence est un alias sur un pointeur qui doit exister. • on verra plus tard que le C++ (STL) propose des structures vector et list permettant de faire des liste de points sans aucun effort et dont l’implémentation est optimisée! 6 Résultats points O A B C : (0,0,0) (1,1,1) (1,0,0) (1,1,1) liste de points L1 (0,0,0) (1,1,1) (1,0,0) liste de points L2 (1,1,1) (2,2,2) liste de points L12 (0,0,0) (1,1,1) (1,0,0) (2,2,2) temps calcul add liste = 500 temps calcul remove liste = 4000 liste de points LC1 (0,0,0) (1,1,1) (1,0,0) liste de points LC2 (1,1,1) (2,2,2) liste de points LC12 (0,0,0) (1,1,1) (1,0,0) (2,2,2) temps calcul add liste chainée = 2 temps calcul remove liste chainée = 1 On notera que l”utilisation d’un tableau est extrêmement pénalisant (jusqu’à 4000 fois plus couteux pour les opérations de suppression). Cela est du au fait que l’on doit à chaque suppression décaler tous les ééments du tableau. C’est d’autant plus pénalisant que le tableau est tres gros (100000 éléments) et que l’on supprime à chaque fois le premier élément induisant de fait la translation de tout le tableau (c’est la pire des situations!). La suppression ainsi que l’ajout d’un élément d’une liste chainée (hormis la recherche du point dans la liste) est insensible à la dimension du tableau. 7