liste de fake

Transcription

liste de fake
Université de Nice-Sophia Antipolis
Algorithmique & Programmation
Deug MIAS-MI 1
2002–2003
TP N 4
Consultation de Tables (Corrigé)
a. Ajoutez à la classe Note une méthode « outil » :
public static Note average (double[] coeff, Note[] note)
qui calcule la moyenne d’un tableau de notes, pondérées par les coefficients d’un tableau de
même longueur (ne vous préoccupez pas de vérifier que les longueurs des deux tableaux sont
bien les mêmes, ce sera toujours le cas quand cette méthode sera appelée). Le principe est que la
moyenne doit être calculée uniquement sur les notes effectives. Par exemple, avec des données :
coeff = {1, 2, 3, 4}
note = {0.0, absent, 15.0, 12.5)
La moyenne sera :
Si toutes les notes valent absent, la moyenne aura cette même absence de valeur !
Il suffit de calculer en parallèle la somme des notes et la somme des coefficients, limitées aux
vraies notes. Le test final est aussi une garde qui protège la division de la dernière ligne.
public static Note average (double[] coeff, Note[] note) {
double noteSum = 0.0, coeffSum = 0.0 ;
for (int i = 0 ; i < coeff.length ; i++) {
if (!note[i].absent) {
noteSum += coeff[i]*note[i].value ;
coeffSum += coeff[i] ;
}
}
if (coeffSum == 0.0)
return new Note() ;
else
return new Note(noteSum/coeffSum) ;
}
.............................................................................................
b. Cherchez la classe Vector dans l’API et lisez-la jusqu’à savoir à peu près ce dont vous allez
disposer. Attention ! Java est un grand labyrinthe, une classe propose toujours plus de choses
que ce dont vous aurez besoin : ne vous laissez pas distraire par des notions inconnues et allez à
l’essentiel !
On trouvera sans difficulté son bonheur si on se laisse guider par les besoins en termes de
table : ajouter devrait impliquer add et supprimer un des remove. Comme la table est une sorte
de tableau d’indices, pour rechercher on devrait avoir besoin de indexOf et pour modifier de
elementAt. Enfin, confiner les indices à des indices légaux nécessite probablement la connaissance de size.
.............................................................................................
1
c. Interprétez en termes d’héritage (de la super-classe Object) la méthode equals de la classe
Student. Que dit exactement cette méthode?
public boolean equals (Object o) {
return ((Student) o).name.equals(this.name) ;
}
On ne peut surcharger une métode qu’en lui laissant exactement la même signature. Le paramètre doit donc être un objet mais nous savons que, dans le cadre de la classe Student, cet
objet sera toujours un étudiant. Il faut alors changer son type par une conversion et travailler avec
(Student) o. Ainsi, le compilateur saura que la référence à l’attribut name est légitime. Il faut
aussi mettre (Student) o entre parenthèses pour que cette conversion s’applique uniquement
à « o » et pas à tout ce qui suit, ce qui ne plairait pas au compilateur.
À présent que l’on dispose de l’attribut name du paramètre, il suffit de tester son égalité avec
le même attribut de l’étudiant pour lequel la méthode est appelée : this.name et, comme les
chaînes sont des objets, en utilisant la surcharge de equals qui se trouve dans la classe String !
Finalement, nous avons abouti à déclarer ce que nous souhaitions : deux étudiants sont le
même étudiant si et seulement si ils ont le même nom.
.............................................................................................
d. Comme une tentative de compilation vous le montrera bien vite, cette classe comporte des
erreurs. Les unes viennent de ce que les attributs note et average de la classe Student ont été
déclarés private. Vous pourriez, bien sûr, ajouter des accesseurs et des modificateurs à la classe
Student mais Java fournit un procédé plus simple. Il est en effet normal qu’un Mi1Student,
non seulement possède les attributs de sa classe parente Student mais aussi qu’il y ait accès : il
suffit pour cela de remplacer private par protected dans la déclaration de ces deux attributs,
ils seront toujours protégés de n’importe qui d’étranger, mais quand même accessibles aux classes
dérivées. Il reste encore des erreurs, dues à l’ambiguïté de l’identificateur note (le compilateur
Java ne se rend pas compte que l’un est un élément, l’autre un tableau). Corrigez-les.
Il suffit de lever l’ambigïté en plaçant explicitement le préfixe this. devant le note qui est un
attribut.
public void set (int test, Note note) {
this.note[test] = note ;
average = Note.average(COEFF, this.note) ; // mise a jour
}
.............................................................................................
Ajouter : Un étudiant nouvellement inscrit se présente, il n’a encore aucune note. Il faut l’ajouter à la table.
e. Écrire une procédure d’instance add(String name) qui fait le travail. Ça ne devrait pas
demander beaucoup d’efforts ...
public void add (String name) {
list.add(new Mi1Student(name)) ;
}
.............................................................................................
2
Rechercher : Connaissant le nom d’un étudiant (la clef), on souhaite connaître l’étudiant luimême.
f. Écrire une fonction d’instance search qui renvoie le premier étudiant de la liste ayant le nom
passé en argument. Vous aurez besoin de refléchir un peu pour utiliser les méthodes de la classe
Vector.
La seule chose que l’on puisse rechercher dans la liste est un étudiant. On utilise donc une
variable auxiliaire : un étudiant fictif student ayant le nom cherché. Si on ne le trouve pas on
renvoie null, la valeur conventionnelle d’inexistence pour les objets. Mais, si on le trouve, il
faudra bien prendre garde à renvoyer l’authentique étudiant, celui qui se trouve dans la liste,
surtout pas student qui n’est qu’un fantôme sans aucune note !
public Mi1Student search (String name) {
Mi1Student student = new Mi1Student(name) ;
int i = list.indexOf(student) ;
if (i == -1) return null ;
else return (Mi1Student) list.elementAt(i) ;
}
.............................................................................................
Mettre à jour : Une épreuve vient enfin de finir d’être corrigée. Il faut rentrer les notes.
g. Écrire une méthode d’instance qui, à une épreuve donnée, met sa note à un étudiant de nom
donné. Il se peut que l’étudiant ait composé sans avoir auparavant régularisé son inscription : si
l’étudiant n’est pas dans la liste, vous devrez l’y ajouter.
public void set (String name, int test, Note note) {
Mi1Student student = search(name) ;
if (student == null) { // nouvel etudiant
student = new Mi1Student(name) ;
list.add(student) ;
}
student.set(test, note) ; // on met la note
}
La méthode set utilisée en dernière ligne est définie dans la classe Student et notre étudiant,
qui est un Mi1Student en hérite sans problème.
.............................................................................................
Supprimer : Un étudiant vient de gagner un tour du monde dans un jeu télévisé. Il décide
d’abandonner (provisoirement) ses études et en prévient ses enseignants.
h. Écrire une méthode d’instance qui supprime un étudiant de nom donné.
public void remove (String name) {
Mi1Student student = new Mi1Student(name) ;
int i = list.indexOf(student) ;
if (i == -1) return ;
else list.removeElementAt(i) ;
}
3
Il y a d’autres façons de faire et, probablement, des spécialistes de Java, effectuant la suppression par effet de bord, auraient écrit quelque chose du genre :
public void remove (String name) {
if (!list.remove(new Mi1student(name)))
throw new RuntimeException( " é t u d i a n t i n e x i s t a n t " ) ;
}
Cependant, vous êtes ici pour apprendre de l’algorithmique et de la programmation, pas du
Java...
.............................................................................................
Nettoyer : Les étudiants écrivent souvent leur nom de façon peu lisible et il en résulte qu’ils
peuvent être deux fois dans la liste avec des orthographes légèrement différentes. Quand on s’en
aperçoit, il vaut mieux regrouper les informations.
i. Écrire une méthode d’en-tête :
public void merge (String name, String alias)
correspondant aux spécifications suivantes :
– si un des deux étudiants n’est pas dans la liste, la méthode ne fait rien ;
– s’il existe une épreuve pour laquelle les deux étudiants ont chacun une vraie note, la méthode ne fait rien (ce sont probablement deux étudiants distincts !) ;
– sinon, on reporte sur « name » les vraies notes de « alias » et on supprime « alias ».
Il suffit de suivre pas à pas le protocole indiqué.
public void merge (String name, String alias) {
// recherche des étudiants
Mi1Student student = search(name) ;
Mi1Student fake = search(alias) ;
if (student == null || fake == null)
return ;
int i = 0 ;
// comparaison des absences
while (i < Mi1Student.NB_OF_NOTES &&
(student.note[i].isAbsent() || fake.note[i].isAbsent()))
i++ ;
if (i < Mi1Student.NB_OF_NOTES) // on na pas été jusqu’au bout
return ; // car il y a une épreuve notée pour les deux
// transfert des notes manquantes de ‘student‘
for (i = 0 ; i < Mi1Student.NB_OF_NOTES ; i++) {
if (student.note[i].isAbsent())
student.set(i, fake.note[i]) ;
}
// nettoyage
list.remove(fake) ;
}
.............................................................................................
4
Consulter : Une table, prototype élémentaire des bases de données, peut être utilisée pour des
requêtes plus complexes comme, par exemple, d’obtenir la moyenne de la promotion pour une
épreuve donnée.
j. Écrire une fonction d’instance average(int test) qui résolve le problème. Vous serez dans
un bon plan si vous utilisez convenablement l’outil average de la classe Note.
L’intérêt de récupérer l’outil average est que celui-ci fait déjà le travail de ne pas comptabiliser les absences ; c’est une bonne occasion d’utiliser le principe de simplification :
se ramener à un problème plus simple
(car déjà résolu)
Il suffit alors de construire un tableau contenant les notes de tous les étudiants à cette épreuve
et, parallèlement, un tableau de coefficients, tous valant 1 (les étudiants sont tous égaux devant le
barême). Il n’aurait servi à rien d’utliser la méthode toArray de la classe Vector car on aurait
obtenu un tableau d’étudiants, pas un tableau de notes.
public Note average (int test) {
double[] coeff = new double[list.size()] ;
Note[] note = new Note[list.size()] ;
for (int i = 0 ; i < list.size() ; i++) {
coeff[i] = 1.0 ;
Mi1Student student = (Mi1Student)list.elementAt(i) ;
note[i] = student.getNote(test) ;
}
return Note.average(coeff, note) ;
}
.............................................................................................
5