10 - Les listes

Introduction

Dans le cours IFT 1810, on introduit à la programmation orientée objet (POO) utilisant le langage JAVA sans aller dans les détails.

Dans notre vie quotidienne, on travaille très souvent avec des objets :

Un tableau est un objet.

On peut fabriquer (construire, instancier) un tableau par plusieurs manières :

  • Fabriquer un tableau de couleur noir, en bois, de largeur 3.25 mètre, de hauteur 1.50 mètre

  • Fabriquer un tableau de couleur blanche, en plastique dur, de largeur 2.75 mètre, de hauteur 2.15 mètre

  • etc . . .

Il faut que le tableau existe avant de parler comment travailler avec un tableau.

Que peut-on faire avec un tableau ?

  • écrire au tableau

  • laver le tableau

  • effacer le tableau

  • etc …

La POO est une nouvelle méthode de programmation basant sur trois concepts :

L’encapsulation :

Fusionner les champs de données (les attributs) et les méthodes pour manipuler ces données dans la même capsule qui s’appelle une classe. On ajoute aussi des clauses d’accès : champs souvent privés, méthodes souvent publiques.

Pour IFT 1810, on travaille seulement à ce concept.

L’héritage :

Construire de nouvelles classes étendues de classes existences qui hérite de données et de méthodes de celles-ci. De plus on peut ajouter de nouveaux champs, de nouvelles méthodes. On étudiera ce concept dans les cours après IFT 1810 (comme IFT 1170, IFT 1166, etc . . .).

Le polymorphisme :

La capacité de se présenter sous plusieurs formes.

Ce concept sera présenté dans les cours suivants de IFT 1810 .

Nous avons vu les tableaux en Java. Ces derniers présentent un inconvénient, il n’est pas facile de modifier la taille d’un tableau. En Java il existe une autre structure plus souple, les listes ou ArrayList.

Cette structure a les même propriétés qu’un tableau mais peut être redimensionnée dynamiquement.

Pour utiliser les listes, il faut importer une bibliothèque en tête du fichier :

import java.util.*;

Exemple 1 :

import java.util.*;

public class Ex3_Cercle {

    // afficher le contenu de la liste des cercles
    static void afficher(List<Cercle> cer, int nbCercles, String message)
    {
    	System.out.printf("\n\nContenu de la kiste de %d cercles %s :\n", 
                              nbCercles, message);
    	System.out.printf(" Rayon  Périmètre    Surface\n");
    	for ( int i = 0 ; i < nbCercles; i++)
    	  System.out.printf("%6.2f %8.2f %10.2f\n", cer.get(i).getRayon(),   
            cer.get(i).perimetre(),cer.get(i).surface());
        System.out.printf("\n\n");
    }

    // une manière de trier une liste des cercles
    // (tri par sélection vu avant l'intra)
    static void trier(List<Cercle> cer, int nbCercles)
    {
    	for (int i = 0; i < nbCercles-1; i++)
    	{ int indMin = i;
    	  for (int j = i+1; j < nbCercles; j++)
    	  	 if ( cer.get(j).getRayon() < cer.get(indMin).getRayon() )
    	  	 	           indMin = j;
    	  if (indMin != i)
    	  {
    	  	  double tempo = cer.get(i).getRayon();
    	  	  cer.get(i).setRayon ( cer.get(indMin).getRayon());
    	  	  cer.get(indMin).setRayon(tempo);
    	  }
    	}
    }

    // déterminer puis afficher le cercle ayant le rayon le plus grand
    static void chercherPlusGrandRayon(List<Cercle> cer, int nbCercles)
    {
    	int indMax = 0 ;
    	for(int i = 1 ; i < nbCercles; i++)
    		if ( cer.get(i).getRayon() > cer.get(indMax).getRayon())
    			   indMax = i;
        cer.get(indMax).afficher("Cercle ayant le rayon le plus grand");

    }

    public static void main(String[] args) {

    	// instancier 3 cercles
    	Cercle c1 = new Cercle(5.3),
    	       c2 = new Cercle(1.7), c3 = new Cercle();

    	c3.afficher("Infos du cercle c3");

        System.out.printf("Le perimetre du cercle c2 : %.2f\n\n",
                              c2.perimetre());

        System.out.printf("La surface du cercle c1 : %.2f\n\n",
                              c1.surface());

       // exemple d'une petite liste des cercles :
        
        List<Cercle> cer = new ArrayList<Cercle>();
        cer.add(new Cercle(5.3));
        cer.add(new Cercle(4.7));
        cer.add(new Cercle());
        cer.add(new Cercle(10.4));
        cer.add(new Cercle(5.2));
        
        
        int nbCercles = cer.size();

        cer.get(1).afficher("Infos de cer[1] ");
        // doubler le rayon du 2ième cercle
        /*Voici un commentaire*/
        cer.get(1).setRayon( 2 * cer.get(1).getRayon());
        cer.get(1).afficher("Infos de cer[1] après avoir doublé son rayon ");

        // forme 2 : Classe.méthode "static"
        Ex3_Cercle.afficher(cer, nbCercles, "avant le tri") ; 
        // Ex2_Cercle. est optionnel

        // quel est le cercle ayant le plus grand rayon
        chercherPlusGrandRayon(cer, nbCercles);

        trier(cer, nbCercles);

        afficher(cer, nbCercles, "apres le tri selon les rayons") ;

    }
}

Différence avec les tableaux :

Tableau Liste
Déclaration Type[] nom = {…}
Type[] nom = new Type[6]
List<Type> nom = new ArrayList()<Type>;
Accès nom[i] nom.get(i)
Taille nom.length nom.size()
Modification nom[i] = elt nom.set(i) = elt
Suppression nom.remove(i)
Ajout nom.add(i) = elt

Il existe plusieurs façons de parcourir une liste.

Méthode classique :

for(int i = 0 ; i < liste.size(); i++)

Avec un itérateur :

ListIterator<Object> it = liste.listIterator();
    	
while(it.hasNext()) {
	// Intructions
	it.next();
}

L’itérateur avance dans les éléments de la liste grâce à it.next().

Exemple 2 :

import java.util.*;

public class Ex4_Cercle {

    // afficher le contenu de la liste des cercles
    static void afficher(List<Cercle> cer, int nbCercles, String message)
    {
    	System.out.printf("\n\nContenu de la liste de %d cercles %s :\n", 
                              nbCercles, message);
    	System.out.printf(" Rayon  Périmètre    Surface\n");
    	for ( int i = 0 ; i < nbCercles; i++)
    	  System.out.printf("%6.2f %8.2f %10.2f\n", cer.get(i).getRayon(),   
            cer.get(i).perimetre(),cer.get(i).surface());
        System.out.printf("\n\n");
    }

    // une manière de trier une liste des cercles
    // (tri par sélection vu avant l'intra)
    static void trier(List<Cercle> cer, int nbCercles)
    {
    	for (int i = 0; i < nbCercles-1; i++)
    	{ int indMin = i;
    	  for (int j = i+1; j < nbCercles; j++)
    	  	 if ( cer.get(j).getRayon() < cer.get(indMin).getRayon() )
    	  	 	           indMin = j;
    	  if (indMin != i)
    	  {
    	  	  double tempo = cer.get(i).getRayon();
    	  	  cer.get(i).setRayon ( cer.get(indMin).getRayon());
    	  	  cer.get(indMin).setRayon(tempo);
    	  }
    	}
    }

    // déterminer puis afficher le cercle ayant le rayon le plus grand
    static void chercherPlusGrandRayon(List<Cercle> cer, int nbCercles)
    {
    	int indMax = 0, i = 0 ;
    	ListIterator<Cercle> it = cer.listIterator();
    	
    	while(it.hasNext()) {
    		if ( it.next().getRayon() > cer.get(indMax).getRayon())
    			indMax = i;
    		i++;
    		//it.next();
    	}
        cer.get(indMax).afficher("Cercle ayant le rayon le plus grand");

    }

    public static void main(String[] args) {

    	// instancier 3 cercles
    	Cercle c1 = new Cercle(5.3),
    	       c2 = new Cercle(1.7), c3 = new Cercle();

    	System.out.println("Infos du cercle c3");
    	System.out.println(c3);

        System.out.printf("Le perimetre du cercle c2 : %.2f\n\n",
                              c2.perimetre());

        System.out.printf("La surface du cercle c1 : %.2f\n\n",
                              c1.surface());

       // exemple d'une petite liste des cercles :
        
        List<Cercle> cer = new ArrayList<Cercle>();
        cer.add(new Cercle(5.3));
        cer.add(new Cercle(4.7));
        cer.add(new Cercle());
        cer.add(new Cercle(10.4));
        cer.add(new Cercle(5.2));
   
        
        int nbCercles = cer.size();

        cer.get(1).afficher("Infos de cer[1] ");
        // doubler le rayon du 2ième cercle
        /*Voici un commentaire*/
        cer.get(1).setRayon( 2 * cer.get(1).getRayon());
        cer.get(1).afficher("Infos de cer[1] après avoir doublé son rayon ");

        // forme 2 : Classe.méthode "static"
        Ex3_Cercle.afficher(cer, nbCercles, "avant le tri") ; 
        // Ex2_Cercle. est optionnel

        // quel est le cercle ayant le plus grand rayon
        chercherPlusGrandRayon(cer, nbCercles);

        trier(cer, nbCercles);

        afficher(cer, nbCercles, "apres le tri selon les rayons") ;



    }
}

Il est pratique d’utiliser System.out.printf pour afficher des données. Il existe d’autres possibilités qui utilisent la concaténation des chaines de caractères.

System.out.println("Infos : " + var1 + ", " + var2);

println permet d’afficher une ligne. On peut concaténer des chaines de carctères avec le contenu de variables qui seront alors transformées en chaine de caractères.

print permet la même chose mais sans ajouter de retour à la ligne à la fin de la chaine.

Cette méthode est pratique pour les types de base mais comment faire pour l’utiliser avec un objet que nous avons défini?

Il suffit de créer la méthode toString() dans l’objet. Cette méthode doit retourner la chaine de caractère que nous souhaitons afficher.

public String toString() {
	   return " - rayon      : " + String.format("%.2f",donnees[0]) + 
"\n" + " - périmètre  : " + String.format("%.2f",perimetre()) + "\n" + 
" - surface    : " + String.format("%.2f",surface()) + "\n";
   }

On peut maintenant afficher un cercle simplement :

System.out.println(c3);

Exemple 3 :

class Cercle
{
   // privé => accessible SEULEMENT dans la classe Cercle
   //private double rayon ;
   private double[] donnees = {0.0, 0.0, 0.0};

   // un constructeur pour construire (instancier) 1 cercle
   public Cercle(double r)
   {
   	  donnees[0] = r ;
   	  donnees[1] = 2*r*Math.PI;
   	  donnees[2] = r*r*Math.PI;
   }

   // un autre constructeur pour construire (instancier) 1 
   // cercle
   public Cercle()
   {
	   donnees[0] = 1.3;
	   donnees[1] = 2*1.3*Math.PI;
	   donnees[2] = 1.3 * 1.3 * Math.PI;
   	   //rayon = 1.3; // par défaut
   }
   
   public double getRayon() {
	   return donnees[0];
   }
   
   public void setRayon(double r) {
	   donnees[0] = r;
	   
   }

   // Math.PI : le champ "static" PI de la classe Math(ématique)
   public double perimetre()
   {
   	 // 2 x PI x rayon
   	 //return 2 * Math.PI * rayon;
	   return donnees[1];
   }

   // PI x (rayon au carré)
   public double surface()
   {
   	 //return Math.PI * rayon * rayon;
	   return donnees[2];
   }
   public void afficher(String message)
   {
   	  // exemple : Infos du cercle ... : rayon, perimetre puis surface
   	  System.out.printf("Infos du %s\n", message);
   	  System.out.printf(" - rayon      : %6.2f\n", donnees[0]);
   	  System.out.printf(" - périmètre  : %6.2f\n", perimetre());
   	  System.out.printf(" - surface    : %6.2f\n\n", surface());
   }
   
   public String toString() {
	   return " - rayon      : " + String.format("%.2f",donnees[0]) + 
			   "\n" + " - périmètre  : " + String.format("%.2f",perimetre()) + "\n" + 
			   " - surface    : " + String.format("%.2f",surface()) + "\n";
   }


} // fin de classe Cercle