1. Livres & vidéos
  2. Algorithmique
  3. Corrigé 6
Extrait - Algorithmique Entraînez-vous et améliorez votre pratique de la programmation (exemples en Java et Python) (2e édition)
Extraits du livre
Algorithmique Entraînez-vous et améliorez votre pratique de la programmation (exemples en Java et Python) (2e édition) Revenir à la page d'achat du livre

Corrigé 6

Prérequis

1.

L’héritage consiste en une transmission des attributs et des méthodes. Si une classe A hérite d’une classe B, alors A hérite de tous les attributs et méthodes de B. Il faut noter qu’il est possible de redéfinir le code d’une méthode héritée.

2.

Lorsqu’une classe A hérite d’une classe B, alors :

  • A est appelée la sous-classe de B ;

  • B est appelée la surclasse de A.

3.

a. et b. Il est normal que ça soit possible pour un objet de la classe C elle-même. Mais c’est également possible pour un objet d’une sous-classe de C. En effet, grâce à l’héritage, les objets de cette sous-classe bénéficient des attributs et méthodes de la classe C. Ils peuvent donc être utilisés à la place des objets de la classe C. Il faut noter que ceci est faux pour un objet d’une surclasse de C, d’où l’impossibilité pour un attribut typé par C de posséder une référence vers un tel objet.

4.

c. C’est seulement possible pour des sous-classes de la classe servant de type à la variable (ou au paramètre) pour les raisons expliquées ci-dessus. Dans une sous-classe, il est possible de redéfinir le code d’une méthode héritée. Cette possibilité permet de mettre en œuvre le polymorphisme.

5.

Une méthode abstraite est une méthode dont il est possible de spécifier le nom, les paramètres et le type de retour mais pas le code. Ce code peut être...

Corrigé 6.1 : La classe Automobile

En Java, la classe Automobile introduit un moteur et un nom. Le moteur est créé dans le constructeur. La méthode demarre demande au moteur de démarrer à son tour. Voici le code de cette classe.

public class Automobile { 
   Moteur moteur; 
   String nom; 
 
   public Automobile(String nom) { 
       this.nom = nom; 
       moteur = new Moteur("moteur de " + nom); 
   } 
 
   public void demarre() { 
       System.out.println(nom + " a commencé à démarrer"); 
       moteur.demarre(); 
       System.out.println(nom + " a terminé de démarrer"); 
   } 
} 

La classe Moteur introduit deux roues (gauche et droite) et un nom. Les roues sont créées dans le constructeur. La méthode demarre demande à chaque roue de tourner. Le code Java de cette classe se présente de la façon suivante.

public class Moteur { 
   Roue roueGauche, roueDroite; 
   String nom; 
 
   public Moteur(String nom) { 
       this.nom = nom; 
       roueGauche = new Roue("roue...

Corrigé 6.2 : La classe Devine2

La classe Devine2 est décrite ci-dessous en Java. La méthode session y fait place à plusieurs méthodes pour gérer un nombre à deviner. La méthode propose réalise la comparaison entre la tentative et le nombre à deviner.

public class Devine2 { 
   NombreAleatoire nombreAleatoire; 
   int nombreTentatives; 
 
   public Devine2(NombreAleatoire nombreAleatoire) { 
       this.nombreAleatoire = nombreAleatoire; 
   } 
 
   public int propose(int tentative) { 
       nombreTentatives++; 
       return nombreAleatoire.compare(tentative); 
   } 
 
   public void initialise() { 
       nombreTentatives = 0; 
       nombreAleatoire.reCalcule(); 
   } 
 
   public int getBorneInf() { 
       return nombreAleatoire.getBorneInf(); 
   } 
 
   public int getBorneSup() { 
       return nombreAleatoire.getBorneSup(); 
   } 
 
   public int getNombreTentatives() { 
       return nombreTentatives; 
   } 
} 

La classe DevineES réintroduit la méthode session dont la réalisation se base sur un objet de la classe Devine2. Les fonctionnalités d’entrée/sortie sont ainsi séparées de la partie purement fonctionnelle.

import java.util.Scanner; 
 
public class DevineES { 
   ...

Corrigé 6.3 : La classe DevineNombre

La classe DevineNombre est basée sur la classe DevineNombreES.

Le constructeur réalise une association avec un objet de la classe DevineNombreES.

La méthode devine utilise l’algorithme de recherche par dichotomie. Chaque proposition est soumise par l’appel de la méthode propose de l’objet de la classe DevineNombreES qui lui est associé.

Le code Java de cette classe est le suivant :

public class DevineNombre { 
   DevineNombreES devineES; 
 
   public DevineNombre() { 
       devineES = new DevineNombreES(); 
   } 
 
   public int devine(int inf, int sup) { 
       int borneInf = inf; 
       int borneSup = sup; 
       int nbrTentatives = 0; 
       int milieu, reponse; 
       do { 
           nbrTentatives++; 
           milieu = (borneInf + borneSup) / 2; 
           reponse = devineES.propose(milieu); 
           if (reponse == 1) 
               borneSup = milieu - 1; 
           else if (reponse == -1) ...

Corrigé 6.4 : L’ordinateur joue contre l’ordinateur

Le but de cet exercice est de faire jouer l’ordinateur contre lui-même par l’intermédiaire de plusieurs objets qui communiquent entre eux. Dans ce but, la classe DevineNombre est modifiée (renommée DevineNombre2) afin de prendre en compte le fait de jouer contre un objet de la classe Devine2, c’est-à-dire d’initialiser la partie et d’utiliser cet objet pour gérer le nombre de tentatives.

La communication ne se fait pas directement entre un objet de DevineNombre2 et un objet de Devine2 mais par l’intermédiaire d’un objet de la classe LienDevine. Celui-ci renvoie les appels de méthode vers l’objet de Devine2 qu’il crée dans son constructeur. Il affiche également les différentes tentatives et leur résultat.

Voici la description de la classe DevineNombre2 en Java.

public class DevineNombre2 { 
    LienDevine lien; 
    NombreAleatoire nbrAleatoire; 
 
    public DevineNombre2(NombreAleatoire nbrAleatoire) { 
        this.nbrAleatoire = nbrAleatoire; 
        this.lien = new LienDevine(nbrAleatoire); 
    } 
 
    public int devine() { 
        int borneInf = nbrAleatoire.getBorneInf(); 
        int borneSup = nbrAleatoire.getBorneSup(); 
        int milieu, reponse; 
        lien.initialise(); 
        do { 
            milieu = (borneInf + borneSup) / 2; 
           ...

Corrigé 6.5 : La course automobile

La classe Automobile représente une automobile avec les attributs et méthodes nécessaires dans le cadre de cet exercice.

La méthode aDepasse (Java)/a_depasse (Python) détermine si l’automobile en a dépassé une autre. Pour dépasser, il faut qu’avant d’avoir avancé, l’automobile se situe avant ou au même endroit que l’autre automobile et qu’elle se situe maintenant après l’autre automobile. Cette méthode nécessite l’introduction de l’attribut positionAvant (Java)/position_avant (Python) qui fournit la position de la voiture avant qu’elle avance d’une valeur aléatoire dans la méthode avance. Sans cet attribut, il est impossible de déterminer si une voiture en a devancé une autre après avoir avancé.

Le constructeur mémorise les paramètres dans les attributs prévus et initialise les deux attributs de position. La méthode avance modifie les positions en utilisant la valeur aléatoire. La méthode aFranchiLigne (Java)/a_franchi_ligne (Python) détermine si l’automobile a franchi la position de la ligne.

Le code suivant correspond à la version Java de la classe Automobile pour simuler une course.

public class Automobile { 
    NombreAleatoireCourse nombreAlea; 
    int positionApres, positionAvant, vitesseMax; 
 
    public Automobile(int vitesseMax, NombreAleatoireCourse nombreAlea) { 
        this.vitesseMax = vitesseMax; 
        this.nombreAlea = nombreAlea; 
        positionAvant = 0; 
        positionApres = 0; 
    } 
 
    public void avance() { 
        positionAvant = positionApres; 
        positionApres = positionApres + nombreAlea.calcule(0, vitesseMax); 
    } 
 
    public boolean aFranchiLigne(int positionLigne) { 
        return positionApres > positionLigne; 
    } 
 
    public boolean aDepasse(Automobile auto) { 
 ...

Corrigé 6.6 : La classe Complexe2

Il est très simple de réécrire la classe Complexe2 en une sous-classe de Complexe, comme décrit ci-dessous. Il faut noter que les paramètres de ces deux méthodes sont maintenant typés par la classe Complexe. Ils peuvent ainsi recevoir un objet de la classe Complexe ou de la classe Complexe2.

Quant au programme principal, c’est le même que dans l’exercice 4.6. En effet, ce programme est un client de la classe Complexe2 et  la conception, dont notamment les liens d’héritage, de la classe Complexe2 n’a pas d’impact sur ses clients qui ne prennent en compte que le nom, les paramètres et le type de retour des méthodes publiques. Même s’il est vrai que nous avons modifié le type des paramètres des deux méthodes introduites dans Complexe2, cette modification est un assouplissement et n’a donc pas d’impact sur le programme principal. Cependant ce programme peut subir une légère modification pour prendre en compte la méthode toString (Java)/__str__ (Python) introduite dans la classe Complexe et dont bénéficie maintenant la classe Complexe2 (par héritage).

La définition de la classe Complexe2 en Java donne le code suivant :

public class Complexe2 extends Complexe { 
    public Complexe2(double reel, double imaginaire) { 
        super(reel, imaginaire); 
    } 
 
    public void ajouteComplexe(Complexe argument) { 
        reel = reel + argument.getReel(); 
        imaginaire...

Corrigé 6.7 : Les comptes en banque

La classe abstraite Compte en Java est décrite ci-dessous. La méthode retire est introduite comme méthode abstraite car il est du rôle des sous-classes de la concrétiser.

public abstract class Compte { 
    long solde; 
 
    public Compte() { 
        solde = 0; 
    } 
 
    public long getSolde() { 
        return solde; 
    } 
 
    public void ajoute(long montant) { 
        solde += montant; 
    } 
 
    public abstract boolean retire(long montant); 
} 

La sous-classe CompteClassique introduit une première définition de cette méthode dans laquelle il n’est pas possible d’avoir un découvert.

public class CompteClassique extends Compte { 
 
    public boolean retire(long montant) { 
        if (montant <= solde) { 
            solde -= montant; 
            return true; 
        } else 
            return false; 
    } 
} 

La sous-classe CompteAvecDecouvert introduit une seconde définition de cette méthode dans laquelle un découvert est possible mais dans la limite déterminée par l’attribut decouvertAutorise.

public class CompteAvecDecouvert extends Compte { 
    long decouvertAutorise; 
 
    public CompteAvecDecouvert() { 
        decouvertAutorise = 0; 
    } 
 
    public long getDecouvertAutorise() { 
        return decouvertAutorise; 
    } 
 
    public void setDecouvertAutorise(long decouvertAutorise) { 
        this.decouvertAutorise...

Corrigé 6.8  : Les ensembles

L’interface Java qui introduit les trois méthodes publiques des classes Ensemble et EnsembleTrie est définie ci-dessous.

public interface InterfaceEnsemble { 
    boolean insere(int valeur);  
    boolean supprime(int valeur);  
    void affiche(); 
} 

Il faut modifier en conséquence ces deux classes pour indiquer qu’elles mettent en œuvre cette interface, ce qui est fait ci-dessous pour chaque classe.

public class Ensemble implements InterfaceEnsemble {  
int tailleEnsemble; 
int[] ensemble; 
... 
} 
  
public class EnsembleTrie implements InterfaceEnsemble {  
int tailleEnsemble; 
int[] ensemble; 
... 
} 

Le programme principal est simple. En fonction du choix de l’utilisateur, un ensemble trié ou non est créé. Ce choix est visible à l’exécution car l’affichage à la fin des valeurs est fait de façon triée uniquement si le choix d’un ensemble trié a été demandé au début.

import java.util.Scanner; 
 
public class TestEnsembles { 
 
    public static void main(String[] args) { 
        Scanner reader = new Scanner(System.in); 
        int valeur; 
        InterfaceEnsemble...

Corrigé 6.9 : Les portes logiques

En partant de la définition de Porte fournie dans l’énoncé (interface en Java/classe abstraite en Python), nous définissions à la suite la classe abstraite PorteImpl qui introduit les méthodes communes à toutes les portes logiques. Il convient de remarquer qu’il n’est pas nécessaire de définir la méthode getSortie (Java)/get_sortie (Python) comme méthode abstraite de Porteimpl car cette méthode est déjà introduite dans l’interface Porte.

Le code Java fournissant la définition de la classe PorteImpl se présente de la façon suivante :

public abstract class PorteImpl implements Porte { 
    boolean entree1, entree2; 
     
    public boolean getEntree1() { return entree1; } 
 
    public boolean getEntree2() { return entree2; } 
 
    public void setEntree1(boolean valeur) { entree1 = valeur; } 
 
    public void setEntree2(boolean valeur) {    entree2 = valeur;} 
} 

La définition des trois classes concrètes de Porte est fournie à la suite. Chacune hérite de PorteImpl et définit complètement la méthode getSortie en fonction de son type de porte logique.

public class PorteET extends PorteImpl { 
    public boolean getSortie() { 
   ...