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