Académique Documents
Professionnel Documents
Culture Documents
Licence Sciences
et Technologies
Module API
Approche
imprative.
Mise en uvre en
Java
Juin 2007
Version 4
J. Barr,P. Le
certen,Y. Le
Tertre, L. Morin,
L. Ungaro
CHAPITRE 1
Introduction 5
1.1 Algorithmes, langages de programmation, programmes 5
1.1.1 Langages de programmation 6
1.1.2 Algorithmes en langages dclaratifs 6
1.1.3 Algorithmes en langages impratifs 8
10
1.4.1 Analyse 12
1.4.2 Rdaction du programme 12
1.4.3 Compilation - excution 14
CHAPITRE 2
20
2.4.1 Dclarations 22
2.4.2 Exemples doprations sur des donnes de types primitifs
CHAPITRE 3
23
24
37
44
Universit de Rennes 1
CHAPITRE 4
CHAPITRE 5
Nommage 57
Portes didentification 58
Dures de vie 59
Identification temporaire - blocs dinstructions 60
Modularit 62
4.5.1 Dcoupage en classes
4.5.2 Paquetages 63
62
Instructions conditionnelles 69
5.1 Forme gnrale de linstruction conditionnelle 69
5.2 Imbrication de conditionnelles 72
5.3 Aiguillage 74
CHAPITRE 6
Rcursivit et itration
81
6.2 Rcursivit 83
83
CHAPITRE 7
95
Module A.P.I
122
Universit de Rennes 1
CHAPITRE 8
CHAPITRE 9
Tableaux 143
9.1
9.2
9.3
9.4
9.5
9.6
9.7
9.8
CHAPITRE 10
176
CHAPITRE 11
191
197
CHAPITRE 12
CHAPITRE 13
212
217
Universit de Rennes 1
CHAPITRE 14
CHAPITRE 15
265
ANNEXE 1
Installations 271
Installation de Java 271
Test de linstallation de java 271
Ajout de paquetages 272
Installation dEclipse 273
Ouverture dun projet Eclipse 273
Cration dune classe 274
Excution 275
ANNEXE 2
Module A.P.I
268
Universit de Rennes 1
239
Introduction
CHAPITRE 1
Introduction
1.1
Un algorithme est la description des oprations qui permettent daccomplir une tche. Cette
tche peut tre un calcul, une transformation dinformation, voire un procd de fabrication.
Lusage dalgorithmes est en fait assez rpandu. Un modle de tricot, une recette de cuisine...
sont des algorithmes. Un algorithme doit tre une description prcise, mais pas ncessairement
exprim dans un langage prdfini. Tous les moyens dexpression sont acceptables : langue
naturelle, agrmente de mathmatiques, de croquis...
Un langage de programmation est un langage rigoureux, comprhensible par une machine, qui
permet dexprimer sans aucune ambigut des algorithmes.
Un programme est un algorithme exprim dans un langage de programmation.
Universit de Rennes 1
1.1.1
Langages de programmation
Il existe de nombreux langages de programmation qui se sont dvelopps au cours des ans en fonction des besoins, de lvolution des ordinateurs et des mthodes dans le domaine du gnie logiciel.
Les langages les plus rudimentaires sont les langages machines. Ils utilisent des instructions
1.1.2
Module A.P.I
Universit de Rennes 1
Introduction
Sigma(1,1).
Sigma(n,s+n) <- n>1 et Sigma(n-1,s)
Sigma(4,x)?
Lexcution du programme consiste, en utilisant les faits et les implications, chercher les solutions
sil en existe. Dans lexemple propos, lexcution trouve une solution : x=10.
Sigma(4,x)? la rgle 2 sapplique, et x vaut s+4 condition que Sigma(3,s)
Sigma(3,s)? la rgle 2 sapplique, et s vaut t+3 condition que Sigma(2,t)
Sigma(2,t)? la rgle 2 sapplique, et t vaut u+2 condition que Sigma(1,u)
Sigma(1,u)? la rgle 1 sapplique, et u vaut 1
donc t vaut 3, donc s vaut 6, donc x vaut 10
Le problme a une solution x=10.
Le plus connu des langages relationnels sappelle PROLOG.
Universit de Rennes 1
1.1.3
somme=0, i=1
while(i<=n){somme=somme+i; i=i+1;}
donc1<=4
somme=1, i=2
while(i<=n){somme=somme+i; i=i+1;}
donc2<=4
somme=3, i=3
while(i<=n){somme=somme+i; i=i+1;}
donc3<=4
somme=6, i=4
while(i<=n){somme=somme+i; i=i+1;}
donc4<=4
somme=10, i=5
5>4
donc somme et i inchangs
while(i<=n){}
return somme;
Module A.P.I
rsultat : 10
Universit de Rennes 1
Introduction
1.2
La syntaxe est lensemble des rgles de construction que doivent respecter les textes des pro-
grammes.
La smantique est la signification des constructions du langage.
Un programme doit dabord respecter la syntaxe, sinon on ne peut lui attribuer aucune signification.
Dans lexemple prcdent :
while(i<=n) {somme=somme+i; i=i+1;}
utilise la syntaxe correcte du langage Java pour exprimer une rptition doprations.
La signification donne cette construction est (informellement) :
tant que i est infrieur ou gal n : ajouter i somme, ajouter 1 i
En revanche, la forme :
while(i<=n) {somme=somme+i i=i+1}
comporte une erreur de syntaxe : le langage exige un ; la fin de chaque instruction lmentaire.
Un programme peut tre correct au niveau syntaxique sans pour autant calculer ce que lon dsire. Il
y a alors une erreur smantique (ou erreur de conception).
Ainsi la forme :
while(i<n) {somme=somme+i; i=i+1;}
est syntaxiquement correcte, mais cela ne calcule pas ce que lon veut car cette version arrte le
cumul sur n-1 cause de lingalit stricte utilise dans le test i<n.
Les notions de syntaxe et de smantique se rencontrent dans tout langage. Comme exemple imag,
on peut considrer les phrases suivantes exprimes dans un langage de physique lmentaire :
lige plomb le : cette phrase est une erreur de syntaxe, on ne peut lui attribuer aucune signifi-
cation.
le lige flotte : cette phrase est syntaxiquement correcte. Elle signifie que le lige flotte (il est
moins dense que leau). De plus elle exprime une chose exacte. Elle est smantiquement correcte (dans la mesure o lexactitude est la valeur qui nous intresse).
le plomb flotte : cette phrase est syntaxiquement correcte. Elle signifie que le plomb flotte.
Elle exprime une chose inexacte. On peut considrer que cest une erreur smantique.
Les erreurs de syntaxe ne sont jamais graves car un compilateur les signale avant toute excution.
Les erreurs de conception sont plus difficiles corriger car elles ne se manifestent pas toujours et
elles peuvent ncessiter une phase de mise au point longue et fastidieuse.
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
1.3
1.3.1
Lanalyse : elle consiste exprimer la rsolution du problme sous une forme la moins ambigu
entre de donnes
1.3.2
sortie de rsultats
Mthodes danalyse
Il existe plusieurs mthodes danalyse, plus ou moins adaptes la complexit et la nature des
problmes.
10
Module A.P.I
Universit de Rennes 1
Introduction
P1, P2, P3... Pn que lon cherche rsoudre sparment. La dcomposition se poursuit jusqu
lobtention de sous-problmes trivialement rsolus. Les rsolutions des sous-problmes sont ralises par des procdures que lon regroupe gnralement par thmes dans des modules.
Comme exemple imag dune telle dcomposition, supposons que nous ayons dterminer litinraire routier pour aller de Rennes Quimper. Une premire analyse conduit :
(P1) Rennes Plormel
(P2) Plormel Lorient
(P3) Lorient Quimper
Le sous-problme P1 peut lui mme tre dcompos en :
(P11) Rennes Mordelles
(P12) Mordelles Pllan-le-Grand
(P13) Pllan-le-Grand Plormel
La dcomposition se poursuit plus ou moins loin. Tout dpend des possibilits du langage utilis et
de procdures dj existantes dans les bibliothques.
1.3.2.3 Analyse avec des objets :
Pour des problmes plus complexes, il faut utiliser une mthode danalyse par objets qui consiste
spcifier de faon abstraite les donnes manipules et les oprations quelles peuvent subir et
ensuite raliser ces abstractions au moyen des types de donnes offerts par le langage ou que lon
sait raliser.
1.3.3
1.4
Exemple introductif
objectif : tre capable de concevoir des programmes trs simples par analogie avec un exemple.
Nous prendrons un exemple trs simple.
Cahier des charges : calculer la surface et le volume de plusieurs sphres de rayons donns.
Universit de Rennes 1
11
Exemple introductif
1.4.1
Analyse
Lanalyse est ici triviale : on applique des rsultats de mathmatiques. La surface et le volume des
sphres sont des rsultats bien connus : la surface est 4 rayon2 et le volume 4 rayon3/3.
Cependant, le problme pos consistant faire ces calculs pour plusieurs sphres, il convient de
dfinir deux fonctions aire et volume dpendant dun paramtre qui est le rayon.
aire : rel rel
aire(rayon) = 4 rayon2
volume : rel rel
volume(rayon) = 4 rayon3/3
Ces fonctions pourront alors tre sollicites avec diverses valeurs du rayon.
Important : si un calcul correspond une notion clairement identifie, comme cest le cas ici avec
les notions de surface de sphre et de volume de sphre il est recommand de le raliser sous
forme dune fonction, mme si ce calcul nest pas destin tre utilis plusieurs fois.
1.4.2
Rdaction du programme
Le problme prcdent peut tre rsolu en Java par le programme suivant :
class Sphere {
nom du programme
procdure principale
12
Module A.P.I
Universit de Rennes 1
Introduction
Une classe comporte dans son intrieur des dclarations de donnes globales et des dfinitions de
fonctions.
Ici nous avons une dclaration de donne globale :
static final double PI = 3.141592;
Cette dclaration donne le nom PI la constante bien connue. Le vocable final indique quil
sagit dune constante, ce qui signifie quon na pas le droit de modifier la valeur associe au nom
PI. Les donnes manipules (constantes, variables, paramtres et rsultats de fonctions) ont un
type. Le type dune donne caractrise le domaine auquel appartient sa valeur. Ici le vocable double indique que la valeur de PI est un nombre rel de grande prcision1. Le vocable static
signifie que la constante PI existe ds le dbut dexcution du programme (cela peut sembler
curieux davoir le dire explicitement, mais cest ainsi)2.
Nous avons ensuite deux dfinitions de fonctions : aire et volume . Une dfinition de fonction est
compose du nom de la fonction suivie de ses paramtres formels entre parenthses. Le type du
rsultat de la fonction est indiqu devant le nom de la fonction et le type des paramtres est indiqu
devant chaque nom de paramtre.
Ainsi :
static double aire(double r)
signifie que la fonction aire a un paramtre de type double appel r et que son rsultat est de
type double . Le vocable static est obligatoire dans le cas dune simple fonction3.
Les textes compris entre // et la fin de la ligne sont des commentaires. Ils sont ignors par le
compilateur et servent documenter le programme. Ici,
// rsultat
est un commentaire de spcification, qui indique la fonction (mathmatique) ralise par cette
fonction (programme).
Le rsultat dune fonction est obtenu en excutant les instructions qui figurent dans le corps de la
fonction, entre accolades {return
4*PI*r*r;}
. Linstruction return expression calcule
lexpression et termine lexcution en donnant comme valeur le rsultat de ce calcul. Pour effectuer
les calculs, on dispose des oprateurs usuels, * pour la multiplication, / pour la division.
Pour quun programme soit directement excutable, il doit possder une procdure principale :
public static void main(String[] arg)
Cest sur cette procdure que commencera lexcution. Une procdure possde des paramtres et
est compose dinstructions, mais contrairement une fonction elle ne rend pas de rsultat. Cela est
indiqu par le vocable void devant le nom de la procdure.
En Java, la procdure principale doit sappeler main et doit avoir un paramtre de type
String[] (ce paramtre sert capter des informations transmises au lancement de lexcution,
mais on sen servira rarement). Une procdure ne rend pas de rsultat au sens fonctionnel du mot.
Autrement dit, tant donn une procdure P, son invocation ... P()... ne signifie aucune valeur. Pour
1. Le vocable double vient du terme double prcision qui dsigne cette sorte de reprsentation de nombres rels.
2. Java est un langage objets et les classes servent souvent programmer des modles dobjets : dans ce cas les donnes
dclares sans ce vocable static sont propres chaque objet cr selon ce modle.
3. Sans le vocable static la fonction serait considre comme une mthode dobjet destine sappliquer sur un objet
dont la classe serait le modle, ce qui nest pas le cas ici.
Universit de Rennes 1
13
Exemple introductif
tre utile, elle doit produire un effet. La notion deffet est primordiale pour un langage impratif,
alors que cette notion est quasiment inexistante pour un langage fonctionnel pur1. Les effets sont
des actions perceptibles sur lenvironnement du programme ou de la machine. Dans les cas simples,
les effets sont de nature informationnelle tel que afficher des informations sur lcran de lordinateur ou mmoriser des informations de faon rmanente dans des fichiers. Les effets peuvent galement tre de nature plus physique, tels que piloter un avion ou contrler le freinage dune voiture.
Dans lexemple, linstruction System.out.println(); produit un effet. Elle affiche sur
lcran le rsultat de lvaluation de son paramtre. Ainsi la procdure principale a pour effet dafficher successivement laire et le volume dune sphre de rayon 4.2 puis laire et le volume dune
sphre de rayon 2.
1.4.3
Compilation - excution
Pour utiliser ce programme, il faut dabord le compiler puis lancer son excution. Dans le cas de
Java, le programme prcdent doit tre plac dans un fichier appel Sphere.java . Avec un systme rudimentaire de dveloppement de programmes, la compilation se fait en tapant la
commande :
javac Sphere.java
Sil y a des erreurs de syntaxe, le compilateur javac (pour Java Compiler) les signale. Il faut dans
ce cas corriger ces erreurs et recommencer la compilation avant daller plus loin. Si le programme
est exempt derreur de syntaxe, le compilateur produit un programme excutable dans un fichier
Sphere.class . Le texte du programme en langage volu, Sphere.java , sappelle programme source. Le programme excutable rsultat de la compilation, Sphere.class , sappelle
programme objet ou encore code objet.
On peut alors lancer lexcution en tapant la commande : java Sphere
Lexcution du programme provoque laffichage suivant sur lcran :
221.671296
310.3398144
50.2656
33.5104
Sphere.java
class Sphere {
...
...
}
javac Sphere.java
compilation
excution
java Sphere
Sphere.class
010001101001
100100101001
011010110110
100100100101
221.671296
310.3398144
50.2656
33.5104
1. Le seul effet dun programme fonctionnel pur est laffichage du rsultat de son valuation.
14
Module A.P.I
Universit de Rennes 1
Introduction
QCM 1.1
Un algorithme est :
prcis.
Ce programme :
1 - Affiche : 3.141592
2 - Affiche : 6.283184
3 - Affiche : 31.41592
4 - Naffiche rien.
5 - Est refus par le compilateur car prsentant une erreur de syntaxe.
3 - Retourne 31.41592
Universit de Rennes 1
15
Exemple introductif
Exercice 1.1
Installation
objectif : prendre en main les outils de programmation - indispensable pour pouvoir aller plus
loin.
Raliser linstallation de lenvironnement de travail en suivant les indications de lannexe1 :
Installation de Java
Test de linstallation de Java
Accs aux paquetages pour les exercices
Installation dEclipse
Usage dEclipse.
Exercice 1.2
16
Module A.P.I
Universit de Rennes 1
Introduction
Aide 1.2
Il faut dfinir deux fonctions, aire et volume . Ces fonctions ont ici trois paramtres, les dimensions du paralllogramme dans les trois directions de lespace. Le programme total, que lon pourra
appeler Parallelepipede contiendra ces deux fonctions et la procdure principale main :
class Parallelepipede {
static double aire(double lx, double ly, double lz) {
// rsultat
: laire dun paralllpipde
// de dimensions lx, ly, lz
...
}
static double volume(double lx, double ly, double lz) {
// rsultat
: le volume dun paralllpipde
// de dimensions lx, ly, lz
...
}
Universit de Rennes 1
17
Exemple introductif
18
Module A.P.I
Universit de Rennes 1
CHAPITRE 2
objectif : apprendre ce que sont les types de donnes et comprendre leur intrt.
Vous avez pu remarquer une diffrence dans les deux programmes donns en exemple au chapitre
prcdent :
le premier, qui calcule la somme des n premiers nombres entiers, utilise des donnes (i, n et
somme ) qualifies par le vocable int,
le second, qui calcule laire et le volume de sphres, utilise des donnes (PI, r, aire,
volume ) qualifies par le vocable double .
Les vocables int et double indique les types des donnes manipules. Pourquoi cette
diffrence ? Est-elle ncessaire, utile, arbitraire ?
2.1
Notion de type
objectif : comprendre ce quest un type de donne.
Les problmes traits par linformatique ne concernent pas uniquement des nombres. Ils peuvent
concerner des couleurs (bleu, vert, rouge...), des textes ou des choses encore plus exotiques comme
des personnes, des voitures, des avions... Chaque nature de donne est dfinie par un type.
Un type est caractris par :
un domaine de valeurs,
les oprations qui sont possibles sur ces valeurs.
Exemples :
nature
exemple de valeurs
exemple doprations
nombre entier
12
5+7
nombre rel
3.14
6.28/2.0
chane de caractres
"bonjour"
false
type Java
int
double
"bon"+"jour"
i>0 && i<3
String
boolean
Un type sert spcifier quelle sortes de donnes sont acceptes comme paramtres et rendues en
rsultat dune opration. Par exemple, lopration daddition de nombres entiers, note +, admet
deux oprandes entiers (type int) et rend en rsultat une valeur entire (type int galement).
Autre exemple, lopration de comparaison dentiers, note >, admet deux oprandes de type
int et rend en rsultat une valeur de type boolean (x>y vaut true si x>y, false sinon).
Universit de Rennes 1
19
2.2
2.2.1
double PI=3.1589;
(i<14)-PI
soustraire un nombre rel dune valeur logique est absurde.
Ces expressions seront refuses par le compilateur.
2.2.2
20
Module A.P.I
Universit de Rennes 1
2.2.3
2.3
Le tableau suivant reprsente une classification des types offerts par la plupart des langages de
programmation :
scalaires
entiers
12
rels
12.0
caractres
'w
boolens
false
types primitifs
tableaux
types
composs
chanes
types programms
0
1
2
3
12
2
25
12
"coucou"
numrs
Couleur = {bleu,blanc,rouge}
structures
Personne = <nom,age>
classe
ex. <toto,19>
class Voiture {
...
void accelerer() {...}
void freiner() {...}
Un certain nombre de types sont offerts par le langage. On les appelle types primitifs. Parmi les
types primitifs on peut distinguer :
Universit de Rennes 1
21
Les langages offrent galement au programmeur le moyen de dfinir de nouveaux types, quon peut
appeler types programms :
Les plus simples des types programms sont les types numrs. Un type numr est une col-
lection finie de valeurs, sans autre proprit que lgalit. Un exemple de tel type est un ensemble de couleurs, {bleu, blanc, rouge}.
Une structure correspond peu prs lide mathmatique de produit cartsien de plusieurs
domaines. Par exemple la description dune personne se compose dun nom, qui est une chane
de caractres, et dun ge, qui est une valeur entire.
Dans un langage objets comme Java, un type programm peut se dfinir au moyen dune
classe. Une telle classe joue le rle de modle pour dcrire des objets de mme nature : on y
dcrit comment ils sont reprsents au moyen de types dj existants et on y programme les oprations auxquelles ils participent. Lexemple suggr dans le tableau concerne un type Voiture qui reprsente des voitures, dont ltat est caractris par une certaine vitesse et que lon
peut acclrer ou freiner.
Dans ce chapitre, nous nous bornerons prsenter les types primitifs scalaires. Les autres seront
vus ultrieurement, une fois matrise la rdaction de programmes simples.
2.4
2.4.1
Dclarations
Une dclaration consiste donner un nom et indiquer le type dune donne ou dune fonction. En
Java, une dclaration de donne a une des formes suivantes :
22
Module A.P.I
Universit de Rennes 1
2.4.2
Universit de Rennes 1
23
les notations numriques pour les nombres rels se distinguent par la prsence dun point ou
Il existe des oprations qui permettent de convertir des donnes dun type dans un autre type. Ces
oprations sappellent des conversions. Elles ralisent des correspondances usuelles entre domaines
de valeurs :
la conversion dun entier en rel fournit le rel qui reprsente la mme quantit,
la conversion dun rel en entier fournit la partie entire du nombre rel.
En Java une telle conversion se note : (type) expression
Exemples :
(int) 3.141592 vaut lentier 3, de type int
(double) 6 vaut le rel 6.0, de type double
En plus de ces rgles strictes, la plupart des langages ralisent implicitement la conversion des
entiers en rel dans les oprations notes +, -, *, / lorsque un des oprandes est explicitement rel.
Par exemple :
5.0/2 est quivalent 5.0/((double) 2) et vaut donc 2.5.
2.5
2.5.1
24
types Java
nombres entiers
int, long,
short, byte
nombres rels
double, float
caractres
char
valeurs logiques
boolean
Module A.P.I
notations de valeurs
12
-4567
3.141592
'a'
'z'
true
6.02E23
'?'
'\n'
false
Universit de Rennes 1
Il existe plusieurs types pour les nombres entiers : int, cods sur 32 bits (de -231 231-1), long,
cods sur 64 bits (de -263 263-1), short sur 16 bits (de -215 215-1) et byte sur 8 bits (de -128
127). Nous utiliserons gnralement le type int, bien quil ne permette pas de reprsenter des
entiers trs grands ( peu prs de -2 milliards +2 milliards).
Les valeurs entires sont notes classiquement, en dcimal.
De mme il existe deux types pour les nombres rels : float , cods sur 32 bits (nombres en simple prcision) et double , cods sur 64 bits (nombres en double prcision). Nous utiliserons le type
double , car le type float est vraiment peu prcis (mme pas lquivalent de 7 chiffres dcimaux
pour la mantisse).
Les valeurs relles sont notes avec un point pour sparer la partie entire de la partie fractionnaire.
La notation avec exposant 6.02E23 signifie 6.021023.
Les caractres sont reprsents par le type char. Les notations de valeurs utilisent lapostrophe :
'x' signifie le caractre x. Pour les caractres dont lcriture directe est impossible, on utilise une
notation particulire : '\n' signifie le passage la ligne, '\r' le retour en dbut de ligne, '\t'
une tabulation...
Les tableaux suivants rsument les oprateurs du langage. Pour chaque oprateur on a prcis son
profil, cest--dire le type de ses paramtres et de son rsultat. Certaines oprations et constantes
sont notes au moyen dun nom prfix par Math : Math.abs , Math.sqrt , Math.PI ... Ce
sont des fonctions et constantes dfinies dans la classe Math de la bibliothque standard de Java.
oprations avec arguments de type entier
notation
profil
exemple
rsultat
addition
4 + 12
16
soustraction
4 - 12
-8
multiplication
4 * 12
48
changement de signe
int int
- 12
-12
division entire
23 / 4
modulo (reste)
23 % 4
test dgalit
==
4 == 12
false
test dingalit
!=
4 != 12
true
>
4 > 12
false
>=
4 >= 4
true
<
4 < 4
false
<=
4 <= 4
true
test de supriorit
test suprieur ou gal
test dinfriorit
test infrieur ou gal
valeur absolue
Math.abs
int int
Math.abs(-4)
Universit de Rennes 1
25
profil
exemple
rsultat
addition
4.0 + 12.7
16.7
soustraction
4.5 - 12
-7.5
multiplication
4E8 * 12E-3
changement de
signe
double double
division
test de supriorit
48E5
- 12.0
-12.0
23.0 / 4.0
5.75
>
true
test dinfriorit
<
false
valeur absolue
Math.abs
double double
Math.abs(-4.5)
4.5
racine carre
Math.sqrt
double double
Math.sqrt(2.0)
1.414...
sinus
Math.sin
double double
Math.sin(0.0)
0.0
cosinus
Math.cos
double double
Math.cos(0.0)
1.0
tangente
Math.tan
double double
Math.tan(0.0)
0.0
logarithme nprien
Math.log
double double
Math.log(1.0)
0.0
exponentielle
Math.exp
double double
Math.exp(0.0)
1.0
constante
Math.PI
double
Math.PI
3.14159...
Math.E
double
Math.E
2.71828...
constante e
Remarque : dans la plupart des langages de programmation les types rels admettent les comparaisons faisant intervenir lgalit (=, , , ), mais il est prfrable de ne pas les utiliser car cest souvent un non-sens. cause des erreurs darrondi, lgalit de deux rsultats rels est gnralement le
fruit du hasard.
profil
exemple
rsultat
test dgalit
==
'a' == 'w'
false
test dingalit
!=
'a'
true
>
false
>=
false
true
true
test de supriorit
test suprieur ou gal
test dinfriorit
test infrieur ou gal
<
<=
!= 'w'
Les caractres peuvent tre compars. Une relation dordre est dfinie sur les caractres et elle respecte lordre alphabtique pour les lettres 'A'... 'Z'... 'a'... 'z' et lordre numrique usuel pour
les chiffres '0'... '9'.
26
Module A.P.I
Universit de Rennes 1
profil
exemple
rsultat
ngation
boolean boolean
ou logique
true| false
||
true|| ???
&
et logique conditionnel
&&
false &&???
test dgalit
==
false==false
true
test dingalit
!=
false!=false
false
ou logique conditionnel
et logique
! false
true
true
true
false
false
Le ou simple, not |, value toujours ses deux arguments, alors que le ou conditionnel, not
||, nvalue pas le second argument si le premier est vrai (le premier argument dtermine le
rsultat vrai). De mme le et simple, &, value ses deux arguments, alors que le et conditionnel,
&&, nvalue pas le second argument si le premier est faux (le premier argument dtermine le
rsultat faux).
La diffrence est importante comme le montre lexemple suivant :
x>0
& (3/x)<12
provoque une erreur lexcution si x vaut 0 car (3/0)<12 est valu et provoque lerreur tentative de division par 0.
En revanche
x>0
&& (3/x)<12
ne provoque pas derreur si x vaut 0 car x>0 est faux et le total vaut donc faux.
2.5.2
Types numrs
Java ( partir de la version 1.5) offre les types numrs. Un tel type possde un ensemble fini de
valeurs dsignes par autant didentificateurs. On peut par exemple dfinir le type Couleur
comme un type numr possdant 3 valeurs notes bleu, blanc et rouge :
enum Couleur {bleu, blanc, rouge};
Les dclarations des donnes dun type numr utilisent le nom du type, et les dsignations de
valeurs se font au moyen de la notation nomDuType.identificateur. Le seul oprateur dfini sur un
type numr est le test dgalit, not == .
Exemple :
Couleur
Universit de Rennes 1
27
QCM 2.1
Soit lexpression :
2>=3 || 12%2==0
0<2<5
2/5
(double) (2/5)
28
Module A.P.I
Universit de Rennes 1
QCM 2.5
Soit lexpression :
((double) 2)/5
|| c==Couleur.jaun
Universit de Rennes 1
29
30
Module A.P.I
Universit de Rennes 1
Exercice 2.1
objectif : se familiariser avec les types des oprandes et du rsultat dune expression, comprendre les erreurs de syntaxes provoques par le non respect des types.
Lexpression 2+3*4 peut se comprendre de deux manires :
(2+3)*4 qui vaut 20 ou 2+(3*4) qui vaut 14
Pour viter les ambiguts, les oprateurs en Java possdent des priorits. Lopration la plus prioritaire est effectue en premier.
Oprateurs par ordre de priorit dcroissante :
- (moins unaire)
*, /,%(multiplication, division, reste)
+, - (addition, soustraction)
==,!=, <, >, <=, >= (comparaisons)
&& (et logique)
|| (ou logique)
Lexpression 2+3*4 se comprend donc 2+(3*4) et vaut 14.
En cas dgalit des priorits, le calcul a lieu de gauche droite.
Ainsi, 1-4-5 se comprend ((1- 4)-5) et vaut -8.
Si lon veut contrler ces priorits, il est ncessaire de parenthser.
Par exemple, pour obtenir 20, il faut crire (2+3)*4 .
(2) -4-5
(4) 2/3>0
(5) 4-5-3==2*-5/2+1
(7) 6<7&&7<5+3
(3) 5-2<4*2
(8)
6<7<5+3
1 - Parenthsage explicite :
Universit de Rennes 1
31
2 - Vrification :
Une faon simple de vrifier ce qui prcde consiste rdiger un programme de test (une simple
procdure main). Voici le modle, pour vrifier que 2+3*4 est quivalent 2+(3*4) :
class TestParenthesage {
public static void main(String[] arg) {
System.out.print"2+3*4 = ");
System.out.println(2+3*4);
System.out.print("quivalent
: 2+(3*4) = ");
System.out.println(2+(3*4));}
}
Ce modle montre une faon systmatique de raliser un programme de test :
Exercice 2.2
objectif : savoir choisir les types des donnes manipules, faire des conversions si ncessaire.
Premire partie
Rdiger un programme TestMoyenne qui calcule la moyenne de 3 nombres entiers (de type int)
pour les triplets de nombres suivants :
3, 1, 1
-12, 2, 12
4, 6,7
Attention : les rsultats du calcul de la moyenne sont des nombres rels (de type double ).
32
Module A.P.I
Universit de Rennes 1
Deuxime partie
En Java, la procdure principale a pour en-tte :
public static void main(String[] arg)
Le paramtre arg est un tableau de chanes de caractres (type String[] ). Ce paramtre est un
tableau dont les lments valent les chanes de caractres frappes la suite du nom du programme
lors de son lancement. Ceci permet de passer des paramtres au programme lors de son lancement.
Si par exemple on lance le programme par la commande :
java TestMoyenne 12 53 6
arg[0] vaut "12", arg[1] vaut "53" et arg[2] vaut "6".
Les paramtres sont des chanes de caractres. Pour obtenir les nombres rels correspondant, il faut
utiliser la fonction de conversion offerte par la bibliothque Java :
Integer.valueOf( s)
qui rend en rsultat le nombre entier reprsent par la chane de caractres s.
Exemple : Integer.valueOf( "12") vaut le nombre entier 12.
Rajouter la procdure principale de TestMoyenne le calcul et laffichage de la moyenne de 3
nombres frapps la suite de la commande de lancement.
Universit de Rennes 1
33
Aide 2.2
La fonction moyenneDeTroisNombres a trois paramtres, les trois nombres entiers dont il faut
calculer la moyenne.
class TestMoyenneDeTroisNombres {
static double moyenneDeTroisNombres(int x, int y, int z){
// rsultat
: moyenne de x, y et z
...
}
Se mfier de la division entire : si on divise la somme de trois entiers par 3, la division effectue est
la division entire, ce qui nest pas la moyenne. Penser faire correctement une conversion dentier
en rel de type double .
34
Module A.P.I
Universit de Rennes 1
CHAPITRE 3
objectif : connatre prcisment les diverses rubriques dun programme, les diverses sortes de
donnes, les expressions et les instructions lmentaires.
Les types spcifient la nature des donnes manipules par les programmes. Nous allons voir maintenant ce qui permet de manipuler les donnes :
3.1
procdure principale
Les dclarations de donnes globales permettent de dfinir des donnes qui seront utilisables
depuis tout le texte du programme, par opposition aux paramtres et donnes locales des diverses
fonctions du programme qui ne sont utilisables que depuis le texte de ces fonctions.
Commentaires :
Pour faciliter la comprhension dun programme, des commentaires peuvent tre utiles et parfois
ncessaires. Un commentaire est une explication destine aux lecteurs humains, ignore par la
machine (le compilateur).
Universit de Rennes 1
35
Dclarations de donnes
3.2
3.2.1
Dclarations de donnes
36
Module A.P.I
Universit de Rennes 1
class leProgramme {
...
static final type nom = valeur ; constante globale
static type nom ; variable globale
...
static void ppp(...) { dfinition de fonction
final type nom = valeur ; constante locale la procdure ppp
type nom; variable locale la fonction ppp
...
}
Exemple :
class leProgramme {
...
static final double graviteTerrestre = 9.81; constante globale
static final int nombreDeCartes = 32; constante globale
...
Remarques :
3.2.2
Une plus grande lisibilit du programme. En effet un programme nest pas seulement destin
une machine, il doit aussi pouvoir tre compris par des lecteurs humains, pour faciliter sa mise
au point et ultrieurement sa maintenance, cest--dire permettre des modifications dues aux
changements des besoins des utilisateurs du programme.
Universit de Rennes 1
37
Dclarations de donnes
tante doit tre modifie, dans une version ultrieure, seule la dclaration de constante est
modifier.
Les dclarations de constantes peuvent tre utilises galement pour nommer des rsultats
intermdiaires et ainsi viter des expressions trop grosses qui pourraient nuire la lisibilit :
soit un rectangle dfini par les coordonnes de son coin suprieur droit (x1,y1) et de son coin
infrieur gauche (x2,y2 ). On peut calculer la dimension de sa diagonale par :
final double d = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
x1,y1
d
h
x2,y2
Enfin, les dclarations de constantes servent calculer une seule fois une valeur qui doit tre
class Parallelepipede {
public static void main(String[] arg) {
int largeur=...; int longueur=...; int hauteur=...;
final int surfaceDeBase=largeur*longueur;
38
Module A.P.I
Universit de Rennes 1
3.3
Dfinitions de fonctions
objectif : savoir dfinir une fonction, distinguer les fonctions qui ralisent des fonctions au
sens mathmatique et les procdures qui ont des effets.
Une fonction est une collection identifie dinstructions qui fait quelque chose. Une fonction est
destine tre appele. Cela consiste donner des valeurs, appeles paramtres effectifs, la place
des paramtres formels et excuter les instructions de la fonction en utilisant ces paramtres effectifs.
On peut distinguer trois catgories de fonctions :
les fonctions pures, les procdures et les fonctions impures
:
Une fonction pure ralise une fonction au sens mathmatique du mot. Elle calcule une valeur
dun certain type et la rend en rsultat, sans plus. Par exemple la fonction sigma3 qui calcule la
somme de 3 nombres entiers :
static int sigma3(int a, int b, int c) {
// rsultat
: la somme de a, b et c
return a+b+c;
}
1. Le vocable static signifie ici que la fonction est simple, que ce nest pas une mthode dobjet (voir plus loin).
Universit de Rennes 1
39
Dfinitions de fonctions
Un appel de cette fonction pourra avoir la forme sigma(3,5,4) qui a pour rsultat 12. Un tel
appel na pas deffet, il signifie une valeur. Pour que lappel serve quelque chose, il faut ncessairement que la valeur soit utilise, soit en donnant cette valeur une variable du programme :
int x = sigma3(3,5,4);... donne la valeur 12 x,
soit en lutilisant pour calculer le paramtre effectif dun oprateur ou dun autre appel de
fonction :
... System.out.print(sigma3(3,5,4)+2));... affiche 14 sur lcran.
Une procdure ne rend pas de rsultat. On lutilise pour les effets quelle produit. Parmi les
effets on peut distinguer les interactions avec lenvironnement, par exemple :
des affichages sur cran,
des acquisitions de donnes introduites par un utilisateur du programme,
des lectures et critures de fichiers,
des actions sur des moteurs, des vannes...
des changements dtat de certains objets du programme.
On peut prendre comme exemple la procdure afficheSommeDe3Nombres qui affiche sur
lcran la somme de trois nombres :
static void afficheSommeDe3Nombres(int a, int b, int c) {
// effet
: affiche la somme de a, b et c
System.out.print(a+b+c);
}
Un appel possible de cette procdure est afficheSommeDe3Nombres(3,5,4) qui a pour
effet dafficher 12 sur lcran :
12
simple fonction mathmatique. Elle peut avoir un effet, comme une procdure, ou consulter
lenvironnement. On peut prendre pour exemple la fonction lectureNombreEntier qui
rend en rsultat le nombre entier frapp au clavier par lutilisateur du programme :
static int lectureNombreEntier() { ... lit un entier...}
Cette fonction attend que lutilisateur frappe une suite de chiffres au clavier, et sil frappe par
exemple 176, elle rend lentier 176 en rsultat. Ceci ne ralise de toute vidence pas une
fonction au sens mathmatique, puisque bien que sans paramtre elle peut fournir des rsultats
diffrents chaque appel.
Dans la suite, on utilisera le terme gnral de fonction pour dsigner indiffremment une procdure, une fonction pure ou une fonction impure.
En Java, un mme nom de fonction peut tre utilis pour des fonctions diffrentes, condition que
ces fonctions diffrent par les types ou le nombre de paramtres. Lusage de ces fonctions nest pas
40
Module A.P.I
Universit de Rennes 1
ambigu, car on voit trs bien, et le compilateur aussi, quels sont les types et le nombre des paramtres effectifs dun appel et cela dtermine quelle fonction est utilise. Par exemple, on peut utiliser
le mme nom, maximum , pour la fonction qui rend en rsultat le plus grand parmi deux caractres
(selon lordre alphabtique) :
static char maximum(char c1, char c2) {
if (c1>c2) {return c1;} else {return c2;}
(si c1>c2 alors le rsultat est c1, sinon le rsultat est c2)
}
et pour la fonction qui rend en rsultat le plus grand de deux nombres entiers :
static int maximum(int i, int j) {
if (i>j) {return i;} else {return j;}
}
On appelle cela la surcharge des noms de fonction (overloading en anglais). Il ne faut pas en
abuser, mais cest souvent pratique. Cela vite dinventer des noms diffrents pour des fonctions
similaires sur des domaines diffrents. Dailleurs les oprateurs du langage utilisent cette pratique,
puisque par exemple les symboles +, -, *, /, >, <, ==... servent dsigner les oprations usuelles,
et cependant diffrentes, sur les entiers, les rels...
3.4
Une fonction est destine des utilisateurs (ventuellement soi-mme). Il est essentiel de documenter correctement ce quelle offre. Ceci se fait au moyen dun commentaire de spcification. Un tel
commentaire doit noncer avec rigueur et sans ambigut ce que ralise la fonction. Il doit se limiter
dire ce que ralise la fonction et non pas comment elle le ralise car cela ne concerne pas lutilisation de la fonction.
Il est bon que la prsentation des commentaires de spcification soit toujours la mme, cela amliore la lisibilit des programmes. Voici ce que nous proposons :
Universit de Rennes 1
41
Instructions et expressions
3.5
Instructions et expressions
objectif : savoir utiliser les instructions lmentaires.
3.5.1
Squences dinstructions
Les instructions figurent dans ce quon appelle le corps des fonctions. En Java, les instructions lmentaires sont systmatiquement dlimites droite par un ;. Une instruction indique quoi faire
lordinateur. La combinaison la plus simple est la combinaison squentielle dinstructions : les
instructions places les unes la suite des autres sont excutes lune aprs lautre. Lors dun appel
de la fonction, la suite dinstructions ci-aprs est excute dans lordre (1) puis (2) puis (3) :
{
System.out.println(235); (1)
System.out.println(9+6); (2)
System.out.println(12); (3)
Lexcution de ces instructions affiche donc successivement 235 puis 15 puis 12.
235
15
12
42
Module A.P.I
Universit de Rennes 1
: a a
3.5.2
Universit de Rennes 1
43
Instructions et expressions
3.5.3
3.5.4
44
Module A.P.I
Universit de Rennes 1
Il peut y avoir plusieurs instructions de retour dans le corps dune fonction, comme par exemple :
static int maximum(int i, int j) {
if (i>j) {return i;} else {return j;}
}
si i est plus grand que j, cest linstruction return
iqui est excute et termine en rendant en
rsultat la valeur de i, sinon cest linstruction return
jqui est excute et termine en rendant
en rsultat la valeur de j.
On peut ne pas aimer cette multitude dinstructions return dissmines dans le corps dune fonction. Pour faciliter la mise au point et la maintenance des programmes, on peut prfrer une seule
instruction return la fin du texte de la fonction. Pour cela il suffit de donner un nom au rsultat
au moyen dune variable temporaire1, par exemple resul et de terminer la fonction par linstruction return resul . Voici la fonction prcdente programme selon ce principe :
static int maximum(int i, int j) {
int resul;
if (i>j) {resul=i;} else {resul=j;}
return resul;
}
Les procdures, sans rsultat, peuvent galement utiliser une instruction return sans expression
accompagnatrice :
return
Le seul effet de cette instruction est de terminer lexcution de la procdure. Pour des raisons de
lisibilit et de maintenance, il vaut mieux viter cette instruction, sauf dans des cas trs simples, et
laisser se terminer la procdure par la fin de son texte, auquel cas linstruction return est inutile.
3.5.5
Expressions
1. Lutilisation des variables sera vue plus loin. Dans cet exemple la variable ne sert qu nommer un rsultat de calcul pour
sen servir en un autre endroit que celui o il est calcul.
Universit de Rennes 1
45
Instructions et expressions
46
Module A.P.I
Universit de Rennes 1
3.5.6
Universit de Rennes 1
47
Instructions et expressions
trace dexcution
main
afficheSurfaceDeCarre
(a1)
(p1)
(p2)
(p3)
(p4)
temps
(a2)
(p1)
(p2)
(p3)
(p4)
Pour un appel de fonction il se passe peu prs la mme chose. Cependant un appel de fonction
nest pas une instruction, cest une expression qui vaut le rsultat de la fonction. Il faut donc faire
apparatre lappel en tant quexpression dans une instruction qui exploite ce rsultat. Lexemple suivant illustre lappel de fonction. Cest un programme qui provoque un affichage identique au prcdent, mais les actions dcriture sont dans la procdure principale main, la fonction
surfaceDeCarre ne faisant que calculer et rendre en rsultat la surface dun carr.
class TestAppelDeFonction {
Dfinition de fonction
static double surfaceDeCarre(double cote) {
return cote*cote; (p1)
}
48
Module A.P.I
de ct
2.0
(a1) vaut
");
de ct
2.0
(a3) vaut
");
Universit de Rennes 1
surfaceDeCarre
(a1)
la surface du carr de ct 2.0 vaut 4.0
la surface du carr de ct 3.0 vaut 9.0
(a2)
(p1)
temps
(a3)
(a4)
(p1)
On remarquera ici une petite difficult dans le dessin : lappel de fonction surfaceDeCarre(2.0) est au sein mme de linstruction (a2). Pendant que la fonction est excute, linstruction (a2) nest pas termine. Lorsque la fonction se termine, le flot de contrle revient dans
linstruction (a2) pour la terminer (faire limpression de la valeur retourne ici).
3.5.7
... k
... k
... k
...
utilisation de k ayant pour valeur 2
...
utilisation de k ayant pour valeur 12
...
utilisation de k ayant pour valeur 9
Remarque : le type nest indiqu quune seule fois, lendroit de dclaration de la variable.
En toute rigueur, lusage des variables nest ncessaire que pour raliser des itrations (voir plus
loin). Mais le langage ninterdit pas de les utiliser dans dautres circonstances, l o des constantes
auraient suffi. Voici par exemple trois faons de calculer le maximum de trois nombres a, b et c en
Universit de Rennes 1
49
Instructions et expressions
3.5.8
a6.02E23
coucou
i prend la valeur 12, c le caractre 'a', x la valeur 6.02 1023 et message la valeur "coucou" .
1. Ces fonctions ne sont pas les fonctions standards de Java pour lire des donnes au clavier. Ce sont des fonctions plus faciles utiliser introduites pour ce cours. Leurs dfinitions en termes des fonctions standards de Java sont donnes en annexe.
50
Module A.P.I
Universit de Rennes 1
Pour disposer de ces fonctions de lecture, il faut placer en premire ligne du fichier source du programme la directive :
import es.*;
Exemple : le programme suivant calcule et affiche le volume dun paralllpipde rectangle dont la
largeur, la longueur et la hauteur sont fournies au clavier.
import es.*;
class Parallelepipede {
public static void main(String[] arg) {
final
final
final
final
int
int
int
int
largeur = Lecture.unEntier();
longueur = Lecture.unEntier();
hauteur = Lecture.unEntier();
surfaceDeBase=largeur*longueur;
Comme le montre cet exemple, des constantes peuvent tre initialises par des lectures. Pour allger
le texte, on utilise parfois des variables (abusivement, en omettant le vocable final ) :
int largeur = Lecture.unEntier();
Universit de Rennes 1
51
Instructions et expressions
QCM 3.1
import es.*;
class TestLectures{
public static void main(String[] z){
int x = 12;
String s = "coucou";
x = Lecture.unEntier();
s = Lecture.chaine();
System.out.print("x="+x); System.out.println(" s="+s);
}
}
Au moment de lexcution, lutilisateur entre au clavier : 56 toto
52
Module A.P.I
Universit de Rennes 1
QCM 3.2
On considre le programme suivant :
class TestFonctions{
static int x;
static int plusUn(int k){
// ???
return k+1;
}
static void affichePlusUn(int x){
// ???
System.out.print(x+1);
}
static void ajouteUnAX(){
// ???
x=x+1;
}
rsultat
: k+1
effet
: ajoute 1 k
effet
: affiche k+1
effet
: ajoute 1 x
: // rsultat
: // effet
: ajoute 1 k
: // effet
: affiche x+1
: // effet
: ajoute 1 x
: x+1
: x+1
: ajoute 1 x
: affiche x+1
Universit de Rennes 1
53
Instructions et expressions
affichePlusUn .
54
Module A.P.I
affiche 7.
donne la valeur 7 la variable globale x.
Universit de Rennes 1
Exercice 3.1
r2
r1
r1
r2
Exercice 3.2
Universit de Rennes 1
55
Instructions et expressions
56
Module A.P.I
Universit de Rennes 1
CHAPITRE 4
objectif : savoir o et comment donner des noms aux lments dun programme, quand naissent et meurent les donnes.
Le but de ce chapitre est dapporter des prcisions sur trois aspects importants :
Le nommage : quelle occasion on doit donner un nom une chose (constante, variable, fonc-
4.1
Nommage
Les noms qui apparaissent dans les programmes pour dsigner les choses sappellent des identificateurs. Ils doivent obir quelques rgles simples :
commencer par une lettre et se poursuivre par des lettres ou des chiffres,
ne pas tre identique un vocable du langage tel que, en Java :
class , int, boolean , if, else, while ...
A ces rgles de syntaxe sajoutent quelques conventions et conseils :
Choisir les noms les plus signifiants possibles : des noms bien choisis compltent, voire rempla-
cent avantageusement les commentaires. Il ne faut pas hsiter utiliser des mots longs si ncessaire. Par exemple :
final int graviteTerrestre = 9.81;
Respecter les normes communment admises, surtout si elles ont fait leur preuve. La norme la
plus rpandue actuellement est :
Les noms de classes commencent par une majuscule :
class TestMoyenne
Les noms de donnes et de fonctions commencent par une minuscule :
String prenom;
int maximum(int i, int j){...}
Pour les noms composs, les sparations se font au moyen de majuscules :
ageDuCapitaine
moyenneDeTroisNombres
Universit de Rennes 1
57
Portes didentification
4.2
Portes didentification
Le schma suivant illustre la structure dun programme simple dot de diverses dclarations de
donnes :
class TestMachin {
static int v;
static double c;
Dans ce schma, on a utilis les mmes noms pour dsigner des choses diffrentes :
58
Module A.P.I
Universit de Rennes 1
c qui dsigne partout la mme donne et des identificateurs de fonctions f et g qui sont utilisables
partout pour dsigner la fonction f et la procdure g.
Une donne locale et une donne globale peuvent porter le mme nom. En cas dhomonymie, le
nom dsigne la donne locale. Il vaut mieux viter de telles homonymies car elles sont source
derreurs.
4.3
Dures de vie
Les donnes dclares au niveau global du programme, en dehors de toute fonction, et dotes du
vocable static , telle que static
int dans
v lexemple, sappellent des variables globales.
Elles existent pendant toute lexcution du programme. On dit que leur dure de vie stend du
dbut la fin de lexcution du programme. Plus gnralement cest ce que signifie le vocable
static : qui existe en un seul exemplaire pendant toute lexcution du programme1.
Les variables dclares au sein dune fonction, telle que int x dans la fonction f, char x dans
la fonction g ou encore double
y
dans la procdure principale main, sappellent des variables
locales. Elles existent uniquement pendant une excution de la fonction dans laquelle elles sont
dclares. Leur dure de vie stend du dbut la fin de lexcution de cette procdure : elles sont
cres au moment de lappel de la fonction et sont dtruites au retour.
Ceci signifie notamment quune variable locale na pas de valeur dtermine au dbut de lexcution dune fonction, alors quune variable globale a toujours une valeur dtermine, celle attribue
par sa dernire affectation.
Comme exemple simple dusage de variables globales, on peut considrer le programme suivant qui
imprime un texte avec un numro de ligne en dbut de chaque ligne :
class Imprime LaCigaleEtLaFourmi {
static int numeroDeLigne;
La variable numeroDeLigne est une variable globale. Elle est accessible depuis le programme
principal qui linitialise 1, et par la procdure imprimeLigne qui imprime sa valeur en dbut de
1. Le vocable static qualifie donc les choses les plus simples, qui existent tout le temps, en correspondance directe
avec le texte de leur dclaration. Les choses plus compliques telles que les variables locales de fonctions ou bien les
composants dobjets (voir plus loin propos des classes modles dobjets) dont la dure de vie est gale la dure dexcution dun appel de fonction ou lexistence dun objet, ne ncessitent aucun vocable particulier.
Universit de Rennes 1
59
ligne et lincrmente de manire y trouver une valeur augmente de 1 lors de sa prochaine excution. Ce programme imprime :
1
2
3
4
Il ne faut pas abuser de lusage de variables globales. Il est assez rare den avoir besoin. Il ne faut
surtout pas les utiliser pour transmettre des arguments une fonction : les paramtres sont faits pour
cela. Lexemple prcdent est la limite dun bon usage des variables globales. On peut la place
utiliser un paramtre supplmentaire numeroDeLigne pour indiquer le numro de ligne la procdure imprimeLigne :
class ImprimeLaCigaleEtLaFourmi {
static void imprimeLigne(int numeroDeLigne, String ligne) {
System.out.print("\n");
System.out.print(numeroDeLigne);
System.out.print("
"); System.out.print(ligne);
}
4.4
calcul de (a+b)/(c-d)
resultat=(a+b)/(c-d)
double sPlus=sin(a+b);
double sMoins=sin(a-b);
resultat=(sPlus+sMoins)/(sPlus-sMoins);
expression sous
forme de treillis
resultat
+
sPlus
Module A.P.I
sin
sin
60
/
sMoins
v
Universit de Rennes 1
Si les rsultats intermdiaires ne sont utiliss quen un seul endroit, cest--dire si le calcul total
sexprime sous forme dun arbre doprateurs et doprandes, on peut mettre directement son
expression lendroit o il est utilis, en tant que sous-expression. Cest le cas de lexemple de gauche.
Si un rsultat intermdiaire est utilis en plusieurs endroits, on a intrt, et cest mme parfois
ncessaire, de nommer ce rsultat intermdiaire et dlaborer le calcul en plusieurs expressions distinctes. Cest le cas de lexemple de droite. Le calcul total ne sexprime pas sous forme dun arbre
mais sous forme dun treillis doprateurs et doprandes.
Les langages de programmation permettent de dclarer des variables locales pour nommer ces
rsultats intermdiaires. Il faut dclarer ces variables le plus prs possible des endroits dutilisation, et ne pas polluer le programme en les dclarant nimporte o. Il faut galement, si cest possible, leur donner une valeur lendroit de leur dclaration. Ce sont des variables locales et leur
dure de vie est donc le temps dexcution de la fonction.
Rien ninterdit bien sr de nommer un rsultat intermdiaire dans le cas o il nest utilis quen un
endroit. Cela peut mme tre plus clair, en vitant une expression peu lisible car trop longue ou en
mettant en valeur ce rsultat intermdiaire en le nommant de faon judicieuse. Un tel nommage
remplace avantageusement certains commentaires. Mais il ne faut pas abuser des identifications
inutiles. Des identifications intempestives attirent lattention sur ce qui ne le mrite pas et dgradent
la lisibilit en ne profitant pas du pouvoir expressif des expressions.
Java permet de placer des dclarations peu prs nimporte o dans le corps des fonctions : il faut
en profiter.
Blocs dinstructions
De nombreux langages, Java en particulier, possdent en plus une notion de bloc dinstructions. Il
sagit simplement dun regroupement dinstructions que lon peut accompagner de dclarations.
Ces dclarations sont alors locales au bloc : dune part une variable ou constante ainsi dclare a
une dure de vie gale la dure dexcution du bloc et dautre part lidentification introduite par la
dclaration a une porte limite ce bloc.
... dbut de bloc entier k, rel x... instructions qui peuvent utiliser k et x... fin de bloc...
En Java, un bloc est dlimit par des accolades {...} , et tout ce qui est entre accolades constitue un bloc. On peut placer un bloc partout o on peut placer une instruction. Un des principaux
intrts du bloc est de limiter la porte didentification des identificateurs et ainsi amliorer la lisibilit et la fiabilit des programmes. Lexemple suivant illustre lusage dun bloc en Java. Les variables u, v, sPlus et sMoins sont ici locales au bloc introduit.
double resultat;
...
{
double u=a+b; double v=a-b;
double sPlus=sin u; double sMoins=sin v;
resultat=(sPlus+sMoins)/(sPlus-sMoins);
}
...
Ces variables ne servent que dintermdiaires de calcul pour la variable resultat . La prsence
dun bloc est rassurante pour le lecteur : il na pas se demander si u, v, sPlus et sMoins servent autre chose dans le programme, car ces variables sont inconnues en dehors du bloc o elles
sont dclares.
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
61
Modularit
4.5
Modularit
De faon gnrale, la modularit consiste dcouper les gros programmes en morceaux, chaque
morceau concernant un thme.
La modularit intervient plusieurs niveaux. En Java, on peut distinguer trois niveaux :
Les fonctions : une fonction ralise un morceau de traitement bien spcifi (calcul dune fonc-
4.5.1
Dcoupage en classes
Les fonctions ou donnes dclares dans une classe sont accessibles depuis les autres classes condition dtre affubles du vocable public .
Si une fonction f ou une donne x (statiques) sont dclares dans une classe C, pour lutiliser
depuis une autre classe il faut utiliser une notation pointe :
C.f() ou C.x
Cest ainsi, par exemple, que lon utilise les fonctions et donnes de la classe Math de la bibliothque standard : Math.sin(x) , Math.PI ...
class Math {
...
public static final double PI =
...
...
public static double sin(double x) {...}
...
}
class Test {
... Math.PI
....
... Math.sin(teta)
}
...
Ou bien encore les fonctions de lectures depuis le clavier dfinies dans la classe Lecture du
paquetage es offert pour les exercices : Lecture.chaine() , Lecture.unEntier() ...
62
Module A.P.I
Universit de Rennes 1
4.5.2
Paquetages
En Java, les classes concernant un mme domaine peuvent tre regroupes en paquetages. Les programmes sources des classes dun paquetage appel xxx commencent par la directive :
package xxx;
Les classes dun paquetage doivent tre places dans un rpertoire de mme nom que le paquetage.
Au sein dun paquetage, on a accs aux classes de ce paquetage et aux classes dclares public
des autres paquetages. Pour dsigner une classe dun autre paquetage, on utilise un nom absolu de
la forme :
nom-du-paquetage.nom-de-classe
Il est possible de dsigner les classes par leur nom court, sans prciser le paquetage, en utilisant la
directive import :
import nom-de-paquetage .nom-de-classe ; pour utiliser une classe du paquetage
import nom-de-paquetage .*; pour pouvoir utiliser toutes les classes du paquetage.
A.java
package xxx ;
public class A {
...
B.java
}
package xxx ;
rpertoire xxx
A.class
B.class
public class B {
...
}
unProgramme.java
import xxx ;
.........
... A ...
... B ...
.........
Les paquetages permettent notamment de structurer les bibliothques dintrt gnral. Par exemple, la bibliothque standard de Java est dcoupe en de nombreux paquetages, par exemple :
java.io : concerne les entres et sorties, notamment pour accder aux fichiers,
java.awt et javax.swing : concerne lusage dinterfaces graphiques (fentres, boutons, zone
de texte...)
java.applet : concerne la programmation dapplets (programmes java tlchargs via le Web
et excuts sur la machine de lutilisateur)
java.net : concerne les accs un rseau,
etc...
Universit de Rennes 1
63
Modularit
Pour pouvoir utiliser les paquetages, le compilateur et lexcuteur de Java doivent connatre les
rpertoires o se trouvent ces paquetages. Cela est indiqu par une variable denvironnement qui
sappelle CLASSPATH (Une variable denvironnement est une variable que lon dfinit, par une
commande, au niveau du systme dexploitation de lordinateur et qui sert paramtrer les fonctions de base du systme et les applications). La variable denvironnement CLASSPATH doit contenir la liste des rpertoires qui contiennent les rpertoires des paquetages, par exemple :
/udd/API/paquetagesMaison:.
Les noms des rpertoires sont spars par :. Dans cet exemple, le rpertoire /udd/API/
paquetagesMaison contient les paquetages maison pour les travaux pratiques de ce cours et
le symbole . signifie le rpertoire courant.
Lendroit o se trouvent les classes utiliser peut galement tre indiqu au moment de la compilation ou de lexcution par une option -classpath :
javac
tion,
-classpath
/udd/API/paquetagesMaison:.
64
Module A.P.I
pour
Prog.java
la compilapour lexcution.
Universit de Rennes 1
QCM 4.1
A propos du choix des identificateurs, on peut affirmer :
1 - Il faut utiliser les noms les plus courts possibles car cela rduit la taille des programmes et les
rend plus lisibles.
2 - Dans la norme usuelle, les noms de classe commencent par une majuscule et les noms des
donnes et des fonctions commencent par une minuscule.
3 - Il faut utiliser les noms les plus signifiants possibles, mme si cela conduit des noms longs,
car cela remplace avantageusement de nombreux commentaires et rend les programmes plus lisibles.
4 - On a le droit dutiliser villeDeMilleHabitants comme identificateur.
5 - On a le droit dutiliser ville De Mille Habitants comme identificateur.
6 - On a le droit dutiliser villeDe1000habitants comme identificateur.
7 - On a le droit dutiliser 1000habitants comme identificateur.
8 - On a le droit dutiliser classe comme identificateur.
9 - On a le droit dutiliser class comme identificateur.
QCM 4.2
On considre le programme suivant :
class QCMLocalGlobal{
static int x;
static int plusK(int x, int k){
int resul=x+k;
return resul;
}
static void ajouteK(int k){
int resul=x+k;
x=resul;
}
Universit de Rennes 1
65
Modularit
locale x du main.
5 - Lidentificateur resul dsigne la mme variable dans la fonction plusK et dans la procdure ajouteK .
6 - Ce programme affiche :
7 - Ce programme affiche :
QCM 4.3
5 - Il est impossible dutiliser une fonction dune classe A depuis une autre classe B.
6 - Pour utiliser une chose statique appele f dfinie dans dune classe A depuis une autre classe
7 - Pour utiliser une chose statique appele f dfinie dans dune classe A depuis une autre classe
B, il faut la dsigner par A.f.
QCM 4.4
grammes java) dans quels rpertoires se trouvent les classes et les paquetages utiliser.
6 - Loption -classpath des commandes javac et java indique (au compilateur ou lexcuteur de programmes java) dans quels rpertoires se trouvent les classes et les paquetages utiliser.
7 - Pour utiliser les classes dun paquetage ppp, on place gnralement en dbut du texte source
une directive import ppp.*; .
8 - Pour utiliser les classes dun paquetage ppp, il est ncessaire de placer en dbut du texte
source une directive import ppp.*; .
9 - Pour utiliser une classe A dun paquetage ppp, on peut la dsigner par ppp.A .
66
Module A.P.I
Universit de Rennes 1
Exercice 4.1
Portes dindentifications
Exercice 4.2
Universit de Rennes 1
67
Modularit
Exercice 4.3
une classe Cercle , spcialise dans les calculs concernant les cercles,
une classe Rectangle , spcialise dans les calculs concernant les rectangles.
une classe TestModularite contenant la procdure principale qui teste les deux classes prcdentes pour un cercle de rayon 12 et pour un rectangle de cts 12 et 15.
68
Module A.P.I
Universit de Rennes 1
Instructions conditionnelles
CHAPITRE 5
Instructions conditionnelles
5.1
condition1
condition2
instructions1
instructions2
autre
...
instructions
Ici, condition1, condition2... sont des expressions rsultat boolen. Le lot dinstructions correspondant la premire de ces expressions dont le rsultat est vrai est excut. Si toutes les expressions sont fausses, les instructions du dernier sinon sont excutes.
En Java cela scrit :
if (condition1) { instructions1 }
else if ( condition2) { instructions2 }
else if ( condition3) { instructions3 }
...
else { instructions }
En Java, on nexige pas que les conditions soient exclusives : une condition nest teste que si les
prcdentes sont fausses. Le dernier cas, introduit par un simple else, correspond au cas o
aucune condition nest vraie. Il est optionnel : si on ne le met pas, rien nest excut si aucune condition nest vraie. Les instructions de chacune des branches de la construction conditionnelle propose sont encadres daccolades {...} et constituent donc un bloc. Ce nest vraiment obligatoire
que sil y a une squence de plusieurs instructions dans la branche, mais il vaut mieux mettre systmatiquement les accolades, mme pour une seule instruction, de faon ne pas changer de forme si
des modifications de programme obligent rajouter des instructions.
Universit de Rennes 1
69
signe ( n ) = 0
+1
si n<0
si n=0
si n>0
return 1;
car le compilateur nadmet pas quune fonction qui doit rendre un rsultat puisse se terminer sans
instruction return .
70
Module A.P.I
Universit de Rennes 1
Instructions conditionnelles
si a b
si a < b
Exemple 3 :
La fonction decodeMois rend en rsultat le nom du mois de lanne dont le numro est pass en
paramtre. Le numro du mois doit tre un entier compris entre 1 et 12. Le nom du mois est une
chane de caractres de type String .
static String decodeMois(int numeroDeMois) {
// prrequis
: numeroDeMois>=1 et numeroDeMois<=12
// rsultat
: le nom en clair du mois de numro numeroDeMois
if (numeroDeMois==1) {
return "janvier";}
else
if (numeroDeMois==2) {
return "fvrier";}
else
if (numeroDeMois==3) {
return "mars";}
else
if (numeroDeMois==4) {
return "avril";}
else
if (numeroDeMois==5) {
return "mai";}
else
if (numeroDeMois==6) {
return "juin";}
else
if (numeroDeMois==7) {
return "juillet";}
else
if (numeroDeMois==8) {
return "aot";}
else
if (numeroDeMois==9) {
return "septembre";}
else
if (numeroDeMois==10) {
return "octobre";}
else
if (numeroDeMois==11) {
return "novembre";}
else
/* numeroDeMois==12 */{ return "dcembre";}
}
: numeroDeMois>=1 et numeroDeMois<=12
Un tel prrequis na pas tre vrifipar le programme de la fonction, mais doit tre respect par
celui qui lappelle. En dautres termes : tant pis pour lutilisateur de la fonction sil viole le prrequis, le rsultat a le droit dtre nimporte quoi. Ici le rsultat sera "dcembre" dans ce cas, mais
cest un nimporte quoi comme un autre, et cela ne fait pas partie de la spcification de la fonction.
Universit de Rennes 1
71
Imbrication de conditionnelles
5.2
Imbrication de conditionnelles
objectif : savoir choisir entre des conditionnelles imbriques ou une conditionnelle tale
La construction conditionnelle est elle-mme une instruction. On peut donc utiliser une conditionnelle au sein dune conditionnelle.
Considrons par exemple la fonction qui tant donn un numro de mois donne le nombre de jours
de ce mois. Pour simplifier, on ne sintresse pas aux annes bissextiles. Le nombre de jours est
donc :
pour les mois de numro infrieur 8 (janvier... juillet), 30 jours pour les mois pairs, sauf 28
72
Module A.P.I
Universit de Rennes 1
Instructions conditionnelles
Universit de Rennes 1
73
Aiguillage
5.3
Aiguillage
La plupart des langages de programmation offrent une forme particulire de conditionnelle, que
lon peut appeler aiguillage, qui permet dexcuter un bloc dinstructions choisi parmi plusieurs
selon la valeur dune expression de type scalaire discret : entier, caractre, type numr. La
forme gnrale dune telle construction est :
aiguillage selon la valeur de expression
soit valeur1 : excuter instructions1
soit valeur2 : excuter instructions2
soit valeur3 : excuter instructions3
...
autres cas : excuter instructions
Cette construction nest pas trs gnrale car le critre du choix ne peut tre que la valeur dune
expression scalaire et on na droit qu des constantes pour valeur1, valeur2... On peut se passer de
cette construction car elle est strictement quivalente :
v=expression
aiguillage selon la valeur de v
si v=valeur1 excuter instructions1
sinon si v=valeur2 excuter instructions2
sinon si v=valeur3 excuter instructions3
...
sinon excuter instructions
Laiguillage est utilis essentiellement pour des raisons de performance : le compilateur le traduit
en une instruction de la machine qui, selon la valeur de lexpression, saute directement, en un
coup, la branche excuter.
En Java la forme de cette instruction est :
switch ( expression) {
case valeur1: instructions1 break;
case valeur2 : instructions2 break;
case valeur3 : instructions3 break;
...
default
:instructions
}
Cette instruction nest pas trs heureuse cause des break; quil faut placer en fin de chacune
des branches. Si on ne met pas le break; , au lieu de poursuivre lexcution la suite de
laiguillage, la branche suivante est excute. Ceci est un hritage de mauvais got du langage C.
titre dexemple, voici un programme qui reprend les fonctions prcdentes, decodeMois et
nombreDeJoursDuMois en utilisant laiguillage. La procdure principale de ce programme lit
au clavier un numro de mois et affiche lcran le nombre de jours du mois correspondant. On
notera sur cet exemple que lon peut regrouper les cas qui donnent lieu un mme traitement.
74
Module A.P.I
Universit de Rennes 1
Instructions conditionnelles
class TestNombreDeJoursDuMois {
static int nombreDeJoursDuMois(int numeroDeMois) {
// rsultat
: nombre de jours du mois de numro numeroDeMois
int resul;
switch (numeroDeMois) {
// janvier, mars, mai, juillet, aot, octobre, dcembre
case 1
: case 3
: case 5
:
case 7
: case 8
: case 10
: case 12
: resul=31; break;
// avril, juin, septembre, novembre
case 4
: case 6
: case 9
: case 11
: resul=30; break;
// fvrier
case 2
: resul=28; break;
default
: resul=0;
}
return resul;
}
static String decodeMois(int numeroDeMois) {
// rsultat
: le nom en clair du mois de numro numeroDeMois
// "mois inconnu" si numeroDeMois nest pas compris
// entre 1 et 12
String resul;
switch(numeroDeMois) {
case
1 : resul= "janvier"; break;
case
2 : resul= "fvrier"; break;
case
3 : resul= "mars"; break;
case
4 : resul= "avril"; break;
case
5 : resul= "mai"; break;
case
6 : resul= "juin"; break;
case
7 : resul= "juillet"; break;
case
8 : resul= "aot"; break;
case
9 : resul= "septembre"; break;
case 10 : resul= "octobre"; break;
case 11 : resul= "novembre"; break;
case 12 : resul= "dcembre"; break;
default
: resul= "mois inconnu";
}
return resul;
}
Universit de Rennes 1
75
Aiguillage
QCM 5.1
Considrons les fonctions :
static int choix(boolean cond,int k1,int k2){
// rsultat
: k1 si cond, k2 sinon
if(cond){return k1;}
else {return k2;}
}
static int f(int k1, int k2){
// rsultat
: ???
return choix(k1>k2,k1,k2);
}
static int g(int k1){
// rsultat
: ???
return choix(k1>=0,k1,-k1);
}
static int h(int k1, int k2){
// rsultat
: ???
return choix(k1>k2,k1-k2,k2-k1);
}
Module A.P.I
Universit de Rennes 1
Instructions conditionnelles
QCM 5.2
Considrons la fonction :
static
String
choix(int
// prrequis
: ???
// rsultat
: ???
if(c==1){return s1;}
else if (c==2){return s2;}
else /*c==3*/{return s3;}
}
c, String
s1,
String
s2,
String
s3){
vaut "alfred" .
provoque une erreur lexcution.
vaut "toto" .
provoque une erreur lexcution.
vaut "dupont" .
: c>=1 et c<=3
: s1, s2 ou s3 selon que c vaut 1, 2 ou 3
c, String
s1,
String
s2,
String
12 - La fonction choix ne peut pas tre programme par laiguillage prcdent car cest une
erreur de syntaxe.
13 - La fonction choix ne peut pas tre programme par laiguillage prcdent car labsence
dinstructions break dans les branches rend le rsultat incorrect.
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
77
s3){
Aiguillage
QCM 5.3
Considrons la fonction :
static boolean comprisEntre(int k, int a, int b){
// prrequis
: a<=b
// rsultat
: indique si a<=k<=b
boolean resul;
if(k<a){resul=false;}
if(k>b){resul=false;}
else {resul=true;}
return resul;
}
tion).
78
Module A.P.I
Universit de Rennes 1
Instructions conditionnelles
Exercice 5.1
Exercice 5.2
Mdiane
Rdiger une fonction qui calcule la mdiane de trois entiers distincts, cest--dire celui qui est
encadr par les deux autres.
Exemple : la mdiane de 8, 1, 4 est 4.
Exercice 5.3
objectif : savoir analyser tous les cas pertinents sur les donnes et matriser limbrication de
conditionnelles.
Rdiger un programme qui affiche la ou les solutions dune quation du second degr :
ax2+bx+c=0
Attention : faire une analyse srieuse. Les nombres a,b,c sont des nombres quelconques. Ils peuvent notamment tre nuls.
Conseil : rdiger une fonction qui rende en rsultat une chane de caractres signifiant en clair le
nombre et la nature des solutions.
Universit de Rennes 1
79
Aiguillage
Aide 5.1
Pour maxDeTroisNombresV1 :
utiliser le fait que maximum(a,b,c) = max(a,max(b,c))
Pour maxDeTroisNombresV2 :
on peut utiliser une conditionnelle tale trois branches dont les branches correspondent aux cas
respectifs o le maximum est a, b ou c.
Aide 5.2
Mdiane
Analyser le problme selon les trois rsultats possibles (a, b ou c), ce qui conduit une conditionnelle tale avec les trois conditions qui expriment respectivement que a, b ou c est la mdiane.
Aide 5.3
Nous avons choisi de raliser une fonction solution qui reoit en paramtres les trois coefficients a,
b et c et rend en rsultat une chane de caractre qui signifie en clair le nombre et la nature des
solutions : static String solution(double a, double b, double c)
class TestEquationSecondDegre {
static String solution(double a, double b, double c) {
// rsultat
: les solutions en clair de lquation ax2+bx+c=0
...
}
: "+solution(4,-8,4));
pour c0 :
et
b delta
------------------------------2a
80
Module A.P.I
et
b + i delta
-----------------------------------2a
Universit de Rennes 1
Rcursivit et itration
CHAPITRE 6
6.1
Rcursivit et itration
Exprimer la rptition
objectif : comprendre deux faons diffrentes de rpter des traitements :
la rcursivit : exprime le rsultat cherch comme solution dquations,
l itration : exprime le rsultat cherch comme lment dune suite de valeurs.
6.1.1
Mthode rcursive
La mthode rcursive est base sur un systme dquations. On cherche des quations qui expriment la fonction calculer pour diverses formes de largument en terme de la mme fonction applique des arguments plus simples. Pour notre exemple, lencadr suivant suggre dexprimer
somme(n) au moyen de somme(n-1) :
somme(n) = 0 + 1 + 2 +... + n
somme(n-1)
Cette formulation nest valable que pour n>0. 0n se pose le problme pour n=0, et bien videmment
la rponse est 0. Ces cas particuliers jouent un rle important : on les appelle les cas de base. Ce
sont les cas pour lesquels le calcul de la solution ne fait pas intervenir la fonction elle-mme. Il est
impratif davoir de tels cas, sinon les quations ne conduisent pas un algorithme. Sans les cas de
base, les quations tournent en rond et ne permettent pas de calculer la fonction en un nombre fini
Universit de Rennes 1
81
Exprimer la rptition
6.1.2
Mthode itrative
La mthode itrative est base sur une suite rcurrente. On cherche une suite dfinie par rcurrence
(cest--dire dont le terme de rang k sobtient par une formule utilisant le terme de rang k-1).
Pour la fonction somme prise en exemple, on envisage la suite :
S0 = 0, S1= 0 + 1, S2= 0 + 1+ 2,...
Sn=0 + 1+ 2...+ n
S0 = 0,
Si = Si-1 + i pour i>0
On a alors : somme(n) = Sn
Le passage de la suite au programme se fait ainsi :
on utilise une variable, s ici, destine valoir successivement les valeurs de la suite,
on initialise cette variable la premire valeur de la suite, 0 ici,
on rpte, en Java au moyen dune instruction while , une instruction daffectation de cette
variable qui fait passer sa valeur du terme de rang i-1 au terme de rang i, et ce jusqu obtention
du terme qui nous satisfait, le terme de rang n ici.
Pour savoir si on a obtenu le terme de rang n, il faut dans cet exemple une variable auxiliaire, i, qui
vaut en permanence le rang du terme calcul dans s. La variable i est initialise 0 et incrmente
chaque rptition de litration.
Cela conduit la dfinition itrative suivante de la fonction somme :
static int somme(int n) {
// prrequis
: n>=0
// rsultat
: la somme des entiers de 0 n
int s=0; int i=0;
while(i<n) {s=s+i; i=i+1;}
return s;
}
82
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
6.2
Rcursivit
objectif : savoir rdiger des fonctions simples de manire rcursive.
6.2.1
factorielle ( n ) =
si n > 1
n factorielle ( n 1 )
Ceci conduit la programmation rcursive suivante :
static int factorielle(int n) {
// prrequis
: n>0
// rsultat
: la factorielle de n
if (n==1) {return 1;}
else {return n*factorielle(n-1);}
}
Exemple 2 : fonction pgcd
La fonction pgcd rend comme rsultat le plus grand commun diviseur de deux nombres entiers
strictement positifs a et b. Le calcul rcursif peut-tre tabli partir des quations bien connues
suivantes :
a
si a=b
si a<b
pgcd (a,b a)
Ce qui conduit la dfinition rcursive :
static int pgcd(int a, int b) {
// prrequis
: a>0 et b>0
// rsultat
: le pgcd de a et b
if (a==b) {return a;}
else if (a>b) {return pgcd(a-b,b);}
else /* a<b */ {return pgcd(a,b-a);}
}
Ces exemples montrent que le passage des quations au programme rcursif est systmatique. Chaque quation donne lieu une branche de conditionnelle :
Universit de Rennes 1
83
6.3
1
si n = 1
factorielle ( n ) = factorielle ( n + 1 )
si n > 1
---------------------------------------------n+1
Pour sassurer de la terminaison, il faut considrer la ou les suites possibles dappels rcursifs et
vrifier que cette suite atteint en un nombre fini de termes les cas pour lesquels il ny a pas dappel
rcursif, appels cas de base.
Un moyen systmatique et formel de sen assurer est de trouver une fonction de terminaison. Cest
une fonction (mathmatique) qui a les proprits suivantes :
elle est positive (par prrequis sur largument de factorielle, n est positif),
largument des appels rcursifs, n-1 ici, est strictement infrieur n.
Pour la fonction pgcd, trouver une fonction de terminaison est moins trivial. On peut prendre :
fonctionDeTerminaison(a,b) = a+b
Cette fonction est bien positive, par prrequis sur les arguments a et b.
dans le cas a>b : lappel rcursif se fait avec a-b et b et a-b+b = a est bien strictement infrieur
84
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
La notion de fonction de terminaison sert prouver la terminaison dun calcul rcursif. La conception dun algorithme est souvent une activit intuitive, base sur des analogies et des expriences
acquises et concevoir un algorithme nest pas la mme chose que de le prouver. On fait rarement
une preuve formelle des algorithmes, mais il est tout de mme essentiel de savoir que cela existe,
que tout programme correct ne marche pas par hasard. Il est satisfaisant pour lesprit de savoir que,
si on veut, on peut faire de telles preuves.
6.4
6.4.1
u=a
cond(u)
u=a
tant que cond(u) est fausse faire u = f(u)
vrai
faux
instructions
qui ralisent
u = f(u)
Universit de Rennes 1
85
6.4.2
une variable u, de type double , sera utilise, initialise 1, le premier terme de la suite,
la condition darrt de litration sera | u2 - a | < 0.001,
le corps de litration ralisera (u + a/u)/2..
Ce qui donne :
static double racineCarree(double a) {
// prrequis
: a>=0
// rsultat
: racine carre de a 0.001 prs
double u = a;
while (!(Math.abs(u*u-a)<0.001)) {u = (u + a/u)/2);}
return u;
}
6.4.3
86
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
...
ki :
...
ki-1+1
21
32
46
524 ...
faci : 1
(ki-1+1)faci-1
a
si a=b
si a<b
pgcd (a,b a)
on imagine assez facilement une suite de couples <ui,vi> dont les composants convergent vers
pgcd(a,b). Il sagit de la suite initialise <a,b> et dont llment suivant sobtient en retranchant le
plus petit composant du plus grand. Par exemple, pour a=21 et b=28, la suite <ui,vi> est :
<21,28>, <21,7>,<14,7>,<7,7>
Le pgcd est 7. Llment qui nous intresse dans cette suite se reconnat au fait que ui=vi. La condi-
Universit de Rennes 1
87
6.4.4
88
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
trace dexcution
main
pgcd
<u,v>
(m1)
(m2)dbut
(p1)
<28,21>
<7,21>
(p3) u<v
(p5)
<7,14>
<7,7>
6.4.5
(p6)
Universit de Rennes 1
89
pgcd (a,b) =
pgcd(max(a, b) min(a, b), min(a, b))
si a b
Ces quations sont strictement quivalentes aux prcdentes. Cest une autre faon de dire, au
moyen des fonctions min et max, que lon peut remplacer le plus grand des deux nombres par la
diffrence du plus grand et du plus petit. Litration correspondante est :
u = a, v = b
tant que uv faire <u, v> = <max(u,v)-min(u,v), min(u,v)>
Affectation multiple qui, selon le principe prcdent, peut se traduire en :
static int pgcd(int a, int b) {
int u=a; int v=b;
while (u!=v) {
int uFutur=max(u,v)-min(u,v); int vFutur=min(u,v);
u=uFutur; v=vFutur;
}
return u;
}
ou encore, en introduisant une variable minuv pour viter de calculer deux fois min(u,v) :
static int pgcd(int a, int b) {
int u=a; int v=b;
while (u!=v) {
int minuv=min(u,v); int uFutur=max(u,v)-minuv;
u=uFutur; v=minuv;
}
return u;
}
6.5
6.5.1
Pour linvention, il ny a pas de voie royale. Cest souvent lexprience acquise et lanalogie avec
90
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
des problmes que lon a dj rsolus qui conduisent inventer litration. La mthode consiste
chercher une suite rcurrente qui conduise la solution, et ceci se fait par essai-erreur, en exhibant
des exemples de telles suites.
Pour lexactitude, il existe deux notions importantes qui sont linvariant de boucle et la fonction de
terminaison. Ces notions seront vues aux paragraphes suivants.
Nous allons illustrer la construction dune itration sur un exemple simple. Soit raliser une fonction nbChiffres gale au nombre de chiffres significatifs de lcriture dcimale dun entier strictement positif.
Par exemple : nbChiffres(1998) = 4
Comment peut sobtenir ce rsultat 4 ?
On peut considrer que un chiffre vient du 8 et trois chiffres viennent de 199. Une piste :
nbChiffres(1998) = nbChiffres(199) + 1 = 3+1 = 4
On peut gnraliser ceci en :
pour n < 10, nbChiffres(n) = 1
pour n 10, nbChiffres(n) = NbChiffres(n/10)+1
Remarque :
On aurait pu partir sur une mauvaise ide en considrant, ce qui nest pas faux, que le rsultat 4
sobtient en prenant 1 chiffre de poids fort, le 1, et 3 chiffres de poids faibles 998. On saperoit
que cest une mauvaise ide car on narrive pas exprimer simplement comment extraire ce 1
et ce 998 de 1998 avec les oprations dont on dispose.
ce stade nous avons des quations dont on pourrait tirer un algorithme rcursif vident. Mais
pour un algorithme itratif, il faut trouver une suite rcurrente qui conduise au rsultat.
Les quations nous suggrent de dcomposer le nombre en son chiffre de poids faible (8 dans
lexemple) et le reste constitu des chiffres voir (199 ici). Chaque chiffre extrait doit tre comptabilis pour fournir le rsultat cherch. Ces rflexions nous conduisent considrer la suite de paires
de nombres
<resteAVoiri, compteuri>
o resteAVoiri est le nombre form des chiffres non encore compts et compteuri est le nombre de
chiffres dj compts. Voici le scnario pour n=1998 :
resteAVoiri : 1998 199
compteuri : 0
1
19
2
1
3
0
4
Universit de Rennes 1
91
6.5.2
Invariant de boucle
Maintenant que nous avons dcouvert un algorithme itratif, comment sassurer formellement quil
est correct ? la mthode consiste trouver un invariant de boucle. Un invariant de boucle est une
proprit (un prdicat) fonction des variables de la boucle et qui doit :
+
nbChiffres(resteAVoir) = nbChiffres(n)
Cette proprit est vraie aprs les initialisations puisque aprs compteur=0 et resteAVoir=n on a bien videmment 0 + nbChiffres(n) = nbChiffres(n)
elle reste vraie chaque excution du corps de boucle puisque, pour resteAVoir >0 les
92
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
nbChiffres(resteAVoir/10)
+
= nbChiffres(n)
est-ce vrai ? oui puisque les mathmatiques nous disent que, sous rserve que resteAVoir >0,
nbChiffres(resteAVoir/10) = nbChiffres(resteAVoir)-1
et donc linvariant substitu redevient :
compteur
+
nbChiffres(resteAVoir) = nbChiffres(n)
Universit de Rennes 1
93
de compteur , et celle de resteAVoir ne dpend que de resteAVoir ). Dans des cas daffectations interdpendantes, il faut tenir compte de la squentialit de ces affectations et corriger les
expressions substitues en consquence.
Ainsi, grce linvariant mis en vidence, on vient de prouver que si la boucle termine, alors le
rsultat est correct. Mais cela ne suffit pas. Encore faut-il sassurer que la boucle termine.
6.5.3
Notion de complexit :
Il est vident que le nombre dexcutions du corps de boucle est toujours infrieur la fonction de
terminaison applique ltat initial. Ceci permet davoir une ide des performances en temps
dexcution dun algorithme itratif. Si on veut approcher au mieux le temps dexcution, il faut
exhiber une fonction de terminaison aussi petite que possible.
Dans le cas de la fonction nbChiffres on peut prendre la fonction suivante :
autreFonctionDeTerminaison = nbChiffres(resteAVoir )
Cest de toute vidence une fonction de terminaison, elle dcrot de 1 chaque itration car il est
bien connu que n/10 a un chiffre dcimal de moins que n (pour n>0).
Cette fonction de terminaison est bien meilleure que la prcdente. Elle montre que le nombre
dexcution du corps de boucle sera infrieur ou gal nbChiffres(n), cest--dire log10(n)+1.
On dit que la complexit (temporelle) de lalgorithme est O(log n).
Plus gnralement, on dit que la complexit est O(f(n)) si le temps dexcution est infrieur k.f(n),
o k est une constante arbitraire qui abstrait notamment les facteurs technologiques.
94
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
6.5.4
pgcd(u-v,v) = pgcd(a,b)
par la proprit (mathmatique) du pgcd : pour u>v, pgcd(u-v,v) = pgcd(u,v)
donc linvariant substitu est quivalent linvariant initial, vrai par hypothse.
Le raisonnement est analogue pour le cas u<v.
Pour fonction de terminaison on peut proposer |u+v|. Cest bien positif ou nul et cela dcrot strictement chaque itration.
6.6
On utilise parfois les itrations pour effectuer un traitement sur une squence de donnes introduites
depuis lextrieur au moment de lexcution, notamment des donnes frappes au clavier par lutilisateur du programme. Par exemple pour calculer la somme ou la moyenne dune suite de nombres.
Le programme lit un lment de la squence chaque tape de litration. Une convention doit tre
choisie pour dterminer la fin de la squence. On peut choisir dindiquer la fin par une valeur particulire, qui ne peut pas apparatre dans la squence, appele marque de fin. Par exemple pour une
squence de nombres positifs, la marque de fin pourra tre -1.
Le programme suivant calcule la somme dune squence dentiers frappe au clavier :
Universit de Rennes 1
95
class SommeSequenceEntree {
static final int marqueFin=-1;
Litration utilise deux variables dtat : somme , qui sert cumuler les valeurs lues, et nombreLu
qui reoit chaque tape un nouvel lment de la squence.
4
6
8
10
2
18
5
20
-1
25
On retrouve bien la mme traduction en boucle que pour une suite rcurrente entirement dfinie
par calcul, la seule diffrence est que le passage de nombreLui-1 nombreLui se fait au moyen de
linstruction de lecture :
nombreLu = Lecture.unEntier();
96
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
0
0
8
1
2
1
0
1
7
2
-1
2
si nombreLu i 1 = 0
si nombreLu i 1 0
Les variables de la boucle sont donc nbZeros et nombreLu . Linitialisation de nbZeros est 0 et
celle de nombreLu est faite par une premire lecture avant la boucle, comme cest souvent le cas
pour une boucle qui traite une squence de donnes lues. La condition darrt est bien videmment
nombreLu==marqueFin . Le programme peut scrire :
class NombreDeZeros {
static final int marqueFin=-1;
6.7
Il peut galement sagir de traiter n donnes introduites par lecture, par exemple faire la somme de
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
97
(int
i=0;
i<n;
i=i+1)
{ instructions
instructions
i=i+1;}
Remarque : la construction for ouvre un bloc qui permet davoir une variable int ilocale ce
bloc, qui na dexistence que pendant la dure dexcution de litration. Nous avons nomm i
cette variable, mais bien sr tout autre identificateur est acceptable.
On peut ainsi programmer les deux exemples prcdents :
Calcul de f n(a) :
u=a; for (int i=0; i<n; i=i+1) {u=f(u);}
Somme de 12 nombres lus au clavier :
somme=0;
for (int i=0; i<12; i=i+1) {
int nombreLu=Lecture.unEntier();
somme=somme+nombreLu;
}
98
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
Instructions dincrmentation et dcrmentation : i++, i-Le besoin dincrmenter (ajouter 1) ou de dcrmenter (retrancher 1) une variable tant trs frquent, Java, comme C et C++, possde une forme abrge pour raliser ces oprations :
i++; est peu prs1 quivalent i=i+1;
i--; est peu prs quivalent i=i-1;
Avec cette notation pour lincrmentation, la boucle prcdente scrit donc :
for (int i=0; i<12; i++) {...}
Tout le monde utilise ces formes abrges : elles sont pratiques et amliorent la lisibilit si on les
utilise sans abus, cest dire juste pour incrmenter ou dcrmenter une variable qui joue un rle
de compteur.
initialisation est une instruction quelconque destine initialiser ltat du contrle de litra-
tion,
condition est une expression boolenne qui conditionne la continuation de litration,
progression est une instruction quelconque destine faire progresser ltat du contrle de litration.
La smantique exacte est donne par la forme strictement quivalente utilisant un while :
{
}
initialisation;
while ( condition) { instructions
progression;}
On dconseille dabuser de cette forme gnrale. Elle nest ni plus courte ni plus puissante que la
forme while . Cest un simple chamboulement textuel des rubriques de litration.
1. Les diffrences sont que dans la forme i++ i nest value quune fois, ce qui peut conduire un rsultat diffrent si i
est une expression de dsignation complique, et en tant quexpression i++ vaut i avant incrmentation alors que
i=i+1 vaut la valeur de i aprs que lincrmentation soit faite.
Universit de Rennes 1
99
6.8
Pour la squence de donnes 3 56 7 9 8 -1, la suite des tats des variables de boucle sera :
i:
0
tatRecherchei : nonDcid
nombreLui
3
nonDcid
56
prsent
56
nonDcid
3
nonDcid
5
nonDcid
7
nonDcid
-1
absent
-1
100
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
Remarque : pour citer une valeur de type numr en Java, il faut gnralement prfixer lidentificateur de la valeur par le nom du type (Etat.nonDecide ) sauf pour lusage dans un switch o
on indique simplement lidentificateur de la valeur (case absent:). Le type de largument du
switch indique sans ambigut de quel type numr il sagit.
Dans le cas relativement frquent dune boucle de recherche, comme cest le cas ici, on peut utiliser une programmation ad-hoc qui utilise une variable boolenne initialise faux et qui est
affecte vrai quand ce que lon cherche est trouv.
La condition darrt de la boucle est alors les donnes sont toutes visites ou on a trouv. Pour
lexemple prcdent, en appelant present cette variable boolenne, cela donne :
class ChercheNombrePair {
public static void main(String[] arg) {
boolean present=false;
int nombreLu=Lecture.unEntier();
while (!present && nombreLu!=-1) {
if (nombreLu%2==0) {present=true;}
else {nombreLu=Lecture.unEntier();}
}
if (present) {
System.out.print("premier nombre pair = ");
System.out.println(nombreLu);
}
else /*!present*/{
System.out.println("aucun nombre pair");
}
}
}
Universit de Rennes 1
101
soit en Java :
!(A || B) = !A &&
!B
!(A && B) = !A ||
!B
102
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
QCM 6.1
Considrons les fonctions :
public static double p1(double x, int k){
// prrequis
: k>=0
// rsultat
: ???
double resul=1;
int i=0;
while(i<k){resul=resul*x; i++;}
return resul;
}
public static double p2(double x, int k){
// prrequis
: k>=0
// rsultat
: ???
if(k==0) {return 1;}
else {return x*p2(x,k-1);}
}
Universit de Rennes 1
103
QCM 6.2
Considrons la fonction :
static int log(int b,int n){
// prrequis : b>=2, n>0
// rsultat : la partie entire du logarithme base b de n
int resul=0; int nn=n;
while(nn!=1){
nn=nn/b; resul++;
}
return resul;
}
Rappel : la partie entire du logarithme base b de n est gal au nombre de chiffres significatifs de
lcriture en base b de n moins 1. On doit avoir par exemple log(10,3675)=3, car
10003675<10000.
1 - log(10,10000) rend 4.
2 - log(10,10000) rend 1.
3 - log(10,10000) ne termine pas.
4 - log(2,4) rend 2.
5 - log(2,32) rend 5.
6 - log(2,32) ne termine pas.
7 - log(10,3675) rend 3.
8 - log(10,3675) ne termine pas.
9 - Cette fonction est correcte (satisfait sa spcification).
10 - Cette fonction est incorrecte car ne termine pas toujours.
104
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
Exercices
objectif : le but des 3 exercices qui suivent est de
rsoudre un problme de manire rcursive en trouvant de bonnes quations,
rsoudre un problme de manire itrative en imaginant une suite rcurrente et en testant cette suite sur des exemples,
savoir prouver quune itration est correcte en exhibant un invariant et une fonction de
terminaison.
Dans les trois exercices qui suivent, on sintresse aux chiffres de lcriture dcimale dun nombre
entier. Par exemple lentier n=3827 est reprsent en dcimal par la suite de chiffres :
7 2 8 3
Ici, un chiffre dcimal sera simplement un entier compris entre 0 et 9.
Le premier chiffre est le chiffre de poids faible, ou chiffre de rang 0. Il sobtient comme reste de la
division du nombre par 10 : n%10 = 7
Les chiffres restants sont les chiffres du quotient du nombre par 10 : n/10=382.
Ceci nous permet dutiliser un nombre entier comme une suite de donnes, ses chiffres dcimaux.
Cest un petit subterfuge qui nous permet de nous passer provisoirement de structures de donnes
mieux adaptes telles que les tableaux, les chanes de caractres, les listes...
Exercice 6.1
tant donn un entier n>=0, on souhaite trouver le ime chiffre de son criture dcimale. Les chiffres sont numrots partir de 0 depuis les poids faibles. Si i est plus grand que le rang du plus fort
chiffre significatif, le rsultat sera 0.
Exemple : pour n=245
chiffre( 0,n) vaut 5,
chiffre( 1,n) vaut 4,
chiffre( 2,n) vaut 2,
chiffre( 3,n) vaut 0...
Rappels : le chiffre dcimal de rang 0 de n est le reste de la division de n par 10 (n modulo 10,
n%10 en java). les autres sont ceux du quotient entier de n par 10 (n/10 en Java).
Exemple : 245%10 vaut 5, 245/10 vaut 24
Rdiger la fonction chiffre de manire rcursive. On commencera par indiquer les quations
Universit de Rennes 1
105
Exercice 6.2
On considre la fonction SommeChiffres qui vaut la somme des chiffres de lcriture dcimale dun
entier positif ou nul.
exemple : SommeChiffres(582) = 2 + 8 + 5 = 15
cera par indiquer les quations qui justifient cette dfinition rcursive.
Rdiger cette fonction de manire itrative (fonction SommeChiffresIter ). On commencera par envisager une suite qui conduise la solution et on testera cette suite sur quelques scnarios.
Indiquer linvariant de boucle et une fonction de terminaison de la version itrative.
Exercice 6.3
tant donns deux entiers m et n, on souhaite dterminer si lcriture dcimale de m contient celle
de n. On suppose que m >= 0, n >= 0. On suppose galement que m < 231-1, de sorte quil peut tre
reprsent par une valeur de type int en Java.
Exemple : si m = 9413 et n = 41 alors contient( m,n) est vrai.
Pour raliser cette fonction, on a besoin dune fonction auxiliaire plus simple, termine( m,n)
qui vaut vrai si lcriture dcimale de n est gale la fin de celle de m et faux sinon. Exemples :
termine( 941,41) est vrai, termine( 9418,41) est faux.
Version rcursive :
Version itrative :
Refaire la mme chose en programmant les fonctions termine et contient de manire itrative.
Indiquer les invariants de boucles qui justifient lexactitude de ces itrations.
Exercice 6.4
objectif : savoir grer la malencontreuse squentialit des affectations dans un corps de boucle.
Rdiger une fonction qui calcule le pgcd de deux nombres a et b les strictement positifs en utilisant
les proprits suivantes :
avec a>b : si le reste de la division de a par b est nul, b est le pgcd, sinon le pgcd de a et b est gal
au pgcd de b et du reste. Exemple :
pgcd(310,21) = pgcd(21,12) = pgcd(12,9) = pgcd(9,3). Ici 3 divise 9, le pgcd est donc 3.
106
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
Exercice 6.5
objectif : savoir utiliser des identifications auxiliaires pour viter de calculer plusieurs fois la
mme chose.
On se propose de trouver une solution de lquation x = cos(x) entre 0 et /2.
Pour cela on peut calculer les termes de la suite :
x0 = 0, xi+1 = cos(xi) pour i>0
Cette suite converge vers la solution, comme le suggre le schma suivant :
x
cos(x)
Rdiger la fonction qui calcule cette solution epsilon prs, epsilon tant pass en paramtre.
Pour calculer le cosinus, on dispose de la fonction : double Math.cos(double x) .
Exercice 6.6
objectif : savoir transformer une itration pour la rendre plus efficace en utilisant des variables
auxiliaires contenant les valeurs des expressions coteuses calculer.
On peut calculer une valeur approche de l'aide de la srie :
n
lim 4
n
i=0
i
1
-------------- = 4 1 1--- + 1--- 1--- +
2i + 1
3 5 7
Les termes de la srie tant alternativement positifs et ngatifs, et strictement dcroissants en valeur
absolue, la srie converge par valeurs alternativement suprieures et infrieures, et le n-ime terme
est un majorant de l'erreur commise en arrtant le calcul au rang n.
Rdiger et tester une fonction calculPi calculant epsilon prs, epsilon tant donn en paramtre.
Premire version :
i
1
------------Dans cette version on calculera chaque terme de la srie comme lindique la formule
2i + 1
en calculant -1i au moyen de la fonction Math.pow(-1,i) dont le rsultat est un nombre rel.
Seconde version :
Dans cette version, on cherchera viter les calculs de -1i (alternance des signes) et de 2i+1 en les
remplaant par des oprations juges moins coteuses.
Universit de Rennes 1
107
Exercice 6.7
Exercice 6.8
objectif : savoir transformer une rcurrence du second ordre en rcurrence du premier ordre.
La suite de Fibonacci est dfinie par la relation suivante :
fibo(0) = 0
fibo(1) = 1
fibo(n) = fibo(n-2) + fibo(n-1) pour n > 1
On se propose de rdiger une fonction int
suite.
fibo(int
qui
n) calcule le nime terme de cette
La dfinition utilise une rcurrence du second ordre (le rang n dpend des rangs n-1 et n-2). Nous
savons calculer par une itration les termes dune rcurrence du premier ordre. Comment faire pour
le second ordre (ou tout ordre suprieur) ?
Principe gnral : on se ramne une rcurrence du premier ordre, mais vectorielle. Ici cela
devient :
fiboNMoins1 i
fiboN i
fiboN i 1
fiboNMoins1 i 1 + fibo N i 1
108
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
objectif : Les 5 exercices qui suivent concernent des itrations sur entres de donnes. Le but
principal est de placer convenablement les instructions de lecture.
Exercice 6.9
Rdiger un programme qui lit une suite de nombres entiers positifs, termine par -1 et affiche la
moyenne de ces nombres.
Exemple : 7 3 0 4 -1
la moyenne est 3.5
Exercice 6.10
On entre au clavier une suite non vide dentiers positifs termine par la marque -1. Rdiger un programme qui lit ces nombres et calcule le maximum de la suite.
Exemple : 7 3 0 4 1 8 23 0 9 -1
le maximum est 23
Exercice 6.11
On entre au clavier une suite non vide dentiers positifs termine par la marque -1. Rdiger un programme qui lit ces nombres et calcule la longueur de la plus longue sous-suite constante.
Exemple : 7 5 5 4 1 1 1 1 8 8 4 -1
longueur de la plus longue sous-suite constante = 4 (suite de quatre 1).
Exercice 6.12
Nombre de "le"
Rdiger un programme qui affiche le nombre de paires de caractres successifs "le" dans un texte
lu au clavier et termin par un point.
Exercice 6.13
Nombre de mots
Rdiger un programme qui dtermine et affiche le nombre de mots contenus dans une phrase termine par un point. On considre que le caractre sparateur de mots est le caractre espace.
Universit de Rennes 1
109
Aide 6.1
Version itrative :
Voici un exemple de scnario, pour la recherche du chiffre de rang 3 dans 24593 :
ii
nn
24593
2459
245
24
Aide 6.2
Version itrative :
Lide consiste cumuler les chiffres de n en commenant par les poids faibles.
Exemple pour n=285 :
110
somme
13
15
resteAVoir
285
28
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
Aide 6.3
si n==0, termine(m,n)=vrai
si n>0 et n%10m%10, termine(m,n)=faux
si n>0 et n%10m%10, termine(m,n)= termine(m/10,n/10)
Version rcursive de contient :
941
94
nn
41
Le rsultat vrai est atteint quand nn=0, ce qui signifie que lon a compar avec succs tous les chiffres de n avec ceux de m.
Universit de Rennes 1
111
9481 948
nn
41
Le rsultat faux est atteint quand les chiffres de poids faible de nn et mm sont diffrents.
Version itrative de contient :
Le principe consiste tester si les chiffres de n se rencontrent quelque part lintrieur des chiffres
de m.
Exemple de scnario pour lequel contient(m,n)=vrai :
mm
9413
941
41
9413
941
94
43
43
43
Aide 6.4
Les proprits indiques nous suggrent une suite de deux composantes, aa et bb, avec aabb. Il
faut se mfier que aa soit bien suprieur bb initialement. Pour cela il doit tre initialis avec la
plus grande valeur parmi a et b, et bb doit tre initialise avec lautre valeur. Le scnario suivant
illustre le calcule du pgcd de 21 et 390 :
aa
390
21
12
bb
21
12
Aide 6.9
La moyenne est la somme divise par le nombre de nombres somms. On peut difficilement calculer la moyenne de faon itrative. Il faut calculer la somme et le nombre de nombres, puis aprs
litration calculer la moyenne. Exemple :
nombreLu : 7
-1
somme :
11
11
14
nbNombres : 0
112
Module A.P.I
Universit de Rennes 1
Rcursivit et itration
Aide 6.10
En plus de la suite des valeurs lues, il faut avoir le maximum des donne lues depuis le dbut de la
squence. Le rsultat est bien videmment ce maximum une fois lue toute la squence.
Exemple :
nombreLu : 2
max :
Aide 6.11
-1
du nombre lu : nombreLu,
de la valeur de la sous-suite constante courante : valSousSuite,
de la longueur courante de la sous-suite constante courante : longueurSousSuite,
de la longueur maximum des sous-suites rencontres : longueurMax.
Voici un exemple de scnario :
nombreLu :
7 5 5 4 1 1 1 1 8 8 4 -1
valSousSuite :
7 5 5 4 1 1 1 1 8 8 4
longueurSousSuite :
1 1 2 1 1 2 3 4 1 2 1
longueurMax :
1 1 2 2 2 2 3 4 4 4 4
Aide 6.12
Nombre de "le"
Lide gnrale est davoir en permanence deux caractres successifs du texte, car1 et car2 et de les
comparer avec 'l' suivi de 'e' :
car1
car2
nombreDeLe
Remarque : Il faut initialiser car1 et car2 par deux lectures avant litration.
Universit de Rennes 1
113
Aide 6.13
Nombre de mots
Quelques prcisions : nous acceptons les textes de 0 caractre, et dans ce cas le nombre de mots et
0. Les mots peuvent tre spars par un nombre quelconque despaces.
On peut partir du principe que ce qui caractrise un mot est la fin du mot. Une fin de mot est
caractrise une paire de caractres dont le premier car1 nest pas un espace et le second car2 est
un espace :
le
corbeau
1
et le
2
renard
4
4 mots
Il ne faut pas oublier le cas o le dernier mot serait termin par le point final :
le
corbeau
1
et le
2
renard.
4
4 mots galement
Il y a un mot de plus la fin si car1 nest pas un espace aprs avoir lu le point final.
114
Module A.P.I
Universit de Rennes 1
CHAPITRE 7
On veut reprsenter les cartes dun jeu de 32 cartes. Il faut notamment reprsenter la force de
chaque carte, sept, huit, neuf, dix, valet, dame, roi, as, ainsi que sa couleur, trfle, carreau,
cur, pique. On peut videmment imaginer de reprsenter ces valeurs par des entiers, mais les
algorithmes deviennent alors totalement illisibles.
On veut reprsenter les clients dune socit de vente. Aucun des types prdfinis nest adapt
reprsenter par un seul objet, un nom, une adresse et un compte.
Dans chacun de ces cas, il va falloir inventer un nouveau type de donnes. Dans ce chapitre nous
allons tudier les plus simples des types programms : les types numrs et les types structures.
7.1
Type numr
objectif : approfondir lusage des types numrs.
Comme nous lavons dj vu, un type numr est dfini par lnumration de ses valeurs. Chaque
valeur est note au moyen dun identificateur. Par exemple, pour la couleur et la force dune carte
on peut dfinir en Java les types numrs :
enum CouleurDeCarte {trefle, carreau, coeur, pique}
enum ForceDeCarte {sept, huit, neuf, dix, valet, dame, roi, as}
Un type numr offre peu de proprits : dans les cas usuels, on na besoin que du test dgalit.
Dans certains cas, on peut vouloir une relation dordre, par exemple pour la force dune carte, on
peut souhaiter lordre sept<huit<neuf<dix<valet <dame<roi<as.
La relation dordre en Java est dfinie par lordre dnumration des identificateurs de valeurs. La
Universit de Rennes 1
115
Type numr
comparaison se fait au moyen de la fonction compareTo . La syntaxe dutilisation de cette fonction est particulire : a et b tant des expressions dun mme type numr,
a.compareTo( b)
rend en rsultat un entier <0 si a est infrieur b, 0 si a est gal b et >0 si a est suprieur b.
Exemple : la fonction suivante indique si une couleur est rouge (carreau ou cur) :
static boolean estRouge(CouleurDeCarte c) {
// rsultat
: indique si c est rouge
return c==CouleurDeCarte.carreau || c==CouleurDeCarte.coeur;
}
On aurait pu galement lcrire, en utilisant compareTo :
static boolean estRouge(CouleurDeCarte c) {
// rsultat
: indique si c est rouge
return
c.compareTo(CouleurDeCarte.carreau)==0
|| c.compareTo(CouleurDeCarte.coeur)==0;
}
Type numr et entres-sorties
Les types numrs sont utiliss pour amliorer la lisibilit des programmes. Il peuvent galement
servir communiquer avec lextrieur, au moyen de lectures et dcritures. Les langages de programmation offrent rarement la possibilit de raliser des oprations dentres sorties en clair de
valeurs dun type numr. En revanche, Java le permet. La forme en clair des valeurs dun type
numr sont simplement les chanes de caractres de leurs identificateurs.
Il existe pour chaque type numr deux fonctions de conversion :
Module A.P.I
Universit de Rennes 1
7.2
Type structure
objectif : apprendre caractriser des donnes complexes laide de composantes plus simples.
Un type structure permet de reprsenter des donnes ayant plusieurs caractristiques appartenant
chacune un domaine de valeurs, donc dun certain type. Cela correspond peu prs lide
mathmatique du produit cartsien de plusieurs domaines. Comme exemple on peut considrer :
Un point dans un plan : ses caractristiques sont labscisse et lordonne. Le type de labscisse
7.2.1
Universit de Rennes 1
117
Type structure
Notion de constructeur
Lorsquon cre un objet de type structure, on a frquemment besoin de lui donner une valeur. On
verra plus loin quon peut modifier par affectation les champs dune structure, mais il est prfrable
de prvoir linitialisation globale de tous les champs ds la cration. Cela donne dans tous les cas
une meilleure lisibilit et cest mme ncessaire pour des structures dont les membres seraient des
constantes, cest--dire quon ne peut plus modifier une fois lobjet cr.
En Java, cette initialisation se fait au moyen dun constructeur que lon dfinit dans le texte de la
classe. Un constructeur se prsente un peu comme une procdure. Il doit imprativement porter le
mme nom que la classe. Il a des paramtres, mais ne rend aucun rsultat : son rle est dinitialiser
lobjet au moment de sa cration. Dans le cas dune structure, il est bon de programmer un constructeur qui a comme paramtres les valeurs initiales de tous les champs de la structure (on appelle
parfois cela le constructeur trivial). En reprenant les exemples prcdents, cela donne :
class Point {
public double x; public double y;
public Point(double sonX, double sonY) {x=sonX; y=sonY;}
}
class CarteAJouer {
public ForceDeCarte force; public CouleurDeCarte couleur;
public CarteAJouer(ForceDeCarte f, CouleurDeCarte c) {
force=f; couleur=c;
}
}
class Personne {
public String nom; public int age; public Sexe sonSexe;
public Personne(String n, int a, Sexe s) {
nom=n; age=a; sexe=s;
}
}
En Java, la cration dune structure se fait au moyen de lopration new suivie du constructeur dot
de paramtres effectifs. Avec ces constructeurs, on pourra crer des structures initialises en utilisant les formes suivantes :
Point origine = new Point(0,0); Point p = new Point(1.0,12.45);
CarteAjouer mistigri =
new CarteAJouer(ForceDeCarte.valet, CouleurDeCarte.trefle);
Personne toto = new Personne("toto",14,Sexe.masculin);
Les dclarations prcdentes supposent les dfinitions suivantes de types numrs :
enum CouleurDeCarte {trefle, carreau, coeur, pique}
enum ForceDeCarte {sept, huit, neuf, dix, valet, dame, roi, as}
enum Sexe {masculin, feminin}
118
Module A.P.I
Universit de Rennes 1
7.2.2
un verre
un autre verre
De ce point de vue, la notion dobjet soppose la notion de valeur. Une valeur est un lment
dun ensemble, au sens mathmatique. Par exemple 12 est une valeur, cest un lment de lensemble des entiers. 12 na jamais t cr (du moins pas au sens de la fabrication dun objet physique). Il na pas didentit : son existence est une existence mathmatique, elle ne se situe ni dans
le temps, ni dans lespace. 12 nest pas un objet.
Universit de Rennes 1
119
Type structure
de mots de mmoire qui contiennent les divers composants de lobjet. Chaque mot de la mmoire
de lordinateur est dsign par un numro quon appelle son adresse. La rfrence un objet est
simplement ladresse o est rang lobjet en mmoire.
rfrence
2568
adresse mmoire
2567
2568
2569
2570
valet
trefle
force
objet de type
couleur CarteAJouer
rfrence
3822
aprs
force : valet
couleur : trefle
espace des objets
De faon concrte et proche de la ralisation en machine, de la place mmoire est rserve pour le
nouvel objet, dans lespace des objets, le constructeur est excut pour initialiser lobjet et
ladresse mmoire de lobjet, qui constitue la rfrence lobjet, est rendue en rsultat (3822 dans
lexemple de la figure).
La forme gnrale de la cration est :
new
nomDeLaClasse(paramtres du constructeur)
120
Module A.P.I
Universit de Rennes 1
Par exemple :
CarteAJouer mistigri; variable de type rfrence un objet de type CarteAJouer .
Ceci est une dclaration sans initialisation explicite. En Java, une telle variable est initialise
null, rfrence qui ne dsigne rien.
mistigri
null
On peut ensuite affecter cette variable, par exemple pour capter la rfrence un objet cr :
mistigri =
new CarteAJouer(ForceDeCarte.valet,CouleurDeCarte.trefle);
On peut galement, comme pour toute dclaration de variable, linitialiser lendroit de sa
dclaration :
CarteAJouer mistigri =
new CarteAJouer(ForceDeCarte.valet,CouleurDeCarte.trefle);
mistigri
force : valet
couleur : trefle
espace des objets
On peut galement dclarer des constantes de type rfrence, au moyen de lattribut final :
final T nom = expression;
Par exemple :
final CarteAJouer mistigri = new CarteAJouer(valet,trefle);
Dans ce cas on est sr que lidentificateur dsignera toujours le mme objet.
On peut aussi, comme avec tout autre type, avoir des paramtres de type rfrence et des rsultats
de fonction de type rfrence. Nous en aurons quelques exemples dans le paragraphe suivant.
7.2.3
Slection de champ
Les champs dune structure sont accessibles au moyen dune opration appele slection de champ.
Etant donne une rfrence objet obj qui possde un champ de nom c, lexpression :
obj.c
dsigne le champ c de obj.
En tant quexpression, elle vaut ce que vaut le champ : mistigri.force vaut valet .
Champs variables - champs constants
Un champ dclar sans aucun autre vocable peut sutiliser comme une variable que lon peut
affecter :
mistigri.couleur=pique; modifie la couleur de lobjet dsign par mistigri .
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
121
Type structure
Si on dsire quun champ ne soit pas modifiable, il suffit de le dclarer avec le vocable final .
Le champ ainsi dclar se comporte comme une constante. Il reoit sa valeur par le constructeur, au moment de la cration de la structure, et cette valeur est dfinitive :
class CarteAJouer {
public final ForceDeCarte force;
public final
CouleurDeCarte couleur;
public CarteAJouer(ForceDeCarte f, CouleurDeCarte c) {
force=f; couleur=c;
}
}
Avec cette dfinition de CarteAjouer , la force et la couleur dune carte ne sont pas modifiables. avec
mistigri =
new CarteAJouer(ForceDeCarte.valet,CouleurDeCarte.trefle);
la carte dsigne par mistigri est tout jamais le valet de trfle.
7.2.4
force : valet
couleur : trefle
carte1
force : valet
couleur : trefle
carte2
Il faut bien remarquer quune telle comparaison rend vrai si et seulement si les deux rfrences sont
les mmes, cest--dire dsignent le mme objet. Elle rend faux si les rfrences dsignent des
objets diffrents, mme sils ont mme valeur. Par exemple, avec la situation illustre ci-dessus :
mistigri==carte1 vaut true
mistigri==carte2 vaut false
bien que les objets dsigns par mistigri et carte2 aient la mme valeur. Loprateur == sur
les objets ne compare pas les valeurs mais seulement les rfrences. Si on veut comparer les
valeurs, il faut le programmer, le langage ne loffre pas.
Voici comment programmer la comparaison dgalit de valeur pour le type CarteAJouer , en
considrant que deux cartes sont gales si et seulement si elles ont mme force et mme couleur.
Cette comparaison, frquente pour des structures, sappelle une comparaison champ par champ.
Une convention trs rpandue est dappeler equals la fonction de comparaison dgalit de valeur
entre objets.
122
Module A.P.I
Universit de Rennes 1
7.2.5
7.2.6
Exemple rcapitulatif
Le programme suivant gre un jeu de bataille simplifi entre deux joueurs. chaque coup chaque
joueur fournit la force et la couleur de sa carte, en clair au clavier. Si une carte est gagnante, le
joueur correspondant marque un point supplmentaire. En cas dgalit des cartes, aucun joueur ne
marque de point. La partie dure 5 coups et le score final est affich.
class JeuDeBataille {
static CarteAJouer laGagnante(CarteAJouer c1,CarteAJouer c2) {
// rsultat
: la plus forte des cartes c1 et c2
// null si les cartes sont de forces gales
if (c1.force.compareTo(c2.force)>0) {return c1;}
else if (c1.force.compareTo(c2.force)<0) {return c2;}
else /* forces gales, on compare les couleurs */ {
if (c1.couleur.compareTo(c2.couleur)>0) {return c1;}
else if (c1.couleur.compareTo(c2.couleur)<0) {return c2;}
else /* carte gales */ {return null;}
}
}
//...
Universit de Rennes 1
123
Type structure
Remarque : dans ce programme, deux nouvelles cartes sont cres par linstruction new chaque
tape du jeu. Cela peut sembler coteux en utilisation de la mmoire. Il ne faut pas trop se tracasser
de cela car le langage utilis, Java, dispose dun mcanisme de gestion de mmoire qui rcupre la
mmoire occupe par les objets qui ne servent plus, ce qui est le cas des anciennes cartes lorsquon
en cre des nouvelles chaque itration. Ce mcanisme de rcupration de mmoire sappelle un
ramasse-miettes, ou encore un garbage collector en anglais.
124
Module A.P.I
Universit de Rennes 1
QCM 7.1
On souhaite dfinir une structure qui regroupe les caractristiques de chaque employ dune entreprise. Ces caractristiques sont le nom, le prnom, et la nature du poste occup. Les nature de
poste sont technique, administratif ou commercial.
La nature du poste est une valeur du type numr ainsi dfini :
enum NatureDePoste{technique, administratif, commercial}
3 - Pour crer un objet de type Employe et capter sa rfrence par lidentificateur durand , il
faut crire :
Employe durand =
new Employe("Durand","Alfred",NatureDePoste.commercial);
4 - Pour crer un objet de type Employe et capter sa rfrence par lidentificateur durand , il
faut crire :
Employe("Durand","Alfred",NatureDePoste.commercial) durand;
8 - Avec la (bonne) dfinition de la classe Employe , on peut modifier la nature du poste dun
employ. Pour attribuer durand la nature de poste administratif, il suffit dexcuter :
durand.emploi=NatureDePoste.administratif;
Universit de Rennes 1
125
Type structure
QCM 7.2
La structure suivante dcrit les caractristiques dun produit vendu dans un magasin :
class DescriptifProduit{ // descriptif dun produit
public String nomProduit;
public String nomFournisseur;
public double prixDAchat;
public double tauxTVA;
public double margeBeneficiaire;
public DescriptifProduit(String nP,String nF,
double pA,double tva,double m){
}
}
3 - Pour crer le descriptif dune lessive et capter sa rfrence par la variable lessiveMachin
on peut crire :
DescriptifProduit
("lessiveMachin","machin",12,19.6,0.2)
lessiveMachin;
4 - Pour crer le descriptif dune lessive et capter sa rfrence par la variable lessiveMachin
on peut crire :
DescriptifProduit lessiveMachin =
new DescriptifProduit("lessiveMachin","machin",12,19.6,0.2);
nomFournisseur(lessiveMachin)
lessiveMachin.nomFournisseur
7 - la fonction suivante :
static double prixDeVente(DescriptifProduit d){
double prixHorsTaxe = prixDAchat*(1+margeBeneficiaire);
return prixHorsTaxe*(1+tauxTVA);
}
est syntaxiquement correcte et rend en rsultat le prix de vente du produit dcrit par d.
8 - la fonction suivante :
static double prixDeVente(DescriptifProduit d){
double prixHorsTaxe = d.prixDAchat*(1+d.margeBeneficiaire);
return prixHorsTaxe*(1+d.tauxTVA);
}
est syntaxiquement correcte et rend en rsultat le prix de vente du produit dcrit par d.
126
Module A.P.I
Universit de Rennes 1
Exercice 7.1
objectif : savoir utiliser les champs dune structure et crer un rsultat de type structure.
Un point du plan peut tre reprsent par ses coordonnes cartsiennes (x, y) dans un repre arbitraire. Dfinir une telle structure Point et rdiger les fonctions suivantes :
a
milieu
distance
b
surfaceRectangle
b
Exercice 7.2
objectif : savoir utiliser les champs dune structure, crer un rsultat de type structure, dfinir
une constante de type structure.
Un nombre complexe peut tre reprsent au moyen dune structure deux champs, x (partie
relle) et y (partie imaginaire).
Dfinir cette reprsentation au moyen dune classe Complexe .
Universit de Rennes 1
127
Type structure
Exercice 7.3
nom : seize
prenom
: louis
adresse
: versailles
pere :
nom : antoinette
mere :
prenom
: marie
adresse
: versailles
pere :
mere :
nom : seize
prenom
: louisette
adresse
: versailles
pere :
mere :
nom : bonaparte
prenom
: napolon
adresse
: bastia
pere :
nom : beauharnais
mere :
prenom
: josphine
adresse
: bastia
pere :
mere :
nom : durand
prenom
: alfred
adresse
: labas
pere :
mere :
nom : dupont
prenom
: jules
adresse
: ici
pere :
mere :
nom : martin
prenom
: raimond
adresse
: ailleurs
pere :
mere :
128
Module A.P.I
Universit de Rennes 1
frres, teste si louis seize est un grand-pre de raimond martin et teste si napolon bonaparte est un grand-pre de jules dupont,
affiche ladresse de napolon bonaparte,
modifie ladresse du grand-pre paternel de raimond martin et affiche ladresse de napolon
bonaparte (prvoir le rsultat de cet affichage).
Universit de Rennes 1
129
Type structure
Aide 7.1
Aide 7.2
Les nombres complexes seront reprsents par une structure Complexe 2 champs, x et y, dote
dun constructeur usuel. Une telle structure reprsente le nombre complexe x+y.i.
Les fonctions add, mul et toString seront rdiges dans une classe TestStructureComplexe dont le main est le programme de test. Voici sa forme gnrale :
import es.*;
class TestStructureComplexe {
static Complexe add(Complexe z1, Complexe z2) {
// rsultat
: somme de z1 et z2
...
}
static Complexe mul(Complexe z1, Complexe z2) {
// rsultat
: produit de z1 et z2
...
}
static String toString(Complexe z){
// rsultat
: la chane de caractre qui figure z en clair
...
}
130
Module A.P.I
Universit de Rennes 1
Les fonctions add et mul ncessitent la cration du rsultat. Ces cration utilisent le constructeur,
en appliquant les formules classiques de laddition et de la multiplication des nombres complexes :
pour laddition : (x1+y1.i) +(x2+y2.i) = x1+x2 + (y1+y2).i
pour la multiplication : (x1+y1.i)(x2+y2.i) = x1.x2 - y1.y2 +(x1.y2 + y1.x2).i
La fonction daddition par exemple est de la forme :
static Complexe add(Complexe z1, Complexe z2) {
// rsultat
: somme de z1 et z2
...
}
Ne pas oublier que les composantes de z1, par exemple, sobtiennent par z1.x et z1.y.
Pour la fonction toString , il est conseill dans un premier temps den faire une version simple
qui rend en rsultat une chane de caractres de la forme unique x+y*i, quelques soient x et y, nuls
ou non, valant 1 ou non... Cette fonction est importante pour visualiser le rsultat des tests.
Dans la procdure principale de test, nous devons utiliser le nombre complexe 1, qui nest autre
que 1+0.i. Nous devons dfinir pour cela la constante complexe UN :
final Complexe UN = new Complexe(1,0);
Aide 7.3
class Personne {
public String nom;
public String prenom;
public String adresse;
public Personne pere;
public Personne mere;
public Personne(String n, String p, String a,
Personne sonPere, Personne saMere){
// personne de nom n, prenom p, adresse a,
// pre sonPere et mre saMere
nom=n; prenom=p; adresse=a; pere=sonPere; mere=saMere;
}
Les champs pere et mere sont dclar de type Personne , ce qui, en Java, en fait des rfrences
des objets de type Personne .
Le constructeur pour des personnes sans pre ni mre initialise les champs pere et mere null,
rfrence qui ne dsigne rien.
Universit de Rennes 1
131
Type structure
132
Module A.P.I
Universit de Rennes 1
Chanes de caractres
CHAPITRE 8
Chanes de caractres
objectif : connatre les principales fonctionnalits offertes par les chanes de caractres :
comparer, rechercher, construire des chanes de caractres, accder aux caractres dune chane.
8.1
titreDeFable
"La Cigale et la Fourmi"
espace des objets
Universit de Rennes 1
133
Le fait que les chanes soient des objets, donc dsigns par rfrence, oblige prendre certaines prcautions pour comparer des chanes. Loprateur de comparaison == compare les rfrences et
non les valeurs. Dans lexemple suivant, titreDeFable et ch2 dsignent des chanes de mme
valeur "La Cigale
et la Fourmi"
. Cependant titreDeFable==ch2 est faux, car
titreDeFable et ch2 dsignent des objets diffrents. Pour comparer la valeur de deux chanes,
Java fournit la fonction .equals() . Ici titreDeFable.equals(ch2) rend vrai.
Ce point est une source frquente derreur, car titreDeFable==ch2 nest pas une faute de
syntaxe, cest officiellement la comparaison des rfrences (qui est utile, mais dont lutilit est
extrmement rare dans le cas de chanes de caractres1).
titreDeFable
ch1
ch2
Les chane de caractres de type String sont des objets non modifiables. Une fois cre, un objet
de type String aura toujours la mme valeur. Ceci nempche pas, bien videmment, davoir des
variables de type String , mais ce qui varie cest leur valeur qui est une rfrence. Lorsquon
affect un identificateur de type String , on lui fait simplement dsigner une autre chane :
String titre ="la Cigale et la Fourmi";
titre
1. Ce qui est critiquable ici ce nest pas la notion de rfrence qui est insparable de la notion dobjet, mais cest le choix
que les chanes de type String soient des objets, alors que de toute vidence on voudrait que ce soient des valeurs.
134
Module A.P.I
Universit de Rennes 1
Chanes de caractres
8.2
Longueur :
s.length() : nombre de caractres de la chane s. Cest une valeur entire de type int.
Par exemple "coucou".length() vaut 6, "".length() vaut 0,
et avec String ch="coucou"; ch.length() vaut 6.
Le ime caractre :
s.charAt( i) : rend en rsultat la valeur du ime caractre de s. Les caractres sont numrots
partir de 0 en commenant par la gauche. i est une expression entire dont la valeur doit tre comprise entre 0 et s.length()-1 (bornes incluses).
Exemples :
"La Cigale et la Fourmi".charAt(0) vaut 'L'
"La Cigale et la Fourmi".charAt(4) vaut 'i'
avec String ch="coucou"; ch.charAt(2) vaut 'u'
Universit de Rennes 1
135
Sous-chane
s.substing( i,j) : rend en rsultat la sous-chane de s comprise entre lindice i (compris) et
lindice j (exclu). j doit tre suprieur ou gal i.
Exemple :
"bonjour".substring(2,6) vaut "njou"
"bonjour".substring(5,5) vaut "" (chane vide)
Position dun caractre dans une chane
s.indexOf( c) : rend en rsultat si c apparat dans s, lindice de sa premire occurrence, et rend 1 si c napparat pas dans s.
Exemples :
"bonjour".indexOf('j') vaut 3
"bonjour".indexOf('d') vaut -1
Position dune sous-chane dans une chane
s1.indexOf( s2) : rend en rsultat si s2 apparat dans s1, lindice de sa premire occurrence, et
rend -1 si s2 napparat pas dans s1.
s1.indexOf( s2,i) : rend en rsultat si s2 apparat dans s1 partir de la position i, lindice de sa
premire occurrence partir de la position i, et rend -1 si s2 napparat pas dans s1 partir de la
position i.
Exemples :
"bonjour".indexOf("jo") vaut 3
"bonjour bonsoir".indexOf("bon") vaut 0 (position du "bon" de "bonjour" )
"bonjour bonsoir".indexOf("bon",2) vaut 8 (position du "bon" de "bonsoir" )
Conversions en chanes de caractres
Les chanes de caractres servent essentiellement communiquer en clair de linformation avec
des utilisateurs humains. Cest pourquoi tous les types de base possdent une conversion standard
en chane de caractres. Par exemple, la conversion de lentier 12 est "12", celle du rel 3.14 est
"3.14" , celle du boolen false est "false" et celle du caractre 'z' est "z".
Loprateur de concatnation, not +, admet comme oprande nimporte quel type de base, condition quun de ses deux arguments soit explicitement une chane. Dans ce cas, le compilateur ralise implicitement la conversion standard de cet oprande en chane avant de faire la concatnation.
Exemples :
"toto a " + 12 + " ans"
signifie la mme chose que "toto
cest--dire "toto a 12 ans" .
a " + "12"
+ " ans"
Ceci est trs utilis pour afficher joliment un rsultat. Par exemple, ageDeToto tant un entier,
plutt que de programmer :
136
Module A.P.I
Universit de Rennes 1
Chanes de caractres
System.out.print("toto a ");
System.out.print(ageDeToto);
System.out.println(" ans");
Il est plus concis de programmer :
System.out.println("toto a " + ageDeToto + " ans");
8.3
Universit de Rennes 1
137
class TestTexteMajuscule{
static final String
minuscules = "abcdefghijklmnopqrstuvwxyz";
static final String
majuscules = "AABCCDEEEEFGHIIJKLMNOOPQRSTUUUUVWXYZ";
static char majuscule(char c){
// rsultat
: la majuscule correspondant c
// (le rsultat est c si c nest pas une lettre minuscule)
int k=minuscules.indexOf(c);
if(k==-1){return c;}
else{return majuscules.charAt(k);}
}
static String texteMajuscule(String txt){
// rsultat
: texte rsultant de txt par remplacement de toute
// lettre par la majuscule correspondante
String resul="";
for(int i=0;i<txt.length(); i++){
resul=resul+majuscule(txt.charAt(i));
}
return resul;
}
138
Module A.P.I
Universit de Rennes 1
Chanes de caractres
QCM 8.1
On considre les dclaration et crations suivantes de chanes de caractres :
String
String
String
String
String
s1
s2
s3
s4
s5
=
=
=
=
=
"tant va la";
"cruche leau";
s1+s2;
s1+" "+s2;
s1+""+s2;
11 - Linstruction s=s.substring(0,2)+'x'+s.substring(3,4);
"abxd" et la fait dsigner par s.
12 - s=s.substring(0,2)+'x'+s.substring(3,4);
13 - s=s.substring(0,2)+'x'+s.substring(3,4);
tion.
cre la chane
Universit de Rennes 1
139
Exercice 8.1
int nombreDe(char c,
String
s)
Exercice 8.2
objectif : savoir comparer les caractres de deux chanes, inventer une fonction auxiliaire, se
mfier des dpassement dindices au sein dune chane.
Sans utiliser la fonction indexOf , rdiger et tester la fonction :
static
int indiceDeSousChaine(String
s1, String
s2)
qui, si s1 est une sous-chane de s2, rend en rsultat lindice de la premire occurrence de s1 dans
s2, sinon -1.
Exemples :
indiceDeSousChaine("toto","0+0 = la tte toto") = 16
indiceDeSousChaine("zozo","0+0 = la tte toto") = -1
indiceDeSousChaine("0 =","0+0 = la tte toto") = 2
indiceDeSousChaine("","0+0 = la tte toto") = 0
Remarque : penser rdiger une fonction auxiliaire.
Exercice 8.3
objectif : savoir utiliser une chane auxiliaire comme rservoir dinformation (ici, la suite des
chiffres "0123456789")
Le but de cet exercice est de raliser la conversion traditionnelle dune chane caractres compose
uniquement de chiffre dcimaux en lentier reprsent en dcimal par cette chane. rdiger et tester
la fonction :
static int interpretationDecimale(String s)
// prrequis
: s ne contient que des chiffres dcimaux
// et linterprtation dcimale de s est < 2**31
// rsultat
: linterprtation dcimale de s
Le prrequis interprtation dcimale de s < 231 sert garantir que le rsultat soit reprsentable
sur un int.
Exemple :
interpretationDecimale("1703") vaut 1703
On conviendra que linterprtation dcimale de la chane vide (aucun chiffres) vaut 0 (convention
raisonnable et pratique).
140
Module A.P.I
Universit de Rennes 1
Chanes de caractres
Aide 8.1
Aide 8.2
Lide gnrale consiste chercher pour chaque position i de s2, la chane s1 est prsente partir
de cette position. Cela fait apparatre le besoin dune fonction auxiliaire :
static boolean occurrence(int i, String s1, String s2)
qui indique si s1 est prsente en position i dans s2.
Cette fonction compare les caractres de s1 aux caractres de s2 partir de la position i. Ceci est
ralis par une itration qui utilise k comme indice de caractre dans s1 et i+k comme indice de
caractre dans s2. La boucle sarrte la premire diffrence rencontre. En sortie de boucle, s1
est dans s2 si et seulement si tous les caractres de s1 ont t compars avec succs, cest--dire si
k est gal la longueur de s1.
Attention : un indice de caractre dans une chane doit tre positif ou nul et strictement infrieurs
la longueur de la chane. Se mfier des cas o partir de la position i les caractres de s2 sont en
nombre infrieur la taille de s1 :
k
i
s1
s2
Aide 8.3
Universit de Rennes 1
141
142
Module A.P.I
Universit de Rennes 1
Tableaux
Tableaux
CHAPITRE 9
objectif : savoir utiliser les tableaux pour organiser des collections de donnes
9.1
0
1
2
3
4
3.97
1.23
0.56
1.23
7.90
Si le tableau sappelle T, lexpression T[2] dsigne la donne dindice 2 qui vaut 0.56.
Lusage dun tableau est justifi dans les cas suivants :
Lorsque la quantit de donnes est important : il nest pas question de rdiger un programme qui
dfinisse autant de noms individuels pour manipuler ces donnes.
Lorsquon doit dterminer par calcul quels lments de la collection sont utiliss.
Exemple 1
Un morceau de musique numrique est constitu dchantillons damplitude du signal sonore. Il
faut environ 20 000 chantillons par seconde denregistrement. Chaque chantillon tant un nombre
entier, il faut 2 400 000 valeurs entires pour reprsenter 2 minutes de musique. Pour appliquer certains traitements un tel enregistrement, on pourra le conserver dans un tableau :
tableau dentiers [0...2 399 999] morceauDeMusique
Ce tableau est tel que morceauDeMusique[t] dsigne lchantillon de signal sonore mesur
lintervalle de temps numro t.
Universit de Rennes 1
143
Exemple 2
Si on a frquemment besoin dobtenir le nom dun mois partir dun numro de mois, on pourra
regrouper les noms de mois, des chanes de caractres, dans un tableau de 12 lments indic de 1
12.
tableau de chanes de caractres [1...12] nomDuMois
Avec un tel tableau, nomDuMois[3] dsignera le nom du 3me mois, et vaudra sans doute mars.
Lexemple 1 est typique de lusage dun tableau pour une grosse quantit de donnes. Mais la fonction de correspondance t morceauDeMusique[t] est galement importante pour les traitements
sur le son. Dans lexemple 2 la collection de valeurs est relativement petite. Le tableau est utilis
pour tablir une correspondance entre entiers et lments, n nomDuMois[n].
9.2
0
1
2
3
4
5
6
7
8
9
10
11
239999
Par ailleurs, on peut dclarer des variables, constantes, paramtres ou rsultats de fonctions de type
tableau, cest--dire de type rfrence un tableau.
La forme gnrale dune dclaration de variable rfrence tableau est :
TypeDesElments[] nomDeTableau;
Exemples :
int[] morceauDeMusique; rfrence un tableau dentiers appel morceauDeMusique
String[] nomDuMois; rfrence un tableau de chanes de caractres appel nomDuMois
La dclaration de tableau nindique pas la taille du tableau. Cest normal car la taille est dcide au
moment de la cration du tableau et figure donc dans lexpression de cration new
nomDeType[taille]. La dclaration seule ne cre pas de tableau. Dans les exemples ci-dessus, les
144
Module A.P.I
Universit de Rennes 1
Tableaux
variables morceauDeMusique et nomDuMois sont initialises la rfrence null qui ne dsigne rien. Le captage dans une variable de la rfrence un tableau se fait par une affectation :
morceauDeMusique = new int[240000];
nomDuMois = new String[12];
morceauDeMusique
0
1
2
239999
???
???
???
???
???
???
nomDuMois
0
1
2
3
4
5
6
7
8
9
10
11
???
???
null
null
null
null
null
null
null
null
null
null
null
null
9.3
Universit de Rennes 1
145
Par exemple voici les affectations qui initialisent le tableau des noms de mois :
nomDuMois[0] = "janvier";
nomDuMois[1] = "fvrier";
nomDuMois[2] = "mars";
...
nomDuMois[11] = "dcembre";
Pour un tableau de taille importante comme le morceau de musique, linitialisation se fait gnralement au moyen dune boucle qui parcourt tous les lments au moyen dune variable entire. Le
tableau pourra tre initialis avec des valeurs lues dans un fichier :
for (int i=0; i<240000; i++) {
morceauDeMusique[i] = fichierDeMusique.lireUnEntier();
}
Dans cet exemple, la fonction fichierDeMusique.lireUnEntier() est suppose lire
chaque appel une nouvelle valeur entire depuis le fichier fichierDeMusique .
Aprs ces initialisations, les tableaux contiennent enfin des valeurs exploitables :
morceauDeMusique
0
1
2
239999
9.4
12
7
2
-1
-12
-8
nomDuMois
45
43
0
1
2
3
4
5
6
7
8
9
10
11
"janvier"
"fvrier"
"mars"
"avril"
"mai"
"juin"
"juillet"
"aot"
"septembre"
"octobre"
"novembre"
"dcembre"
146
Module A.P.I
Universit de Rennes 1
Tableaux
Si on lutilise ainsi :
double[] T1 = {4,12,67,1};
metAZero(T1,2);
T1 se trouve modifi. Il vaut {4,12,0,1}
Lappel a eu un effet. Cest dailleurs ce que dit la spcification de cette procdure.
Si on ne dsire pas deffet, mais obtenir un nouveau tableau partir dun tableau pass en paramtre, la fonction doit crer le nouveau tableau et ne pas modifier celui pass en paramtre. Cest le
cas de la fonction suivante, miseAZero , qui est sans effet et rend en rsultat un nouveau tableau
obtenu partir de T en remplaant par 0 la valeur de llment k.
static double[] miseAZero(double[] T, int k){
// prrequis
: k>=0 et k<T.length
// rsultat
: nouveau tableau ayant zro en position k
// et les mme valeurs que T dans les autres positions
double[] resul = new double[T.length];
for(int i=0; i<T.length; i++){
resul[i]=T[i];
}
resul[k]=0;
return resul;
}
Ici, nous avons cr au sein de la fonction un nouveau tableau resul , de mme taille que T. Puis
nous avons copi T dans resul (on appelle cela cloner le tableau T). Ensuite nous avons mis 0
llment k de resul . Et enfin nous avons rendu resul en rsultat.
9.5
Java permet, lors de la dclaration dun tableau, de crer le tableau et ses lments. La forme gnrale est :
typeDesElments[] nomDeTableau = {e0, e2... ek};
Exemples :
int[] lesDixPremiersEntiers = {0,1,2,3,4,5,6,7,8,9};
char[]
chiffresDecimaux
= {'0','1','2','3','4','5',6','7','8','9'};
Universit de Rennes 1
147
148
Module A.P.I
Universit de Rennes 1
Tableaux
9.6
sonAdresse,
int
sonAge)
int etatRecherche=Etat.nonDecide;
int i=0;
while (etatRecherche==Etat.nonDecide) {
if (i==population.length) {etatRecherche=Etat.absent;}
else if (population[i].nom.equals(nomCherche)) {
etatRecherche=Etat.present;
}
else {i++;}
}
if (etatRecherche==Etat.absent){
System.out.println("aucune personne de ce nom");
}
else /*etatRecherche==Etat.present*/ {
System.out.println("nom
: " + population[i].nom
+ " adresse
: " + population[i].adresse
+ " ge : " + population[i].age
+ " ans");
}
Universit de Rennes 1
149
Exemple 2
On a 100 nombres entiers dans un fichier. On dsire rechercher combien de nombres sont infrieurs
ou gaux la moyenne, et combien sont suprieurs. Il nous faut dans un premier temps calculer la
moyenne des nombres, ce qui impose un parcours de toute la suite des nombres. Puis on doit la parcourir nouveau pour compter ceux qui sont infrieurs ou gaux la moyenne. La lecture dun
fichier est relativement longue. Pour viter de lire deux fois le fichier on peut utiliser un tableau qui
mmorise les nombres. Le comptage utilise alors le tableau.
class ComptageDesInferieursALaMoyenne {
public static void main(String[] arg) {
LectureFichierTexte fichierDeNotes =
new LectureFichierTexte("notesDeMath.txt");
final int nombreDeNotes=100;
int[] note = new int[nombreDeNotes];
// initialisation du tableau note
// avec les valeurs lues dans le fichier de notes
// et calcul de la moyenne des notes
double sommeDesNotes=0;
for (int i=0; i<nombreDeNotes; i++) {
note[i] = fichierDeNotes.lireUnEntier();
sommeDesNotes = sommeDesNotes+note[i];
}
double moyenneDesNotes = sommeDesNotes/nombreDeNotes;
// comptage de nombre de notes inf. ou gales la moyenne
int nbNotesInferieuresALaMoyenne=0;
for (int i=0; i<nombreDeNotes; i++) {
if (note[i]<=moyenneDesNotes) {
nbNotesInferieuresALaMoyenne++;
}
}
9.7
System.out.println("moyenne
des : notes
" + moyenneDesNotes);
System.out.println(nbNotesInferieuresALaMoyenne
+ " notes sont infrieures ou gales la moyenne");
System.out.println(
(nombreDeNotes - nbNotesInferieuresALaMoyenne)
+ " notes sont suprieures la moyenne");
}
150
Module A.P.I
Universit de Rennes 1
Tableaux
j pourra tre note T[i..j] si la position j est comprise et T[i..j[ si la position j est exclue.
0
i tranche T[i..j] j
T.length
La proprit dsire pour le rsultat est trivialement vraie pour une tranche vide, ce quon
sur
la tranche
Exemple 2 : tri dun tableau par placements successifs des lments maximaux
Soit raliser une procdure qui trie un tableau par ordre croissant. Le tri est une opration trs utile
car, une fois tri, la recherche dinformation dans un tableau est considrablement plus rapide que
dans un tableau en vrac. Le tri dun tableau T1 est un tableau T2 qui a les mmes lments que
T1 (en valeur et en quantit pour chaque valeur) mais tel que si i>j alors T2[i]>=T2[j]. Nous
nous intressons ici une procdure de tri, qui a pour effet de trier un tableau pass en paramtre.
Le tri se fera donc sur le tableau lui-mme (par opposition une fonction qui rendrait en rsultat un
nouveau tableau tri).Le principe que nous allons mettre en uvre nest pas trs efficace, mais il a
Universit de Rennes 1
151
T[0
iMax
15
15
partie trie
T.length
Si nous cherchons un indice iMax du maximum de la tranche T[0..i[ , en changeant les valeurs
de T[iMax] et de T[i-1] , la partie trie grossit dune unit. Il suffit donc dappliquer ce procd pour i variant de T.length 1.
La recherche de iMax peut se faire au moyen dune fonction similaire la fonction de lexemple
prcdent. La seule diffrence est que cette fonction cherche un indice du maximum sur une tranche
T[0..k[ et non sur le tableau complet. Il faut donc rajouter un paramtre k qui indique la borne
suprieure de la tranche :
static int indiceDeMax(double[] T, int k){
// prrequis
: k>0 et k<=T.length
// rsultat
: indice dun lment maximum de la tranche T[0..k[
double max=T[0]; int indiceDuMax=0;
int i=1;
while(i<k){
// invariant
: T[indiceDuMax]
est maximal
sur la tranche
if(T[i]>max){max=T[i]; indiceDuMax=i;}
i++;
}
return indiceDuMax;
}
Le tri est alors ralis par une itration qui maintient linvariant :
T a les mmes lments que Tinitial (valeur de T lors de lappel), T[i..T.length[ est tri et
les lments de T[i..T.length[ sont suprieurs ou gaux ceux de T[0..i[ .
static void trier(double[] T){
// effet
: tri T par ordre croissant
int i=T.length;
while(i>0){
// invariant
: T a les mmes lments que Tinitial
// T[i..T.length[
est tri et les lments de T[i..T.length[
// sont suprieurs ou gaux ceux de T[0..i[
int iMax=indiceDeMax(T,i);
double vMax=T[iMax]; T[iMax]=T[i-1]; T[i-1]=vMax;
i--;
}
}
En sortie ditration, i vaut 0, et le tableau est donc intgralement tri.
152
Module A.P.I
Universit de Rennes 1
T[0..
Tableaux
tranche. Si T[m]>v, la tranche suivante est T[i..m-1] et si T[m]<v, la tranche suivante est
T[m+1..j] .
Litration termine soit lorsque T[m]==v, auquel cas m est lindice cherch, soit lorsque i>j,
auquel cas v nest pas dans le tableau puisque la tranche o il pourrait de trouver est devenue
vide.
Linvariant de cette itration est :
v nest pas prsent en dehors de la tranche T[i..j]
static int recherche(double[] T, double v){
// prrequis
: T est tri par ordre croissant
// rsultat
: un indice i tel que T[i]=v si v est prsent dans T,
// -1 sinon
int i=0; int j=T.length-1;
int milieu=(i+j)/2;
while(i<=j && T[milieu]!=v){
// invariant
: v nest pas prsent
en dehors de la tranche
if(T[milieu]>v){j=milieu-1;}
else / * T[milieu]<v */ {i=milieu+1;}
milieu=(i+j)/2;
}
if(i<=j){return milieu;}
else {return -1;}
}
En sortie ditration, si i<=j, milieu est lindice cherch (puisque litration sest termine avec
T[milieu]==v ), sinon v nest pas prsent dans T, puisque lintervalle o il est susceptible de se
trouver est vide.
La terminaison de cette itration est garantie par la dcroissance stricte de la taille de la tranche
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
153
T[i
T[i..j] . Il faut cependant tre prudent. Cette dcroissance est stricte car on considre soit
[i..milieu-1] soit [milieu+1..j] dont les tailles sont strictement infrieures la taille de
[i..j] . Ce nest pas toujours le cas pour [i..milieu] ou [milieu..j] qui ont mme taille
que [i..j] si i=j. Dans ce cas, milieu=i et litration risque de ne pas terminer (cest ce qui
se passe effectivement si on programme ainsi).
Plus formellement, on peut prendre i-j comme fonction de terminaison. Lintervalle est divis par
2 chaque itration, ce qui garantit un temps de recherche infrieur k.log(T.length ). Par exemple, pour un tableau dun million dlments, la recherche ncessite au plus 20 pas ditration, car
2201000000.
9.8
0 1 2 3 4 5 6 7
1
2
3
4
5
echiquier[4][6]
6
7
154
Module A.P.I
Universit de Rennes 1
Tableaux
Si on ne donne quun seul indice, on obtient un lment qui est lui mme un tableau de dimen-
0
1
2
3
0 1 2 3 4 5 6 7
...
27 28 29 30
dcembre 11
Universit de Rennes 1
155
Remarques :
Le nombre de lignes dun tableau M deux dimensions sobtient par M.length . Cest nor-
mal puisque M, en tant que tableau (de tableaux) est le tableau des lignes.
Dans la mesure o la ligne i de M existe, son nombre dlment est M[i].length .
Si M est un tableau rectangulaire rgulier et de taille non nulle, son nombre de collonnes
peut sobtenir par M[0].length .
Exemple dutilisation de tableaux rguliers 2 dimensions : produit de matrices
Une des utilisations importantes des tableaux deux dimensions est tout ce qui se rapporte au calcul
matriciel : transformations linaires, rsolutions de systmes dquations linaires...
Lexemple suivant illustre le produit de matrices de nombres rels. La fonction produitMatrice a pour paramtres une matrice np A (n lignes, p colonnes) et une matrice pq B. Elle rend
en rsultat la matrice produit C=AB, de n lignes et q colonnes. Le calcul est ralis selon la formule classique Cij = AikBkj, ce calcul tant ralis au moyen de trois boucles imbriques. Le programme principal calcule et affiche le produit de deux matrices 33 donnes sous forme de tableaux
initialiss.
class TestMatrice {
static double[][] produitMatrice(double[][] A, double[][] B) {
// prrequis
: A est une matrice n x p et B une matrice p x q
// rsultat
: le produit matriciel A X B
final int n=A.length;
final int p = B.length;
final int q = B[0].length;
double[][] C = new double[n][q]; // matrice rsultat
for(int i=0;i<n;i++){
for (int j=0;j<q;j++){
C[i][j]=0;
for (int k=0;k<p;k++) {
C[i][j]= C[i][j]+A[i][k]*B[k][j];
}
}
}
return C;
}
156
Module A.P.I
Universit de Rennes 1
Tableaux
QCM 9.1
1 - Les tableaux servent faire correspondre des nombres entiers (les indices) et des donnes de
types quelconques mais identiques (les lments du tableau).
2 - Un tableau remplace avantageusement lusage de variables de mme type, car il est plus concis dutiliser des noms de la forme T[0], T[1], T[2], T[3] ... que des identificateurs divers.
3 - En Java, les tableaux sont des objets toujours dsigns par rfrence.
4 - En Java, on peut crer un tableau de 20 lments (de type int par exemple) par une simple
5 - En Java, un tableau de 20 lments (de type int par exemple) est ncessairement cr par
une instruction : new int[20];
6 - En Java, une dclaration de la forme int[] T;dfinit T comme tant une rfrence un
tableau dentiers et cette rfrence est initialise null, de sorte que T ne dsigne rien.
7 - En Java, T2 tant dclar int[] T2;et T1 dsignant un tableau dentiers de taille 30,
linstruction daffectation T2=T1; provoque la cration dun tableau de taille 30 dont la rfrence
est capte par T2 et la copie des lments de T1 dans le tableau dsign par T2.
8 - En Java, T2 tant dclar int[] T2;et T1 dsignant un tableau dentiers, linstruction
daffectation T2=T1; le captage par T2 de la rfrence au tableau dsign par T1.
QCM 9.2
Soit la squence dinstructions :
String[] T1 = new String[30];
String[] T2 = T1;
T2[4]="bonjour";
Universit de Rennes 1
157
lments que T dans lordre inverse renverse de celui o ils figurent dans T.
rend en rsultat un nouveau tableau contenant les mmes lments que T dans lordre inverse renverse de celui o ils figurent dans T.
1 - En Java, on peut crer un tableau de taille nulle, par exemple un tableau dentiers de zro lments, par new int[0] .
2 - Un tableau de taille nulle est dsign par null.
Considrons un tableau de tableau ainsi dclar : double[][]
T; .
6 - Si i>=0 et i<T.length,
158
Module A.P.I
Universit de Rennes 1
Tableaux
Exercice 9.1
objectif : ces exercices ont pour but de se familiariser avec lusage des tableaux. La fonction
enClair demand dans lexercice 1 permet de visualiser un tableau. Elle sera trs utile par la
suite pour des tests.
Rdiger et tester les fonctions suivantes de manipulation de tableaux de chanes de caractres :
1 - Fonction enClair telle que enClair(T) rend en rsultat la chane de caractres "en clair"
constitue des lments de T par ordre dindices spars par des blancs. Exemple :
avec :
rsultat :
"toto"
"alfred"
"jerome"
"simon"
"{toto,alfred,jerome,simon}"
3 - Fonction indiceDuplusPetitAlphabetique telle que indiceDuPlusPetitAlphabetique(T,i) soit lindice de la plus petite chane, selon lordre alphabtique, contenu
dans le tableau T partir de lindice i. Pour tester lordre alphabtique on utilisera la mthode
s1.compareTo( s2) qui rend un entier ngatif si la chane s1 est infrieure s2, 0 si les chanes
sont gales et un entier positif si s1 est suprieur s2.
Exemple :
avec :
0
1
2
3
"toto"
"alfred"
"jerome"
"simon"
4 - Procdure trier telle que trier(T) transforme le tableau T en un tableau contenant tous les
lments que possdait T classs par ordre croissant.
Remarque : on peut crer un tableau initialis au moyen dune instruction de la forme :
String[] T={"toto","alfred","jerome","simon"};
Ceci est trs pratique pour faire des tests reproductibles.
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
159
Exercice 9.2
objectif : les exercices 9.2 9.6 concernent le tri de tableaux. Lobjectif de ces exercice est
double :
- connatre quelques algorithmes classiques de tri,
- apprendre raisonner sur des tranches de tableau.
1 - Rdiger la fonction
static
int nombreDe(double v,
double[]
T)
int rangDe(double v,
double[]
T)
qui rend en rsultat le rang par ordre croissant de v dans T. Le rang de v dans T est le nombre dlments de T strictement infrieurs v. Ainsi si aucun lment nest infrieur v, le rsultat est 0, et
si tous les lments sont infrieurs v, le rsultat est T.length .
3 - Utiliser les fonctions prcdentes pour programmer la fonction de tri :
static double[] tri(double[] T){
// rsultat
: un nouveau tableau contenant les lments de T
// tris par ordre croissant
Remarque : le principe de ce tri consiste, pour chaque lment de T placer dans le rsultat partir
du rang de cet lment autant de fois cet lment quil a doccurrences dans T. Ce principe simple
conduit replacer plusieurs fois, sa place, la mme valeur dans le tableau rsultat, mais ce nest
pas grave (lviter serait assez compliqu).
Exercice 9.3
3
6
7
12
9
24
56
21
87
33
3
6
7
12
9
24
56
21
33
87
3
6
7
12
9
24
21
56
33
87
3
6
7
12
9
21
24
56
33
87
3
6
7
9
12
21
24
56
33
87
partie
trie
Ainsi, comme le suggre lexemple ci-dessus, chaque parcours la partie trie du tableau saccrot
dau moins un emplacement.
160
Module A.P.I
Universit de Rennes 1
Tableaux
Pour un tableau de taille n, suffit de rpter n fois ce processus pour trier compltement le tableau.
Puisque chaque parcours la partie trie saccrot dau moins une unit, on vite des comparaisons
inutiles en effectuant le parcours suivant sur une tranche diminue dune unit, cest dire uniquement sur la partie possiblement non trie.
Cet algorithme est souvent prsent sous forme dune mtaphore, la monte de bulles. Considrons le cas dun tri par ordre croissant, comme le montre lexemple prcdent. Un lments T[i]
tel que T[i]<T[i-1] est appel bulle, par analogie avec une bulle de gaz dans un liquide. Une
telle bulle est destine monter vers la surface (les indices faibles ici), par change avec llment prcdent.
Il est bon de concrtiser ce concept par une procdure monteeDeBulles qui ralise une remonte de bulles sur une tranche T[k..T.length[ . Voici sa spcification :
static void monteeDeBulles(double[] T, int k)
// prrequis
: 0<=k<T.length
// effet
: ralise une monte de bulles
// sur la tranche T[k..T.length[
1.1 - Rdiger la procdure monteeDeBulles .
La procdure monteeDeBulles est destine tre utilise dans la procdure de tri, au moyen
dun itration qui procde un succession de remontes de bulles sur des tranches
T[k..T.length[ de tailles dcroissantes de sorte trier totalement le tableau T.
1.2 - Rdiger cette procdure trier.
2 - Tri bulle
Le tri bulle est une amlioration du tri par permutations. Il consiste terminer la procdure de tri
ds que la tentative de monte de bulles ne fait monter aucune bulle (ne procde aucun change).
En effet, cela signifie que la tranche sue laquelle on a tent une monte de bulle est correctement
ordonne, et puisque tous ses lments sont suprieurs la partie dj trie, le tableau est totalement
tri.
Cela ncessite de modifier la procdure de monte de bulles de manire ce quelle indique si une
bulle a effectivement t monte. Cette nouvelle procdure, tenteMonteeDeBulles est ainsi
spcifie :
static boolean tenteMonteeDeBulles(double[] T, int k)
// prrequis
: 0<=k<T.length
// effet
: ralise une monte de bulles
// sur la tranche T[k..T.length[
// rsultat
: indique si une bulle a effectivement t monte
2.1 - Rdiger la procdure tenteMonteeDeBulles .
2.2 - Rdiger cette procdure trier qui ralise un tri bulle.
Universit de Rennes 1
161
Exercice 9.4
Le tri par comptage (Distribution counting) ne peut sappliquer que si le domaine des valeurs est
numrable (un intervalle dentiers par exemple) et pas trop grand. On procde en deux temps :
1 - on compte le nombre doccurrences de chaque valeur prsente dans le tableau trier, dans un
tableau dont la taille est la dimension du domaine possible pour les valeurs,
2 - ensuite on construit le tableau tri en parcourant le tableau des occurrences.
exemple, soit le tableau T :
5
Exercice 9.5
162
Module A.P.I
Universit de Rennes 1
Tableaux
Exercice 9.6
67
23
4
12
4
19
5
67
56
12
12
12
19
67
56
4
7
12
4
19
67
5
23
67
6
12
56
4
4
7
12
19
67
4
4
5
6
7
12
12
19
23
56
67
67
5
6
12
23
56
67
Remarque : la complexit est O(n.log(n)). Cest le mieux que lon puisse faire dans le cas gnral,
pour un tableau nayant aucune proprit particulire.
On veut rdiger selon ce principe une fonction de tri dun tableau dentiers :
static int[] tri(int[] T)
// rsultat
: un nouveau tableau contenant
// les lments de T tris par ordre croissant
Lalgorithme suggr est naturellement rcursif. Son petit dfaut est de ncessiter des tableaux
intermdiaires. Pour viter de crer de nouveaux tableaux lors de lclatement dun tableau en deux
parties, on peut passer en paramtre une tranche du tableau originel, cest--dire le tableau T et
deux indices i et j qui dlimitent les lments trier. Pour cela il faut rdiger une fonction
auxiliaire :
static int[] triTranche(int[] T, int i, int j)
// prrequis
: ???
// rsultat
: un nouveau tableau contenant
// les lments de la tranche T[i..j[
Universit de Rennes 1
163
Exercice 9.7
Manipulation de matrices
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1
0
0
0
0
1
0
0
0
0
1
0
0
0
0
1
Spcification :
static int[][] matriceUnite(int n)
// rsultat
: reprsentation de la matrice unit de taille n
3 - Transpose : la fonction Transposee doit rendre en rsultat un tableau reprsentant la
matrice transpose de celle reprsente par un tableau carr M.
Rappel : la transpose dune matrice M est la matrice MT telle que MT[i,j] = M[j,i] (interversion
des lignes et des colonnes).
164
Module A.P.I
Universit de Rennes 1
Tableaux
Exemple :
avec M reprsentant la matrice :
12 6 4
9 1 0
3 15 8
12 9 3
6 1 15
4 0 8
Spcification :
static int[][] transposee(int[][] M)
// prrequis
: M est un tableau carr
// rsultat
: reprsentation de la matrice transpose
// de celle reprsente par M
4 - Test de diagonalit : la fonction estDiagonale doit indiquer si la matrice reprsente par un
tableau carr M est diagonale. Rappel : une matrice M est diagonale si seule les lments M[i,i] sont
diffrents de 0.
Exemples :
la matrice suivante est diagonale :
12 0 0
0 1 0
0 0 8
12 0 0
0 1 15
4 0 8
Spcification :
static boolean estDiagonale(int[][] M)
// prrequis
: M est un tableau carr
// rsultat
: indique
si la matrice
reprsente
par
M est
5 - Carr magique
Une matrice carre dentiers est magique si les sommes des valeurs de chaque ligne, de chaque
colonne et des deux diagonales sont gales.
Exemple de carr magique :
6
La fonction estMagique doit indiquer si la matrice reprsente par un tableau M est magique.
Spcification :
static boolean estMagique(int[][] M)
// prrequis
: M est un tableau carr
// rsultat
: indique si la matrice reprsente par M est magique
Universit de Rennes 1
165
diag
Exercice 9.8
Lalgorithme suivant permet de dterminer les nombres premiers infrieurs n. Soit un tableau de
boolens premier , de taille n, initialis vrai.
On commence avec lindice k=2, aprs avoir mis premier[0] et premier[1] faux.
Si premier[ k]=vrai, on met faux tous les lments dindice multiple de k jusqu lindice
k2.
On incrmente k et on recommence tant que k est infrieur la racine carr de n.
Les nombres premiers sont alors les nombres i tels que premier[ i]=vrai.
Rdiger la fonction suivante selon ce principe :
static boolean[] premier(int n)
// prrequis
: n>=0
// rsultat
: tel que pour tout i <n,
// premier(n)[i] indique si i est premier
166
Module A.P.I
Universit de Rennes 1
Tableaux
Aide 9.1
Fonction enClair :
Il faut se mfier de placer les , uniquement entre deux lments de T. Pour cela on peut concatner
au rsultat ,lment pour chaque lment sauf pour le premier.
Encore faut-il que T possde au moins un lment. Nous acceptons que T soit vide (T.length =0)
et le rsultat est "{}" dans ce cas. Il convient de traiter ce cas sparment au dbut du corps de la
fonction.
Fonction estPresent :
T ntant pas priori tri, nous sommes oblig deffectuer un parcours des lments successifs.
Litration sarrte lorsquon a parcouru tout le tableau (i==T.length ) ou quand on rencontre un
lment gal s.
Fonction indiceDuPlusPetitAlphabetique :
La ralisation de cette fonction est similaire celle de la fonction indiceDeMax vue dans ce chapitre du cours. Les diffrences sont :
Lordre est lordre alphabtique, qui se teste par T[i].compareTo(min)<0 pour savoir si
T[i] est plus petit (avant par ordre alphabtique) que min.
On cherche le minimum sur la tranche T[k..T.length[ au lieu de la tranche T[0..k[ .
Procdure trier :
Cette procdure est similaire la procdure de tri dun tableau de nombres vue dans ce chapitre du
cours. La seule diffrence est que lon maintient trie la tranche T[0..i[ au lieu de la tranche
T[i..T.length[ car on procde par dplacement des lments minimaux successifs (au lieu
des lments maximaux).
0
partie trie
iMin
"pp"
"jj"
"jj"
"pp"
T.length
Universit de Rennes 1
167
Aide 9.2 - Tri dun tableau par dtermination des rangs des lments
1 - Fonction nombreDe
Il suffit de parcourir le tableau T en incrmentant un compteur resul chaque fois que llment
T[i] est gal v.
2 - Fonction rangDe
Il suffit de parcourir le tableau T en incrmentant un compteur resul chaque fois que llment
T[i] est strictement infrieur v.
3 - Fonction tri
Pour chaque lment T[i], on calcule son rang j et son nombre doccurrences n, puis on place
dans le tableau rsultat, partir de j, n occurrences successives de T[i].
Aide 9.3
168
Module A.P.I
Universit de Rennes 1
Tableaux
Aide 9.4
La procdure de tri par comptage commence par chercher le plus grand lment de T de manire
dterminer la taille du tableau de comptage nombreDOccurences . Ce tableau est cr avec cette
taille et initialis avec des 0 partout.
Ensuite, le tableau T est parcouru en comptant le nombre doccurrences de chaque valeur rencontre, cest--dire en incrmentant nombreDOccurences[ v] pour chaque valeur v rencontre.
Enfin le tableau nombreDOccurences est parcouru pour placer des squences successives de
nombreDOccurences[ i] valeurs gales i dans le tableau T.
Aide 9.5
triTranche
sur
tout
le
tableau,
soit :
triTran-
Fonction triTranche :
Le rsultat est un nouveau tableau de mme taille que la tranche. Il convient de crer ce tableau en
dbut du corps de la fonction :
int[] resul = new int[j-i+1];
Larrt de la rcursivit a lieu pour une tranche rduite un seul lment. Le rsultat est alors le
tableau constitu de ce seul lment : resul[0]=T[i]
Pour un tableau de plus dun lment, le dcoupage en deux parties de la tranche T[i,j] donne
les deux tranches T[i,(i+j)/2] et T[(i+j)2+1,j] .
Le tri de ces deux tranches (appels rcursifs) donne les tableaux tris T1 et T2.
Ces tableaux sont alors fusionn dans resul .
La fusion consiste piocher dans T1 ou dans T2 selon en prlevant chaque fois le plus petit lment parmi T1[k1] et T2[k2] .
La fusion se termine par un clusage dun des tableaux. En effet, le prlvement dans T1 ou T2
doit sarrter ds quun des tableau est puis. Il faut alors complter resul par les lments restant dans lautre tableau.
Universit de Rennes 1
169
Aide 9.7
Manipulation de matrices
1 - Fonction enClair
Peu de difficult. Placer un passage la ligne, "\n", devant chaque visualisation de ligne.
2 - Fonction matriceUnite
Le rsultat est un tableau carr de taille n, cr par
int[][] resul = new int[n][n];
Deux boucles imbriques parcourent le tableau resul pour y placer 1 aux indices correspondant
la diagonale principale (i==j) et 0 ailleurs (i!=j).
3 - Fonction Transposee
Le rsultat est un tableau carr de mme taille que M, cr par
int n=M.length; int[][] resul = new int[n][n];
Deux boucles imbriques parcourent les tableaux M et resul pour appliquer la dfinition de ce
quest la transpose :
resul[i][j] = M[j][i]
4 - Fonction estDiagonale
Il suffit de vrifier que tout lment hors de la diagonale principale est nul.
5 - Fonction estMagique
Il est bon de se donner les fonctions intermdiaires suivantes, qui permettront de programmer de
faon aise et comprhensible la fonction estMagique . Ces fonction sont :
170
Module A.P.I
Universit de Rennes 1
Tableaux
Aide 9.8
Le tableau boolen rsultat, resul , est de taille n. Il faut linitialiser true, sauf resul[0] et
rsul[1] qui doivent tre positionns false .
Ensuite, pour chaque k depuis 2 jusqu n-1, si resul[k] vaut true il faut positionner
false les lments dindices multiples de k. Pour cela il convient dutiliser une boucle qui progresse par pas de k, de la forme :
for(int i=2*k; i<n; i=i+k){...}
Voici un exemple de procdure de test de cette fonction.
Ce qui nous intresse en fait ce nest pas dafficher le tableau de boolens qui indique si un nombre
est premier, mais dafficher la suite des nombres premiers infrieurs n. Pour cela nous avons
rdig une fonction static String
nombresPremiers(int ) qui rend
n en rsultat la chane
de caractres qui visualise en clair cette suite.
static String nombresPremiers(int n){
// rsultat
: la suite en clair des nombres premiers < n
boolean[] estPremier = premier(n);
String resul="";
for(int i=0; i<n; i++){
if(estPremier[i]){resul=resul+i+" ";}
}
return resul;
}
public static void main(String[] z){
System.out.println("nombres premiers < 100
System.out.println(nombresPremiers(100));
}
:");
La procdure principale de test utilise cette fonction pour imprimer la suite des nombres premiers
infrieurs 100. Cela doit donner :
2 3 5 7 1 1 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 8
97
Universit de Rennes 1
171
172
Module A.P.I
Universit de Rennes 1
CHAPITRE 10
La notion de structure permet de dfinir un type de donne qui possde plusieurs caractristiques
reprsentes par les valeurs des champs de la structure. On va maintenant tendre cette notion en
permettant de regrouper non seulement des valeurs mais galement des oprations dans la dclaration de type. Un tel regroupement de donnes (attributs) et doprateurs (mthodes) sappelle un
objet. Un type dobjet est dfini au moyen dune classe.
10.1
nord
Y
ouest
est
sud
10.1.1
dune part on utilise un type structure, compos de champs de donnes, pour reprsenter les
caractristiques de lobjet modliser, un robot dans notre exemple :
Universit de Rennes 1
173
donnes
Y
orientation
class Robot {
public int X; public int Y;
public Orientation o;
public Robot(int x, int y, Orientation versOu) {
X=x; Y=y; o=versOu;
}
}
avec, pour lorientation : enum Orientation {nord,est,sud,ouest }
tournerADroite
class utilisationDeRobot {
static void avancer(Robot ceRobot) {
switch (ceRobot.o) {
case nord
: ceRobot.Y = ceRobot.Y+1; break;
case est
: ceRobot.X = ceRobot.X+1; break;
case sud
: ceRobot.Y = ceRobot.Y-1; break;
case ouest: ceRobot.X = ceRobot.X-1; break;
}
}
static void tournerADroite(Robot ceRobot){
switch (ceRobot.o) {
case nord
: ceRobot.o=Orientation.est; break;
case est
: ceRobot.o=Orientation.sud; break;
case sud
: ceRobot.o=Orientation.ouest; break;
case ouest: ceRobot.o=Orientation.nord
; break;
}
}
174
Module A.P.I
Universit de Rennes 1
10.1.2
Approche objet
Une faon de faire plus modulaire consiste dfinir les oprations dans le texte de la classe qui dfinit le type de lobjet.
X
donnes
objet gnral
+
procdures
Y
orientation
initialisations
avancer
tournerADroite
Universit de Rennes 1
175
lattribut static , sont des composants qui existent en un seul exemplaire et qui ne sont
associs aucun objet particulier. Ctait le cas des fonctions utilises jusqu prsent ainsi
que des constantes et variables globales utilises dans certaines classes.
Les composants non statiques, cest--dire non affubls de lattribut static , sont des
composants qui existent dans chaque objet instance de la classe. Cest le cas des composants de donnes qui dcrivent lobjet (X, Y, o) et des mthodes dobjet (avancer() ,
tournerADroite() ).
4 - La forme de lappel est diffrente : lobjet sur lequel porte lopration nest pas indiqu entre
parenthses comme pour un paramtre explicite, mais devant le nom de lopration :
vigor.avancer() . Pendant lexcution de cet appel, linstance courante est lobjet dsign par vigor.
5 - La rdaction des oprations est galement un peu diffrente : les composants de linstance courante sont dsignes simplement par leurs identificateurs, X, Y, orientation , sans avoir
indiquer explicitement lobjet.
10.1.3
176
Module A.P.I
Universit de Rennes 1
10.1.4
On dsire que la position dun Robot ne puisse tre modifie que par la procdure avan-
cer() , parce que, par exemple, le mouvement du robot que lon modlise ne peut se faire que
dune unit dans sa direction courante.
On dsire que lorientation dun Robot ne puisse tre modifie que par la procdure tournerADroite() , parce que le robot ne peut faire que des rotations dun quart de tour droite.
En rgle gnrale, on dsire cacher les donnes concrtes qui reprsentent ltat dun objet car
ces donnes concrtes, les entiers X, Y et orientation dans lexemple du robot, rsultent dun
choix plus ou moins arbitraire pour reprsenter lobjet et ne font pas partie des spcifications logiques de lobjet. Par exemple, pour fixer les ides, on pourrait trs bien reprsenter concrtement la
position du robot non pas par son abscisse X et son ordonne Y, mais par sa distance lorigine R et
langle Teta de son rayon vecteur avec laxe Ox, ou toute autre reprsentation.
Y
R
Teta
X
Tout ce qui reprsente correctement ltat du robot peut convenir et cest au programmeur de faire
son choix pour diverses raisons de simplicit de calcul ou de facilit de programmation. Dans tous
les cas, vu de lextrieur, le robot doit se comporter pareillement. Les proprits du robot doivent
tre les mmes quelque soit la faon dont il est concrtement reprsent. Ces proprits intrinsques
du robot constituent ce quon appelle labstraction du type Robot . On ne va pas dvelopper ici une
thorie des robots qui avancent dun pas et tournent droite car ce genre de thorie est inintressante et par trop spcialise. Mais pour bien saisir ce quest une telle abstraction voici une proprit
que possde tout objet de type Robot :
si on excute la squence doprations :
avancer(), tournerADroite(), avancer(), tournerADroite(),
avancer(), tournerADroite(), avancer(), tournerADroite()
le robot se retrouve dans la mme position et la mme orientation quavant la squence.
Une telle proprit est intrinsque : elle est totalement indpendante de la reprsentation concrte
choisie.
Puisque les donnes concrtes ne font pas parties des proprits abstraites de lobjet, il est malsain
de permettre laccs ces donnes. Ces donnes nexistent que par hasard, cause du choix arbitraire de reprsentation.
Universit de Rennes 1
177
La technique usuelle, appele encapsulation, consiste interdire laccs direct aux donnes des
objets en dehors des programmes de la classe. En Java cela se note par le vocable private .
Lidentificateur dun composant de la classe, que ce soit une donne ou une fonction, affubl du
qualificatif private peut tre utilis uniquement depuis les textes de programme de la classe.
Notion daccesseur
Dans lexemple de la classe Robot , les donnes concrtes X, Y et orientation doivent tre
caches. Cependant il existe bien ici des correspondants directs X, Y et orientation qui font partie
de labstraction robot : un robot possde vraiment une abscisse X, une ordonne Y et une
orientation orientation. Dans ce cas on rdige des mthodes dont le seul rle est doffrir un accs
ces informations. Ces mthodes sont gnralement triviales : elles rendent en rsultat la valeur dun
composant de lobjet, ou affectent un composant de lobjet, parfois aprs avoir opr quelques vrifications de consistance. Ces mthodes sappellent des accesseurs. La convention la plus rpandue
est dappeler getXXX la mthode qui permet de lire la proprit XXX de lobjet et setXXX celle
qui permet de laffecter. Avec ces conventions, une rdaction de la classe Robot devient :
class Robot {
donnes concrtes caches
private int X; private int Y; private Orientation o;
constructeurs
public Robot(int x, int y, Orientation versOu) {...}
public Robot() {...}
oprations
public void avancer() {...}
public void tournerADroite(){...}
accesseurs
public int getX() {return X;}
public int getY() {return Y;}
public int getOrientation() {return o;}
On na fourni ici que des accesseurs en lecture, car on veut que les mouvements soient limits
ceux dfinis par avancer et tournerADroite .
Pour obtenir labscisse du robot vigor, il suffit dappeler la mthode : vigor.getX() . Lcriture vigor.X est interdite (en dehors du texte de la classe Robot ) : cest une erreur de syntaxe.
Rappels sur la nature des objets
Nous avons dj expliqu la nature des objets propos des cas particuliers que sont les chanes de
caractres (type String ) et les structures, objets sans mthodes dont les composants de donnes
ont le qualificatif public .
Les objets dfinis par un type classe ont les mmes prrogatives :
178
Module A.P.I
vigor
null
Universit de Rennes 1
X: 3
Y: 12
o: ouest
vigor
Laffectation dune variable de type classe est laffectation dune rfrence la variable. Lobjet
anciennement rfrenc nest pas affect.
vigor=totor;
avant
aprs
vigor
X: 3
Y: 12
o: ouest
vigor
X: 3
Y: 12
o: ouest
totor
X: 4
Y: 2
o: nord
totor
X: 4
Y: 2
o: nord
non pas les valeurs des objets rfrencs. Le rsultat est vrai si et seulement si les rfrences
dsignent le mme objet.
vigor
totor
X: 3
Y: 12
o: ouest
fulgor
X: 3
Y: 12
o: ouest
Universit de Rennes 1
179
Exemple rcapitulatif
10.2
Exemple rcapitulatif
La chasse au trsor :
On suppose quun trsor est plac un certain endroit (x0,y0) du plan. Un robot modlis par la
classe Robot prcdemment prsente se trouve initialement en (0,0). Le but du jeu est de piloter
le robot de faon lamener au mme endroit que le trsor. Le droulement de ce jeu peut tre prcis ainsi :
choisir au hasard la position (x0,y0) du trsor (sans la communiquer au joueur),
fixer la position initiale du robot en(0,0), orientation nord,
rpter tant que le robot nest pas sur le trsor {
indiquer au joueur la distance entre le robot et le trsor,
obtenir un ordre tourner droite ou avancer de la part du joueur et lexcuter,
}
afficher gagn et la position du trsor
Pour tirer des nombres au hasard on dispose dans la bibliothque standard de Java de la classe
Random . Un objet de cette classe est un gnrateur alatoire de nombres. Il possde une mthode
nextInt(k) qui rend en rsultat un nombre entier tir au hasard compris entre 0 et k (exclu).
class ChasseAuTresor {
// position du trsor (variable globale)
static int x0; static int y0;
// le robot (variable globale)
static Robot leRobot;
static int carreDistanceAuTresor() {
// rsultat : carr de la distance du robot au trsor
int dx=leRobot.getX()-x0; int dy=leRobot.getY()-y0;
return dx*dx + dy*dy;
}
180
Module A.P.I
Universit de Rennes 1
10.3
Universit de Rennes 1
181
class Personne {
public static final int tailleNormaleAdulte = 170;
private static int plusGrandeTaille = 0;
private String nom;
private int taille;
public Personne(String ceNom, int cetteTaille) {
nom = ceNom; taille = cetteTaille;
if (cetteTaille > plusGrandeTaille) {
plusGrandeTaille=cetteTaille;
}
}
public String getNom() { return nom; }
public int getTaille() { return taille; }
public setTaille(int nouvelleTaille) {
taille = nouvelleTaille;
if (nouvelleTaille > plusGrandeTaille) {
plusGrandeTaille=nouvelleTaille;
}
}
}
Pour viter des affectations incohrentes de la variable plusGrandeTaille , celle-ci a t dclare prive (private ). Ainsi elle ne peut tre cite que depuis le texte de la classe Personne ,
loccasion du constructeur et de la mthode setTaille de changement de taille.
Pour pouvoir accder la valeur de cette variable depuis lextrieur de la classe, on a donc programm un accesseur getPlusGrandeTaille .
Cet accesseur ne sapplique pas une instance particulire de Personne , cest donc une fonction
statique. Depuis lextrieur de la classe Personne on lappelle sous la forme
Personne.getPlusGrandeTaille() .
182
Module A.P.I
Universit de Rennes 1
class TestPersonne {
public static void main(String[] x) {
// cration de trois personnes
Personne jules = new Personne("Jules", 135);
Personne alfred = new Personne("Alfred", 183);
Personne marcel = new Personne("Marcel", 168);
int k = Personne.getPlusGrandeTaille()
System.out.print("la plus grande taille est " + k);
jules.setTaille(183);
int k = Personne.getPlusGrandeTaille()
System.out.print("la plus grande taille est " + k);
if (k>Personne.tailleNormaleAdulte) {
System.out.print("cest plus que la normale");
}
tailleNormaleAdulte
170
constante statique
plusGrandeTaille
183
variable statique
nom:"Jules"
taille: 135
nom:"Alfred"
taille: 183
instances de Personne
nom:"Marcel"
taille: 168
jules
alfred
marcel
10.4
Universit de Rennes 1
183
Rubrique prrequis
// prrequis
condition
:
Cette rubrique indique les conditions ausquelles doivent satisfaire les paramtres de la fonction et
ltat de lobjet (ltat de this) lorsquil sagit dune mthode dobjet. La condition est donc une
formule logique (un prdicat). Cette condition na pas tre teste par le programme de la
fonction : il est de la responsabilit de lutilisateur de respecter cette condition. En dautres termes,
tant pis pour lutilisateur sil ne respecte pas le prrequis, la fonction peut faire nimporte-quoi dans
ce cas sans que le programmeur de la fonction en soit responsable.
Dans le cas dune mthode dobjet, ltat de lobjet (this) ne doit faire en aucune faon usage des
composants de lobjet, qui ne sont que des moyens concrets de mise en uvre. Il ne faut utiliser que
les notions abstraites de lobjet.
Par exemple, pour une liste de personnes reprsente par un tableau et une variable comptabilisant
le nombre dlments de la liste :
class ListeDePersonnes {
private Personne[] lesElements; private int nbElements;
public ListeDePersonnes() { // liste vide
lesElements= new Personnne[1000]; nbElements=0;
}
...
public Personne laPremiere(){
// prrequis
: this nest pas vide
// rsultat
: la premire personne de this
}
...
}
Le prrequis this nest
pas vide
, est acceptable car tre vide fait partie de la notion
abstraite de liste. La condition nbElements>0 serait en revanche innaceptable car elle fait rfrence la mise en uvre.
Rubrique effet
// effet
:
changements dtat ou interractions avec lextrieur
Ici encore, pour une mthode dobjet qui change ltat de this, ou une fonction qui change ltat
dun objet de la classe pass en paramtre, le changement dtat doit tre indiqu en termes de
labstraction reprsente par la classe, et surtout pas en terme de changement dtat des composants. Par exemple, pour une classe ListeDePersonne , la mthode qui permet dajouter une
personne la liste serait ainsi spcifie :
public void ajouter(Personne p) { // effet
lesElements[nbElements]=p; nbElements++;
}
: ajoute p this
// rsultat
expression
:
indiquant le rsultat rendu
lexpression qui indique ce que vaut le rsultat ne doit pas faire rfrence aux moyens utiliss pour
le calculer. Il ne doit faire rfrence quaux paramtres, ltat abstrait de this (pour une mthode
dobjet) ou dun paramtre de la classe, et toutes les fonctions connues par ailleurs, mathmatiques ou spcifiques au domaine trait.
184
Module A.P.I
Universit de Rennes 1
Exercice 10.1
Dans un exercice prcdent nous avions reprsent les nombres complexes au moyen dune structure. Ce nest pas la bonne faon de faire. Il faut totalement abstraire les donnes concrtes qui
reprsentent un nombre complexe (x et y dans cet exemple), rdiger les fonctions de manipulation
des complexes lintrieur de cette classe et ne rendre visible aux utilisateurs que ces fonctions.
Rdiger la classe Complexe dans cet esprit.
Pour satisfaire aux gots divers et varis des utilisateurs potentiels, on pourra raliser deux versions
de chaque fonction de calcul :
une version fonction statique, par exemple :
public static Complexe add(Complexe z1, Complexe z2)
// rsultat : la somme de z1 et de z2
une version mthode dobjet :
public Complexe add(Complexe z)
// rsultat : la somme de this et de z
Exercice 10.2
Reprsentation de personnes
Rdiger une classe Personne qui reprsente une personne dote des attributs suivants : nom,
sexe, adresse, anne de naissance.
Le nom et ladresse sont des chanes de caractres (quelconque, on ne cherche pas vrifier la vraisemblance dtre un nom ou une adresse). Le sexe a deux valeurs possibles, masculin ou feminin. Lanne de naissance est donne sous la forme dun entier.
Les composants de donnes seront privs. On donne accs en consultation ces attributs au moyen
daccesseurs.
La classe doit offrir :
un constructeur trivial, qui reoit en paramtres la valeurs des attributs (nom, sexe, adresse et anne
de naissance),
Une mthode toString qui rend en rsultat une chane de caractres qui visualise en clair les
attributs de la personne.
Une fonction statique laPlusJeune telle que, p1 et p2 tant des personnes, laPlusJeune( p1,p2) est la personne la plus jeune parmi p1 et p2 (p1 en cas dgalit des ges).
Tester cette classe dans un programme principal (TestPersonne ) qui cre une personne toto,et
une personne x et imprime la plus jeune de ces deux personnes.
Universit de Rennes 1
185
Exercice 10.3
Une collection de personnes est un objet qui permet denregistrer un nombre quelconque dlments de type Personne . Une telle collection sera ralise par la classe Population dont voici
la spcification :
class Population{
public Population()
// constructeur
: population vide
186
Module A.P.I
Universit de Rennes 1
Mise en uvre
On dcide de reprsenter une population au moyen dun tableau personnes dlments de type
Personne et dune variable entire nbPersonnes .
Correspondance abstrait-concret : La variable nbPersonnes indique combien de personnes sont
dans la collection. Les personnes prsentes dans la collection sont ranges dans le tableau personnes depuis lindice 0 jusqu lindice nbPersonnes-1 . Le tableau personnes doit toujours avoir la taille suffisante pour contenir les personnes de la collection. Pour cela, il est cr
initialement avec une taille arbitraire tailleInitiale=5 , puis chaque fois que la taille du
tabeau devient insuffisante, on le remplace par un tableau de taille double.
un objet de type Population
personnes
nbPersonnes
0
1
2
3
4
On se propose de rdiger une classe Rationnel qui reprsente les nombres rationnels (cest-dire les fractions p/q) dote des oprations classiques : somme, produit, quotient, test dgalit.
Voici la spcificationde la classe Rationnel :
class Rationnel {
public Rationnel(int a, int b)
// prrequis
: b!=0 (a et b de signe quelconque)
// constructeur
: cre un rationnel gal a/b
public Rationnel(int a)
// constructeur
: cre un rationnel gal a
public String toString()
// rsultat
: chane de caractre figurant this,
//
par exemple "-235/12" ou "235"
public static boolean egal(Rationnel x, Rationnel y)
// rsultat
: indique si x et y sont gaux
public static Rationnel somme(Rationnel x, Rationnel y)
// rsultat
: somme de x et y
public static Rationnel produit(Rationnel x, Rationnel y)
// rsultat
: produit de x par y
Universit de Rennes 1
187
Mise en uvre :
On dcide de reprsenter un rationnel au moyen de deux entiers, le numrateur p et le dnominateur
q. Pour simplifier, les entiers seront raliss au moyen du type int.
Afin de faciliter le test dgalit et pour profiter au maximum de lintervalle de reprsentation des
entiers, on impose les contraintes suivantes sur p et q :
Le dnominateur q est >0. Le signe du nombre rationnel est donc celui de lentier p (qui est quelconque).
Le rationnel 0 est reprsent par p=0 et q=1.
Pour un rationnel diffrent de 0, p et q sont tels que la fraction p/q est irrductible (p et q sont
premiers entre eux). Par exemple, 27/18 devra tre simplifi en 3/2.
Rdiger cette mise en uvre.
Exercice 10.5
188
Module A.P.I
Universit de Rennes 1
c)
Universit de Rennes 1
189
190
Module A.P.I
Universit de Rennes 1
CHAPITRE 11
11.1
tableau (ou, plus gnralement vecteur) : suite de donnes accessibles directement au moyen
dun indice entier.
liste : suite de donnes accessibles lune aprs lautre selon leur rang dans la suite.
ensemble : collection de donnes en vrac telle que toutes les donnes ont une valeur diff-
"zaza"
Une dfinition abstraite, encore appele spcification, qui dcrit les oprations quelle offre,
sans aucune allusion la moindre ralisation concrte des mcanismes mis en uvre pour raliser ces oprations.
Une ou plusieurs ralisations concrtes, encore appeles mises en uvre1, au moyen de donnes de types existants et de procdures.
Pour la mise en uvre, on utilise un type classe qui permet de dfinir des objets abstraits. Nous
avons dj vu que lencapsulation permet disoler la mise en uvre et lutilisation.
1. On dit implementation en anglais, et on dit implmentation (avec accent sur le e) en franglais.
Universit de Rennes 1
191
11.2
position 2
tte
e
queue
fin de parcours
tat de parcours
le positionner en tte de la liste (position 0 si elle existe, fin de parcourssi la liste est vide)
le positionner en queue de la liste (position n-1 si elle existe, fin de parcourssi la liste est vide)
passer la position suivante de la position courante. Ceci positionne en fin de parcourssi le
parcours est en queue.
queue
d
suivant
192
prcdent
Module A.P.I
Universit de Rennes 1
ajouter un lment par insertion la suite de la position courante du parcours. Ltat de parcours
//------------------------------------
vide
vide
Universit de Rennes 1
193
public ListeDEntiers()
// constructeur
: liste vide
Pour des raisons de modularit, la classe Parcours est une classe interne la classe ListeDEntiers . Nous verrons plus loin la notion de classe interne : cest simplement une classe dfinie
lintrieur dune autre classe.
194
Module A.P.I
Universit de Rennes 1
11.3
class utilisationDeListe {
public static void main(String[] arg) {
Dclaration et cration dune liste initialise vide :
ListeDEntiers uneListe = new ListeDEntiers();
Introduction de valeurs par la mthode ajouteEnQueue. Les instructions suivantes
construisent une liste contenant les carrs des nombres entiers de 1 9 :
for (int i=1; i<=9; i++) {uneListe.ajouteEnQueue(i*i);}
Recherche dans la liste du plus grand multiple dun nombre donn.
Pour cela il suffit de parcourir la liste partir de la queue.
System.out.print("recherche
du plus grand multiple
de j= ")
int j = Lecture.unEntier();
ListeDEntiers.Parcours p = uneListe.nouveauParcours();
p.queue();
while (!p.estEnFin()&&p.elementCourant()%j!=0) {
p.precedent();
}
Cet exemple illustre lutilisation dun parcours de liste :
la classe Parcours tant interne la classe ListeDEntiers, depuis lextrieur de la
classe il faut la nommer par :
ListeDEntiers.Parcours
Aprs la boucle, si le parcours p est en fin, cela signifie quil ny a pas de multiple dej.
Sinon llment courant du parcours p est la valeur cherche :
if (p.estEnFin()) {
System.out.println(j+"
na pas de multiple
dans la liste");
}
else {
System.out.print("plus grand multiple de "+j+ "
:);
System.out.println(p.elementCourant());
}
Modification dlments :
lexemple suivant ajoute 1 aux multiples de 3 dans la liste.
p.tete();
while (!p.estEnFin()) {
int v=p.elementCourant();
if (v%3==0) {p.modifElement(v+1);}
p.suivant();
}
Impression en clair de la liste :
System.out.println(uneListe.toString());
Suppression dlments :
suppression de tous les multiples de 4 de la liste :
p.tete();
while (!p.estEnFin()) {
if (p.elementCourant()%4==0) {p.retireElement();}
else {p.suivant();}
}
}
}
Universit de Rennes 1
195
196
Module A.P.I
Universit de Rennes 1
11.4
11.4.1
12
maillon de tte
maillon de queue
12
null
12
null
Dans le cas dun maillon associ llment de tte, precedent vaut null (il ny a pas de prcdent) et dans le cas dun maillon associ llment de queue, suivant vaut null (il ny a pas de
suivant). La dfinition de la structure Maillon est :
class Maillon {
int element; Maillon suivant; Maillon precedent;
Maillon(Maillon s, Maillon p, int e) {
element=e; suivant=s; precedent=p;
}
}
La liste est alors reprsente par deux rfrences :
Universit de Rennes 1
197
une liste
12
tete
45
19
23
null
null
queue
La rfrence llment de queue est redondant : on pourrait sen passer et le retrouver en parcourant les maillons partir de la tte. Mais on la conserve pour une meilleure efficacit car elle
permet davoir un accs immdiat la queue de la liste.
Il faut bien sr se mfier du cas particulier de la liste vide. La liste vide est simplement reprsente
par tete=null et queue=null (il ny a aucun lment, donc aucun maillon).
une liste vide
tete
null
queue
null
aprs
tete
null
tete
queue
null
queue
nouveau maillon
12
null
null
tete et queue doivent recevoir la rfrence au nouveau maillon cr pour llment rajout.
198
Module A.P.I
Universit de Rennes 1
45
tete
queue
aprs
nouveau maillon
12
tete
exPremier
45
null
queue
La variable tete et le champ precedent de exPremier (le maillon de tte avant lajout) doivent recevoir la rfrence au nouveau maillon. La variable queue reste inchange dans ce cas.
Cette analyse conduit la rdaction suivante pour la mthode ajouteEnTete :
public void ajouteEnTete(int nouvelElement) {
if (tete==null) {
// cas liste vide
tete = new Maillon(null,null,nouvelElement);
queue = tete;
}
else {
// chane en tete
Maillon exPremier = tete;
tete = new Maillon(exPremier,null,nouvelElement);
exPremier.precedent=tete;
}
}
La mthode ajouteEnQueue sobtient par une analyse similaire. Il suffit dchanger les vocables
tete et queue ainsi que precedent et suivant :
public void ajouteEnQueue(int nouvelElement) {
if (queue==null) {
// cas liste vide
queue = new Maillon(null,null,nouvelElement);
tete = queue;
}
else {
// chaine en queue
Maillon exDernier = queue;
queue = new Maillon(null,exDernier,nouvelElement);
exDernier.suivant=queue;
}
}
Pour le retrait de llment de tte, tete reoit la rfrence au maillon suivant de tete. Il faut
galement grer correctement le chanage des prcdents. Dans le cas o la liste ne devient pas
Universit de Rennes 1
199
tete
45
null
queue
aprs
45
null
tete
queue
tete
queue
aprs
tete
null
queue
null
200
Module A.P.I
Universit de Rennes 1
Une raison est de ne pas alourdir le texte des mthodes susceptibles de provoquer une erreur.
Une autre est de considrer que cest lutilisateur de la classe de ne pas provoquer derreur, et
on lui a clairement indiqu dans les spcifications quelles sont les oprations interdites.
Une dernire raison est que, tant donne la mise en uvre, ces erreurs seront dtectes car elles
conduisent tenter daccder un maillon dsign par la rfrence nulle, ce qui provoque une
erreur null pointer exception signale par le langage lexcution.
11.4.2
Parcours de listes
45
19
null
23
null
queue
Universit de Rennes 1
201
de p
Les positionnements sur llment suivant et prcdent donnent lieu une erreur si le parcours est
en fin. Sinon, il suffit daffecter courant respectivement par la rfrence au maillon suivant ou
prcdent, cest--dire par les valeurs contenues dans les champs suivant ou precedent du
maillon courant :
public void suivant() {courant=courant.suivant;}
public void precedent() {courant=courant.precedent;}
202
Module A.P.I
Universit de Rennes 1
avant
aprs
un parcours
courant
un parcours
null
courant
sa liste
sa liste
tete
suivant du
nouveau
queue
nouveau maillon
12
tete
null
queue
suivant du
nouveau
Si le parcours nest pas en fin, llment doit tre insr la suite de llment courant. Dans ce cas
le suivant du nouveau maillon est le suivant du courant, son prcdent est le maillon courant et le
champ suivant du maillon courant doit recevoir la rfrence au nouveau maillon :
avant
aprs
un parcours
un parcours
courant
courant
nouveau maillon
12
45
45
suivant du
nouveau
suivant du
nouveau
Dautre part, dans tous les cas, le nouvel lment doit devenir llment courant du parcours. Cela
est ralis en affectant courant avec la rfrence au nouveau maillon.
Il reste grer correctement le chanage permettant le passage au prcdent. Dans le cas o le suivant du nouveau maillon nest pas null, le champ precedent du suivant du nouveau maillon
reoit la rfrence au nouveau maillon.
un parcours
courant
nouveau suivant du
maillon nouveau
94
12
Universit de Rennes 1
203
Dans le cas o le suivant du nouveau maillon est null, cela signifie que le nouvel lment est llment de queue. Cest donc la variable queue qui reoit la rfrence au nouveau maillon.
un parcours
courant
sa liste
tete
nouveau
maillon
12
null
queue
204
Module A.P.I
Universit de Rennes 1
-dire sil vaut null, cela correspond au cas o on retire llment de queue. Le prcdent du courant devient la nouvelle queue et cest donc la variable queue de la liste qui doit recevoir la valeur
du champ precedent du courant (ouf !).
Le parcours doit se positionner sur llment suivant llment supprim (ou en fin de parcours si on
vient de supprimer la queue). Dans tous les cas, cela se fait simplement en affectant la variable
courant du parcours avec la rfrence au suivant de llment supprim.
retrait dans le milieu
avant
le parcours
le parcours
courant
courant
45
aprs
12
94
45
94
retrait en tte
le parcours
avant
le parcours
courant
la liste
avant
courant
12
94
94
la liste
tete
tete
queue
queue
De cette analyse rsulte la programmation suivante. Comme cest souvent le cas, le programme est
plus simple que les explications qui le justifient :
public void retireElement() {
Maillon suivant=courant.suivant;
Maillon precedent=courant.precedent;
if (precedent!=null) {precedent.suivant=suivant;}
else {tete=suivant;}
if (suivant!=null) {suivant.precedent=precedent;}
else {queue=precedent;}
courant=suivant;
}
Universit de Rennes 1
205
11.5
class C {
...
A.B b;
...
}
Les vocables private et public sappliquent aux classes internes. Une classe interne public
est utilisable depuis toute classe, alors quune classe interne private nest utilisable que depuis le
texte de la classe englobante. Cela permet de cacher les classes internes qui sont des outils destins
ntre utiliss que par la classe englobante, pour une mise en uvre particulire de labstraction
reprsente par cette classe.
Exemple : la classe Maillon , interne la classe ListeDEntiers , nest quun outil de mise en
uvre des listes. Elle na pas tre propose lextrieur de la classe ListeDEntiers , cest une
notion qui doit rester totalement trangre aux utilisateurs de la classe ListeDEntiers . La
classe Maillon est donc private .
Autre exemple : en revanche, la classe Parcours , galement interne la classe ListeDEntiers, reprsente une notion offerte aux utilisateurs de la classe ListeDEntiers . Cela fait
partie de labstraction liste de pouvoir tre parcourue au moyen dun Parcours . Les utilisateurs
des listes vont explicitement utiliser des objets de type Parcours . La classe Parcours est donc
public .
class ListeDEntiers {
private static class Maillon {
}
public class Parcours {
}
...
Maillon m;
...
}
class UtiliseListes {
...
ListeDEntiers uneListe;
...
ListeDEntiers.Parcours p;
...
}
206
Module A.P.I
Universit de Rennes 1
de lobjet de la classe englobante propos duquel lobjet de la classe interne a t cr (on lappelle
instance courante de la classe englobante). Par exemple, depuis la classe Parcours , on utilise
tete et queue : ces identificateurs dsignent directement les variables tete et queue de lobjet
de type ListeDEntiers auquel cet objet de type Parcours est attach.
Une image que lon peut donner de cette notion de classe interne dynamique est celle dune usine
fabriquer des objets rattache chaque objet de la classe englobante. Ainsi, chaque objet de type
ListeDEntiers possde une usine fabriquer des parcours sur cette liste.
liste A
liste B
parcours 1 de liste A
parcours 2 de liste A
parcours 1 de liste B
parcours 2 de liste B
parcours 3 de liste B
Pour des raisons de structuration, il est prfrable que les objets de la classe interne soient crs par
des mthodes de la classe englobante. Cest ce que nous avons fait pour les parcours de listes : la
classe ListeDEntiers possde les mthodes nouveauParcours qui rendent en rsultat un
nouvel objet de type Parcours oprant sur la liste laquelle on applique la mthode. On peut
appeler ces mthodes des fabricateurs. Elle encapsulent des appels aux vrais constructeurs, pour
des raisons de modularit et de contrle lors de la cration (ici il ny a pas de contrle, mais il pourrait y en avoir) :
public class ListeDEntiers {
...
public Parcours nouveauParcours() {
// un nouveau parcours initialis au dbut de la liste
return new Parcours();
}
public Parcours nouveauParcours(Parcours p) {
// nouveau parcours initialis ltat de parcours de p
return new Parcours(p);
}
}
...
La premire mthode, la plus utilise, cre un parcours positionn sur le dbut de la liste (ou dans
ltat estEnFin si la liste est vide).
La deuxime mthode cre un parcours positionn dans le mme tat quun autre parcours p pass
en paramtre. Cela peut tre utile pour effectuer certaine recherches complexes dans une liste.
Universit de Rennes 1
207
Exercice 11.1
Manipulations de listes
Faire tourner sur un schma chacune des procdures suivantes et indiquer ce quelles font.
import list.*;
class ManipulationDeListes {
static ListeDEntiers carres(int j) {
ListeDEntiers c = new ListeDEntiers();
for(int i=1;i<=j;i++){c.ajouteEnQueue(i*i);}
return c;
}
static int p1(int j) {
ListeDEntiers c = carres(9);
ListeDEntiers.Parcours
p= c.nouveauParcours();
p.queue();
while(!p.estEnFin()){
int i=p.elementCourant();
if (i%j==0){ return i;}
else { p.precedent();}
}
return 0;
}
static ListeDEntiers p2(){
ListeDEntiers l = carres(9);
ListeDEntiers.Parcours
p= l.nouveauParcours();
while(!p.estEnFin()){
int i=p.elementCourant();
if (i%3==0) { p.modifElement(i+1);}
p.suivant();
}
return l;
}
static ListeDEntiers p3(){
ListeDEntiers resul = carres(9);
ListeDEntiers.Parcours
p= resul.nouveauParcours();
p.queue();
while(!p.estEnFin()){
int i=p.elementCourant();
if (i%4==0) { p.retireElement();}
p.precedent();
}
return resul;
}
}
208
Module A.P.I
Universit de Rennes 1
Exercice 11.2
Soient L1 et L2 deux listes dentiers, tries par ordre croissant de la tte la queue.
On veut construire la liste L qui contient tous les lments de L1 et L2 trie par ordre croissant.
exemple :L1 = 0 1 3 5 12
L2 = 1 2 5 13 15 16
L = 0 1 1 2 3 5 5 12 13 15 16
Rdiger une fonction qui rend en rsultat la liste L ainsi construite.
Exercice 11.3
Afin de construire des arbres gnalogiques, on se propose de rdiger la classe Personne qui
satisfait aux spcifications suivantes :
Une personne possde un nom, un pre, une mre et des enfants. Lors de la cration dune
personne on indique son nom, son pre et sa mre. La liste de ses enfants est initialise vide et
cette personne est rajoute dans la liste des enfants de son pre et de sa mre.
nom
Adam
pre ?
mre ?
enfants
nom
Abel
pre .
mre .
enfants
nom
Eve
pre ?
mre ?
enfants
nom
Cain
pre .
mre .
enfants
nom
Ida
pre .
mre .
enfants
On dispose de la classe ListeDePersonnes , dote des mmes fonctionnalits que ListeDEntiers (sauf que les lements sont des refrences des objets de type Personne )
Rdiger la classe Personne et un programme principal de test qui cre la population illustre sur
la figure, puis imprime la liste des enfants de la grand-mre paternelle de Ida.
Exercice 11.4
Compression - dcompression
Certaines applications utilisent des suites de donnes dans lesquelles de nombreuses valeurs successives sont identiques. Cest par exemple le cas pour reprsenter des images formes de grandes plages de mme couleur. Une telle suite de valeurs entires est reprsente sous forme compresse de
la faon suivante : chaque sous-suite de k lments conscutifs gaux de valeur e est reprsente
dans la liste compresse par k suivi de e. Exemple :
La compression de la suite L=<6, 6, 6, 6, 6, 2, 3, 3, 3, 3, 1, 1> est la suite <5, 6, 1, 2, 4, 3, 2, 1> car
L contient cinq 6 suivi de un 2 suivi de quatre 3 suivi de deux 1.
Rdiger la fonction compression qui rend en rsultat la compression dune liste dentiers passe
en paramtre. Le rsultat devra tre une nouvelle liste cre par la fonction.
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
209
Exercice 11.5
Renault
54
nombreDindividus
Leblanc
42
Martin
12
Piron
86
Durand
76
210
Module A.P.I
Universit de Rennes 1
CHAPITRE 12
Un fichierest une collection de donnes stocke de faon persistante sur un support priphrique
(disque, disquette, bande magntique, CDROM, etc...). Sur un mme support on peut mettre plusieurs fichiers, do la ncessit de nommer un fichier et parfois son support galement.
L'utilisation des fichiers rpond trois besoins principaux :
Les relevs pluviomtriques ou de tempratures d'une rgion sont stocks sur fichiers, ce qui
La structure des fichiers est trs spcifique chaque langage de programmation. Nous prsentons
ici uniquement les fichiers squentiels de texte.
12.1
1. Le terme binaire est mal choisi, car toute information, en mmoire ou sur fichier, est reprsente par des successions de
bits. Un terme plus juste serait codage brut ou spcifique, qui ne passe pas par lintermdiaire de caractres pour
reprsenter linformation.
Universit de Rennes 1
211
Bien que compos physiquement dune suite de caractres, un fichier texte peut contenir tous types
dinformation. Il suffit davoir une convention de reprsentation des divers types de donnes sous
forme de chanes de caractres et de disposer des fonctions de conversion correspondantes. Pour les
types de base, on utilise les conventions naturelles dj pratiques pour les lectures clavier et les
critures cran : notation dcimale pour les entiers, notation avec point et exposant pour les rels,
true et false pour les boolens...
Un avantage des fichiers textes, en plus de la compatibilit avec tous les langages de programmation, est la lisibilit humaine des informations. Les informations sont crites en clair, sous
forme de chanes de caractres que lon peut lire ou construire avec tout diteur de texte disponible
sur tout ordinateur. Ainsi, moyennant la connaissance de certaines conventions propres la gamme
dapplication manipulant ces fichiers, ils sont comprhensibles par un lecteur humain.
Par exemple, un fichier contenant les noms et les ges dune population se prsentera ainsi :
toto 12 jules 14 alfred 18 marcel 9
et pour le lire il suffira dexcuter, comme pour une entre depuis le clavier, les procdures spcifiques de lecture suivantes :
...lireChaine()... lit le nom "toto" sous forme dune donne de type String
puis ...lireUnEntier()... lit lge 12 sous forme dune donne de type int
puis ...lireChaine()... lit le nom "jules" sous forme dune donne de type String
puis ... lireUnEntier()
lit...
lge 14 sous forme dune donne de type int
etc...
12.2
12.2.1
212
Module A.P.I
Universit de Rennes 1
La mthode finDeFichier permet de savoir si on est en fin de fichier, cest--dire si tous les
caractres ont t lus. Le rsultat de cette mthode sert souvent dargument pour terminer une boucle qui lit le fichier.
La mthode fermer clt laccs au fichier. Une fois ferm, cest une erreur que de chercher
accder au fichier par cet accs. Une programmation saine ferme les fichiers avant de terminer
lexcution du programme, bien que a marche souvent si on ne le fait pas pour un accs en lecture.
La lecture du fichier donn en exemple pourrait tre ralis par la boucle suivante :
LectureFichierTexte population
= new LectureFichierTexte("lesEnfants.txt");
...
while (!population.finDeFichier()) {
String nom = population.lireChaine();
int age = population.lireUnEntier();
... traitement des donnes lues nom et age ...
}
population.fermer();
...
Universit de Rennes 1
213
12.2.2
void
void
void
void
void
ecrire(char c)
ecrire(String s)
ecrire(int k)
ecrire(boolean b)
ecrire(double x)
La mthode fermer clt laccs au fichier. Lopration fermer est ici essentielle : si on ne lexcute pas, les informations ne sont pas conserves dans le fichier.
Voici, titre dexemple, un programme qui cre un fichier appel lesEntiers.txt contenant
les nombres entiers de 0 39 avec, pour chacun deux, lindication sil est pair ou non. Aprs excution, le fichier contiendra :
0 est pair
1 est pair
2 est pair
...
38 est pair
39 est pair
: true
: false
: true
: true
: false
class TestEcriture {
public static void main(String[] arg) {
EcritureFichierTexte sortie =
new EcritureFichierTexte("lesEntiers.txt");
for (int i=0; i<40; i++) {
sortie.ecrire(i);
sortie.ecrire(" est pair
: ");
sortie.ecrire((i%2)==0);
sortie.ecrire('\n'); passage la ligne par criture explicite de '\n'
}
sortie.fermer();
}
}
214
Module A.P.I
Universit de Rennes 1
Exercice 12.1
Rdiger un programme qui lit un fichier entree contenant des entiers et crit dans un fichier sortie
les carrs des valeurs lues.
Le nom (ou le chemin) du fichier entree sera donn au clavier et le nom du fichier sortie sera fabriqu en ajoutant au nom du fichier dentre le suffixe ".carre ".
Exercice 12.2
Il est courant de recevoir des messages o les caractres accentus ont t saisis de la faon
suivante :
Bonjour He'le`ne,
vas-tu e^tre disponible pour aller to^t sur l'i^le de Bre'hat,
ou` il fait beau a` Noel
On souhaite raliser un programme pour transcrire ces messages sous la forme plus lisible :
Bonjour Hlne,
vas-tu tre disponible pour aller tt sur l'le de Brhat,
o il fait beau Nol
Les accentuations possibles sont a avec (, ^), e avec (, , ^, ), i avec (^, ), o avec (^, ) et u
avec (,^, ).
Remarque : on ne cherche traiter ni les majuscules accentues ni le caractre .
Le texte original sera contenu dans un fichier d'entre et le rsultat sera
crit dans un fichier de sortie.
Universit de Rennes 1
215
216
Module A.P.I
Universit de Rennes 1
CHAPITRE 13
13.1
la mise en uvre, mais sans relation dordre sur les lments, la recherche dun lment est
ncessairement proportionnelle la taille de lensemble (en moyenne), alors quil est proportionnel au logarithme de la taille si on opre sur une collection trie (voir les exercices concernant la recherche par dichotomie). Les oprations ensemblistes dunion, dintersection et de
diffrence prennent un temps proportionnel au produit des tailles des ensembles oprandes dans
le cas densembles non tris, alors quil ne prennent quun temps proportionnel la taille des
oprandes si les ensembles sont tris. Ces rapports de performance sont considrables ds que la
taille des ensembles devient importante.
Nous prsentons ici des ensembles dentiers, raliss par la classe EnsembleDEntiers . Bien
videmment on peut imaginer les mmes fonctionnalits pour des ensembles de nimporte quel type
dlments, pourvu que ce type soit dot des oprations de comparaison dgalit et de supriorit.
La classe EnsembleDEntiers ralise des ensembles modifiables: ce sont des objets dont ltat
est un ensemble fini, ventuellement vide, de valeurs entires. On peut le faire voluer en taille en
ajoutant ou en retirant un lment.
Comme pour les listes, cette classe offre une classe interne EnsembleDEntiers.Parcours
qui permet de crer des objets pour parcourir un ensemble par ordre croissant de ses lments.
Universit de Rennes 1
217
// constructeur
// rsultat
// rsultat
: ensemble vide
(aucun
effet
si e nest
pas
dans
th
de e1
218
//================================================================
public class Parcours {
public void tete()
// effet
: positionne this sur le plus petit lment
public void suivant()
// effet
: positionne this sur lelment suivant
public boolean
estEnFin()
// rsultat
: indique
si this est termin
public int elementCourant() // prrequis
: this nest pas en fin
// rsultat
: lment courant de this
public void retireElement() // prrequis
: this nest pas en fin
// effet
: retire llment courant de this
} //==============================================================
Module A.P.I
Universit de Rennes 1
13.2
12
25
suivant
debut
ou cration
32
74
estEnFin
EnsembleDEntiers.Parcours p
On peut prendre comme exemple dapplication la rdaction dune fonction inclus qui indique si
un ensemble e1 est inclus dans un ensemble e2. Lalgorithme de cette fonction consiste parcourir
lensemble e1 et vrifier que chacun de ses lments appartient e2 :
static boolean inclus(EnsembleDEntiers e1, EnsembleDEntiers e2) {
EnsembleDEntiers.Parcours p = e1.nouveauParcours();
boolean estInclus=true;
while(!p.estEnFin() && estInclus) {
if(!e2.contient(p.elementCourant())){estInclus=false;}
p.suivant();
}
return estInclus;
}
13.3
Universit de Rennes 1
219
220
Module A.P.I
Universit de Rennes 1
Remarque : la reprsentation au moyen dun tableau nest pas efficace en ce qui concerne lajout et
le retrait dlments : linsertion pour lajout et le tassement pour le retrait sont des oprations qui
ncessitent en moyenne un temps proportionnel la taille de lensemble. Une reprsentation plus
efficace utilise un arbre binaire ordonn et quilibr, appel arbre AVL, dont la mise en uvre
sort du cadre de ce cours.
place suffisante
ajouteElement(9)
elements
nbElements
4
26
53
elements
nbElements
4
9
26
53
place insuffisante
ajouteElement(12)
elements
nbElements
4
9
26
53
elements
nbElements
4
9
26
53
4
9
12
26
53
Universit de Rennes 1
221
Mthode retireElement
Le retrait dun lment prsente des difficults similaires. Il faut commencer par tester si llment
appartient lensemble, sinon il ny a rien faire. Le test dappartenance ayant donn lindice de
llment retirer, on utilise cet indice en appelant une procdure prive retireIemeElement
qui retire le ime lment.
public void retireElement(int e) {
// retire e de this (aucun effet si e nest pas dans this)
int k = indiceDe(e);
if (k!=-1) {retireIemeElement(k);}
}
Lorsque le nombre dlments devient plus petit que la moiti de la taille du tableau, un nouveau
tableau plus petit est cr de faon ne pas encombrer inutilement la mmoire. Lancien tableau,
sauf llment retir, est recopi dans le nouveau. Dans le cas o un tableau plus petit nest pas
recr, le tableau est simplement tass dune position partir de lindice de llment supprim. Il
y a un cas particulier lorsque lensemble devient vide, car on a dcid de reprsenter lensemble
vide par aucun tableau. Dans ce cas, la rfrence au tableau est mise null.
cas de cration dun tableau plus petit
retireElement(12)
elements
nbElements
4
9
12
26
53
elements
nbElements
4
9
26
53
4
9
12
26
53
4
9
26
53
elements
nbElements
4
26
53
222
Module A.P.I
Universit de Rennes 1
Oprations ensemblistes
La ralisation des oprations ensemblistes, union, intersection et diffrence, profite du fait que les
tableaux sont tris par ordre croissant. Puisque lon parcourt les lments des ensembles oprandes
par ordre croissant, on gnre les lments du rsultat galement par ordre croissant. Chaque lment du rsultat est donc ajout au bout du tableau, la suite de ceux dj prsents. On utilise
pour cela une procdure outil ajouteAuBout qui ajoute un lment au bout du tableau reprsentant le rsultat. Cette procdure double la taille du tableau chaque fois que cest ncessaire.
private void ajouteAuBout(int e) {
if (elements!=null && nbElements<elements.length){
// place suffisante
elements[nbElements]=e;
}
else if (nbElements==0) {
elements= new int[taillePourSingleton]; elements[0]=e;
}
else {
// place insuffisante, cration dun nouveau tableau
int[] nouveau
= new int[facteurDeCroissance*elements.length];
for (int i=0;i<nbElements;i++) {nouveau[i]=elements[i];}
nouveau[nbElements] = e;
elements=nouveau;
}
nbElements++;
}
Nous avons choisi de raliser les oprations ensemblistes sous forme de fonctions pures, et non pas
par modification dun des oprandes. Le rsultat est donc un nouvel ensemble cr par lopration.
Fonction union
Lunion est ralise comme le montre lexemple suivant :
e1 1 2 3 5 6
e2 2 4 5
union 1
e1 1 2 3 5 6
e2 2 4 5
union 1 2
e1 1 2 3 5 6
e2 2 4 5
union 1 2 3
e1 1 2 3 5 6
e2 2 4 5
union 1 2 3 4
e1 1 2 3 5 6
e2 2 4 5
union 1 2 3 4 5
e1 1 2 3 5 6
e2 2 4 5
union 1 2 3 4 5 6
Universit de Rennes 1
223
e1 1 2 3 5 6
e2 2 4 5
inter. 2
e1 1 2 3 5 6
e2 2 4 5
inter. 2
e1 1 2 3 5 6
e2 2 4 5
inter. 2
e1 1 2 3 5 6
e2 2 4 5
inter. 2 5
e1 1 2 3 5 6
e2 2 4 5
inter. 2 5
e1 1 2 3 5 6
e2 2 4 5
dif. 1
e1 1 2 3 5 6
e2 2 4 5
dif. 1
e1 1 2 3 5 6
e2 2 4 5
dif. 1 3
e1 1 2 3 5 6
e2 2 4 5
dif. 1 3
e1 1 2 3 5 6
e2 2 4 5
dif. 1 3
e1 1 2 3 5 6
e2 2 4 5
dif. 1 3 6
224
Module A.P.I
Universit de Rennes 1
Mthode toString :
public String toString() { //reprsentation en clair
if (estVide()) {return "{}";}
StringBuffer resul = new StringBuffer("{| "+ elements[0]);
for (int i=1; i<nbElements; i++) {
resul.append(" , " + elements[i]);
}
resul.append(" |}"); return resul.toString();
}
Mthodes de cration de parcours :
public Parcours nouveauParcours() {
// rsultat
: nouveau parcours initialis en dbut densemble
return new Parcours();
}
public Parcours nouveauParcours(Parcours p) {
// rsultat
: nouveau parcours initialis ltat de p
return new Parcours(p);
}
public
public
public
public
public
Universit de Rennes 1
225
Exercice 13.1
Manipulation densembles
Exercice 13.2
E,int
On se propose de reprsenter les polynmes coefficients entiers. Afin de reprsenter de faon conomique les polynmes de degr important mais dont la plupart des coefficients sont nuls, on
dcide de raliser une mise en uvre de la classe Polynome au moyen dune liste de paires
dentiers <ci,di> o ci est le ime coefficient non nul par ordre croissant des degrs et di est le degr
correspondant.
Exemple : le polynme 6x45 + 33x12 + 5x + 1
sera reprsent par la liste de paires dentiers : <1,0> <5,1> <33,12> <6,45>
Le polynme nul sera naturellement reprsent par une liste vide.
La classe Polynome offre les fonctionnalits suivantes :
static Polynome zero
le polynme nul
static Polynome aPartirDe(int[] tab)
polynme indiqu par un tableau contenant alternativement les coefficients non nuls et les degrs
correspondants, par ordre dcroissant des degrs, tab = {cn,dn,...,c1,d1,c0,d0}. Ce constructeur
sera essentiellement destin programmer des test. Ainsi avec
int[] tab = {6,45,33,12,5,1,1,0};
Polynome.aPartirDe(tab)
rendra le polynme 6x45 + 33x12 + 5x + 1.
String toString()
forme textuelle en clair du polynme :
an*X^n +... + a2*X^2 + a1*X + a0 ( 0 si this est le polynome nul)
226
Module A.P.I
Universit de Rennes 1
a,int
Universit de Rennes 1
227
comme une valeur, par exemple comme lentier bien connu qui sappelle 12, et jamais personne na
eu faire new 12 .
La fonction Polynome.apartirDe(T)
Tests :
Il vaut mieux faire des tests entirement contenus dans un programme de test plutt que des tests
par lecture des donnes, pour des raisons vidente de reproductibilit et de gain de temps. Les tests
seront programms dans la procdure principale dune classe TestPolynome . On sefforcera
dinventer les tests les plus judicieux possibles. Un bon test nest pas un test qui sarrange pour que
a marche mais qui, au contraire, fait tout pour que a ne marche pas. Il faut certes tester les cas
habituels mais aussi tester les cas particuliers.
Exercice 13.3
On se propose de reprsenter des images constitues de points noirs ou blancs. Une telle image se
prsente comme un damier de points de taille hauteur largeur.
Chaque point est repr par sa position verticale h et horizontale l.
Le coin suprieur gauche a pour coordonnes (0,0).
largeur
hauteur
On dcide de reprsenter de telles images par une classe ImageBinaire dont les spcifications
sont donnes ci-aprs.
228
Module A.P.I
Universit de Rennes 1
: hauteur de this
: largeur de this
Pour la mise en uvre, on dcide de reprsenter une image au moyen dune matrice M de boolens
de taille hauteur largeur.
M[i][j] = true si le point (i,j) est noir,
M[i][j] = false si le point (i,j) est blanc.
Universit de Rennes 1
229
conn
la mthode toString qui rend en rsultat la chane de caractres qui visualise limage, en utilisant des caractres * pour les points noirs, des caractres . pour les points blancs et des passages la ligne \n pour terminer les lignes de limage. Par exemple, pour limage de gauche, le
rsultat est la chane de caractres de droite :
.**.................................
..***.............******............
...****............*******..........
....*****....*******************....
....**************************.****
....*************************...****
...****....************************.
..***........*******************....
.**..............*********..........
....................................
230
Module A.P.I
Universit de Rennes 1
et im est change en :
Principe :
On utilise une liste de paires dentiers aVisiter qui contient tout moment de lalgorithme un
ensemble de points qui restent visiter. Ces points visiter sont les points adjacents aux points
noirs dj rpertoris de la partie connexe en cours de construction. On initialise la liste aVisiter
avec un point noir de limage, par exemple le premier point noir rencontr en parcourant limage
ligne par ligne, de gauche droite et on met blanc ce point de limage. Ensuite, tant que la liste
aVisiter nest pas devenue vide :
on retire un point pt de la liste aVisiter ,
on noircit ce point pt dans limage rsultat,
on ajoute aVisiter les points noirs de limage adjacents pt et on les mets blanc dans
limage.
Lorsque la liste aVisiter est devenue vide, limage rsultat est totalement construite : elle contient tous les points noirs de limage origine connexes au premier point noir choisi.
Universit de Rennes 1
231
Exercice 13.4
logique dintervalles
On dispose des fonctions min et max qui rendent en rsultat respectivement le minimum et le
maximum de deux entiers passs en paramtres. On utilisera ces fonctions pour exprimer le plus
simplement possible les rponses aux questions suivantes.
Rdiger la fonction intersectionVide spcifie par :
static boolean intersectionVide(PaireDEntiers x, PaireDEntiers y)
// prrequis
: x et y reprsentent des intervalles dentiers
// rsultat
: indique si x et y sont dintersection vide
Rdiger la fonction IntervalleIntersection spcifie par :
static PaireDEntiers IntervalleIntersection
(PaireDEntiers x,
PaireDEntiers y)
// prrequis
: x et y reprsentent des intervalles
// dintersection non vide
// rsultat
: lintersection de x et y
232
Module A.P.I
Universit de Rennes 1
On dit que deux intervalles dentiers sont fusionnables sils ont une partie commune ou bien sils se
touchent. Exemples :
[2,6] et [3,9] sont fusionnables,
[2,6] et [3,5] sont fusionnables,
[2,6] et [7,9] sont fusionnables.
[2,6] et [8,12] ne sont pas fusionnables.
tant donns deux intervalles fusionnables x et y, on note fusion(x,y) lintervalle union des ensembles reprsents par x et y. Exemples :
fusion([2,6], [3,9]) = [2,9]
fusion([2,6], [3,5]) = [2,6]
fusion([2,6], [7,9]) = [2,9]
Rdiger la fonction fusionnable spcifie par :
static boolean fusionnable(PaireDEntiers x, PaireDEntiers y)
// prrequis
: x et y reprsentent
// des intervalles dentiers
// rsultat
:
// indique si x et y sont fusionnables
Rdiger la fonction fusion spcifie par :
static PaireDEntiers fusion(PaireDEntiers x, PaireDEntiers y)
// prrequis
: x et y sont fusionnables
// rsultat
: la fusion de x et y
x
y
5
4
10
8
20
14
25
17
On dcide de reprsenter un ensemble par un tableau de paires dentiers tab pour mmoriser ses
intervalles, par ordre croissant de leurs bornes, et une variable entire nbElements qui indique le
Universit de Rennes 1
233
x
tab
nbElements
3
null
10
tab
nbElements
2
20 25
null
null
14 17
Comme le montre ces exemples, le tableau tab nest pas ncessairement entirement utilis.
On dsire programmer une classe EnsembleDEntiers selon ce principe, dote des oprations
usuelles dunion et dintersection et de test dappartenance. Les spcifications de cette classe sont
donnes ci-dessous. Nous insistons sur le fait que les intervalles qui constituent un ensemble sont
non fusionnables deux deux et sont tris par ordre croissant dans tab.
class EnsembleDEntiers {
public static EnsembleDEntiers aPartirDe(int[] T)
// prrequis
: le tableau T contient alternativement
// les bornes inf et sup dintervalles non fusionnables,
// par ordre croissant des bornes
// rsultat
: lensemble constitu de ces intervalles
public boolean contient(int k)
// rsultat
: indique si k appartient this
public static EnsembleDEntiers intersection
(EnsembleDEntiers x, EnsembleDEntiers y)
// rsultat: lintersection de x et de y
234
Module A.P.I
Universit de Rennes 1
Opration dintersection
Rdiger et tester la fonction intersection qui rend en rsultat lensemble intersection de x et
de y. On utilisera un algorithme analogue celui vu en cours, qui consiste parcourir les collections dintervalles de x et y par ordre croissant, en progressant dans lensemble qui possde lintervalle de borne suprieure minimale (ou dans les deux si les bornes suprieures sont gales).
Exemple :
2
resul
10
20
14
7 8
25
17
4
En (1) on gnre [4,5] dans le rsultat et on progresse dans x sur lintervalle [7,10]. En (2) on gnre
[7,8] dans le rsultat et on progresse dans y. En (3) on ne gnre rien, car [7,10] et [14,17] sont
dintersection vide, et on progresse dans x. En (4) on ne gnre rien, car [14,17] et [20,25] sont
dintersection vide, et on progresse dans y. Aprs (4), cest termin car un des ensembles, y ici, est
entirement visit.
Pour la taille du rsultat, on utilisera la proprit suivante :
si x et y ne sont pas tous les deux vides,
nombreDIntervalles(intersection(x,y)) nombreDIntervalles(x) + nombreDIntervalles(y) - 1
Programmation de lunion
La fonction union , qui rend en rsultat lensemble union de x et de y, est un peu plus difficile
programmer. Le principe gnral est est le suivant : on progresse dans les ensembles x et y par ordre
croissant des bornes infrieures des intervalles ; chaque intervalle de x ou de y est soit fusionn au
dernier intervalle du rsultat sil est fusionnable avec celui-ci, soit ajout sil nest pas fusionnable.
Exemple :
x
y
resul
5
4
10
14
20
10
14
25
17
5
17 20
25
En (1) on gnre initialement [2,5] dans le rsultat et on progresse dans x. En (2) on fusionne [4,8]
[2,5] ce qui donne [2,8] et on progresse dans y. En (3) on fusionne [7,10] [2,8] ce qui donne
[2,10] et on progresse dans x. En (4) on gnre [14,17] dans le rsultat, car [14,17] et [2,10] ne sont
pas fusionnables, et on progresse dans y. En (5), on gnre [20,25] dans le rsultat, car [14,17] et
[20,25] ne sont pas fusionnables et cest termin.
En analysant cet exemple, on constate quil est souhaitable de se doter dune mthode :
private void cumuleAuBout(PaireDEntiers nouvelIntervalle)
qui, si nouvelIntervalle est fusionnable avec le dernier intervalle de this remplace ce dernier intervalle par sa fusion avec nouvelIntervalle , et sinon ajoute nouvelIntervalle
la suite dans le tableau.
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
235
x
?
5
6
10
20
11
19
25
26
complmentaire(x)
Exercice 13.5
On dsire manipuler les entiers naturels (positifs ou nuls) sans limitation de grandeur (si ce nest par
la capacit mmoire de lordinateur). Ces entiers ne sont bien sr pas reprsentables directement
dans des mots du calculateur qui sont de taille fixe (et petite, 32 ou 64 bits). Nous devons donc les
reprsenter par une classe GrandEntier dont voici les spcifications :
public class GrandEntier {
public static GrandEntier deValeur(int k)
// prrequis
: k>=0
// rsultat
: le GrandEntier de valeur k
public String toString()
// rsultat
: lcriture dcimale de this
public static int comparaison(GrandEntier x, GrandEntier y)
// rsultat
: -1 si x<y, 0 si x=y, +1 si x>y
public static GrandEntier somme(GrandEntier x, GrandEntier y)
// rsultat
: x + y
public static GrandEntier produit(GrandEntier x,GrandEntier y)
// rsultat
:xy
}
Mise en uvre
On dcide de reprsenter un grand entier par la liste de ses chiffres (dcimaux par exemple, bien
quune base plus grande soit plus conomique).
Exemple : lentier 6 227 020 800 sera reprsent par la liste <6,2,2,7,0,2,0,8,0,0>, chaque chiffre
tant un petit entier (compris entre 0 et 9 si la base est dcimale). On normalisera la reprsentation en sinterdisant les chiffres 0 en poids fort.
236
Module A.P.I
Universit de Rennes 1
CHAPITRE 14
Un arbre est une structure de donnes qui permet de conserver de linformation de manire hirarchique. Les arbres sont utiliss pour reprsenter des choses aussi diffrentes que :
Une expression arithmtique : (12-3*25)*8 + 4*5 est vue comme un nud + avec comme fils
les deux expressions, lune 12-3*25 et 4*5. A son tour, lexpression 12+3*25 est vue comme un
nud - avec comme fils les deux expressions, 12 et 3*25. Lexpression simple 12 est vue
comme une feuille de larbre (elle est atomique). Lexpression 3*5 est vue comme un nud *
avec comme fils les deux expressions, 3 et 25, toutes deux vues comme des feuilles...
+
*
12
25
Un texte documentaire, tel un cours ou un mode demploi : le document est dcoup en chapi-
Lordinateur
1 - Introduction
blabla1 blabla2
2 - Le matriel
2.1 - Lunit centrale
blabla3 blabla4 blabla5
2.2 - La mmoire
blabla6
2.3 - Le disque
blabla7
3 - Les logiciels
3.1 - Le systme
blabla8
3.2 - Les langages
3.2.1 - Java
blabla 9
3.2.2 - C++
blabla10
3.3.3 - Assembleur
blabla11
Lordinateur
Introduction
Les logiciels
Le matriel
Le systme
blabla1
blabla8
Lunit centrale
La mmoire
blabla6
blabla3
Les langages
blabla4
Le disque
blabla7
Java
blabla9
C++
Assembleur
blabla10
blabla11
blabla5
Universit de Rennes 1
237
14.1
Spcification de la classeArbreBinaire
Dans un premier temps nous allons nous intresser un cas simple darbres, les arbres binaires. Ce
sont des arbres dont les nuds ont exactement 2 fils, appels gauche et droite. Nous considrons ici
des arbres non modifiables. Un tel arbre est simplement une valeur structure que lon peut :
fabriquer laide de loprateur feuille( i) pour obtenir une feuille porteuse de linformation i,
fabriquer laide de loprateur noeud( i,g,d) pour obtenir un nud porteur de linformation
i et de fils g et d,
ou que lon peut obtenir en tant que sous-arbres gauche ou droite dun nud par les oprations
gauche et droite .
Voici la spcification propose pour la classe ArbreBinaire :
class ArbreBinaire {
public static ArbreBinaire
noeud(String info,ArbreBinaire g,ArbreBinaire d)
// rsultat
: le noeud <info,g,d>
public static ArbreBinaire feuille(String info)
// rsultat
: la feuille <info>
public static ArbreBinaire aPartirDe(String s)
// rsultat
: larbre binaire figur par s selon une notation
// parenthse prfixe
public boolean estNoeud()
// rsultat
: indique si this est un noeud
public boolean estFeuille()
// rsultat
: indique si this est une feuille
public String info()
// rsultat
: linfo associe this
public ArbreBinaire gauche()
// prrequis
: this est un noeud
// rsultat
: le fils gauche de this
public ArbreBinaire droite()
// prrequis
: this est un noeud
// rsultat
: le fils droite de this
public String toString()
// rsultat
: this en clair sous forme parenthse prfixe
238
Module A.P.I
Universit de Rennes 1
14.2
les informations associes aux nud sont des symboles dopration "+" et "*",
les informations associes aux feuilles sont des valeurs numriques exprimes en dcimal, par
exemple "3622" .
d12 = ArbreBinaire.feuille(12);
d56 = ArbreBinaire.feuille(56);
mulD12D56 = ArbreBinaire.noeud("*",d12,d56);
d24 = ArbreBinaire.feuille(24);
expr1=ArbreBinaire.noeud("+",mulD12D56,d24);
*
12
56
24
*
12
56
Universit de Rennes 1
239
14.3
sorte : lindication de sa sorte, nud ou feuille. Le type de cet attribut sera dun type numr
Sorte ,
feuille
"12"
?
?
sorte
info
gauche
droite
noeud
"*"
feuille
"12"
?
?
sorte
info
gauche
droite
feuille
"56"
?
?
240
Module A.P.I
Universit de Rennes 1
Les constructeurs sont privs : lutilisateur ne pourra faire new ArbreBinaire(...). Cest
une bonne discipline lorsque, comme cest la cas ici, on reprsente un domaine de valeurs et non
pas de vrais objets. On ne cre pas proprement parler un arbre, mais on le dnote au moyen
doprations telles que noeud , feuille ou aPartirDe . Cest comme pour les entiers, on ne
cre pas 12, on le dnote par 12 ou par 8+4 ou par 2*6...
Les opration les plus simples qui fabriquent des arbres sont feuille et noeud :
public static ArbreBinaire feuille(String info) {
// rsultat
: la feuille <info>
return new ArbreBinaire(info);
}
public static ArbreBinaire
noeud(String info,ArbreBinaire g,ArbreBinaire d){
// rsultat
: le noeud <info,g,d>
return new ArbreBinaire(info,g,d);
}
Lopration suivante aPartirDe permet dobtenir larbre dnot par une chane de caractres
sous forme parenthse prfixe :
Cette fonction nest pas simple raliser. En toute rigueur, sa ralisation exige une analyse syntaxique de la chane de caractres qui dnote larbre, mais cela nous emmnerait trop loin. Ici, on
peut profiter de ce que le prrequis nous garantit que la chane est correcte (sans erreur de
syntaxe) : on peut alors sen tirer au moyen de deux fonctions (prives) auxiliaires :
extraitInfo(String
quis)
rend en rsultat la sous-chane du dbut de s qui constitue la
donne info de larbre : cette sous-chane commence au dbut de s et sarrte soit la rencontre
du premier caractre sparateur '(' ou ',' ou bien la fin de s.
Exemples :
extraitInfo("add(mul(12,56),24)") vaut "add"
extraitInfo("12") vaut "12"
extraitMembre(String
s, int
qui rend
i) en rsultat la sous-chane de s qui commence en position i et reprsente un sous-arbre gauche ou droite dun noeud : cette souschane se termine sur le premier caractre sparateur ',' ou ')' rencontr qui ne soit pas
inhib par un prenthsage (...).
Exemples :
extraitMembre("add(mul(12,56),24)",4) vaut "mul(12,56)"
extraitMembre("add(mul(12,56),24)",15) vaut "24"
Universit de Rennes 1
241
On extrait la partie info en dbut de s. Si cette partie info est s dans son intgralit, s reprsente la
feuille feuille( info). Sinon s reprsente un nud : on extrait les chanes sg et sd qui reprsentent les fils gauche et droite et s reprsente le nud noeud( gauche,droite).
242
Module A.P.I
Universit de Rennes 1
Universit de Rennes 1
243
14.4
Comme le montre cet exemple, les parcours darbres sont naturellement rcursifs : pour remplacer
s1 par s2 dans un arbre qui est un nud, on utilise le remplacement de s1 par s2 dans les fils gauche
et droite et on recre le nud en remplaant ventuellement linformation associe.
244
Module A.P.I
Universit de Rennes 1
La fonction suivante value une expression arithmtique constitues doprations notes "+" et
"*", cest--dire rend le rsultat numrique du calcul suggr par lexpression :
static int eval(ArbreBinaire expr) {
// prrequis
: expr reprsente un expression entire
// avec "+" ou "*" pour info associes aux noeuds et des
// reprsentation dcimales de nombres associes aux feuilles
// rsultat
: lvaluation de expr
if(expr.estFeuille()) {return Integer.valueOf(expr.info());}
else /* expr.estNoeud() */ {
if (expr.info().equals("+")){
return eval(expr.gauche())+eval(expr.droite());
}
else /* expr.info().equals("*") */ {
return eval(expr.gauche())*eval(expr.droite());
}
}
}
On peut ainsi construire une expression et lvaluer :
ArbreBinaire expr=ArbreBinaire.aPartirDe("+(*(12,56),24)");
System.out.println("expr = "+expr);
System.out.println(
"expr.enClairInfixe() = "+expr.enClairInfixe());
System.out.println("eval(expr) = "+eval(expr));
Ce morceau de programme affiche :
expr = +(*(12,56),24)
expr.enClairInfixe() = ((12*56)+24)
eval(expr) = 696
14.5
Spcification de la classeArbre
Nous allons nous intresser maintenant aux arbres dont chaque nud peut avoir un nombre quelconque de fils. Ces arbres seront offerts par la classe Arbre . La spcification de la classe Arbre
ressemble beaucoup celle de ArbreBinaire . Les seules diffrences proviennent de la multiplicit quelconque des fils dun nud. Ces diffrences sont :
Universit de Rennes 1
245
qui rend en rsultat un parcours initialis sur le premier fils du nud; les fils pourront alors tre
obtenus par les mthodes usuelles dun parcours : elementCourant , suivant et le test
estEnFin .
class Arbre {
public static Arbre noeud(String info, Arbre[] fils)
// rsultat
: larbre noeud<info,fils[0]...>
public static Arbre feuille(String info)
// rsultat
: larbre feuille<info>
public boolean estNoeud()
// rsultat
: indique si this est un noeud
public boolean estFeuille()
// rsultat
: indique si this est une feuille
public String info()
// rsultat
: linfo associe this
public Parcours<Arbre> parcoursLesFils()
// prrequis
: this est un Noeud
// rsultat
: parcours initialis sur le premier fils de this
public static Arbre aPartirDe(String s)
// rsultat
: larbre binaire figur par s selon une notation
// parenthse prfixe
14.6
les informations associes aux nud sont des titres de chapitres de divers niveaux,
les informations associes aux feuilles sont les textes des paragraphes du document.
Voici un exemple dun tel document :
246
Module A.P.I
Universit de Rennes 1
Le monde animal
1 - Les mollusques
Ils sont mous
1.1 - les bivalves
ils ont deux valves
1.2 - Les gastropodes
Ils ont une coquille en colimaon
Ils ont deux cornes
2 - Les vertbrs
2.1 - Les poissons
Ils nagent
2.2 - les reptiles
Ils marchent ou rampent
Ils ont le sang froid
2.3 - Les mammifres
Ils ont le sang chaud
2.3.1 - Les ctacs
Ils nagent
2.3.2 - Les bovids
Ils marchent
Ils vivent dans les pturages
3 - Conclusion
voila cest fini
Universit de Rennes 1
deux
247
cornes)"
Le monde
animal(1
- Les mollusques(Ils
sont mous,1.1
- Les bivalves(Ils
ont
deux
valves),1.2
- Les
gastropodes(Ils
ont
une
coquille
en colimaon,Ils
ont deux cornes)),2
- Les vertbrs(2.1
Les poissons(ils
nagent),2.2
- Les reptiles(Ils
marchent
ou rampent,Ils
ont le sang froid),2.3
- Les mammifres(ils
ont le sang
chaud,2.3.1
- Les ctacs(Ils
nagent),2.3.2
- Les bovids(Ils
ma
chent,Ils
vivent
dans les pturages))),3
- Conculsion(voila
ces
fini))
Ce nest pas trs joli... mais linformation y est.
Un traitement que lon peut vouloir faire sur un tel document est de lindenter. Ceci consiste
rajouter un certain nombre despaces supplmentaires gauche chaque passage un niveau de
chapitrage infrieur. Cette fonction dindentation pourra tre ralise par la fonction suivante :
static String indente(Arbre a) {
// rsultat
: a en clair indent
return indente(a,0);
}
static String indente(Arbre a,int i) {
// rsultat
: a en clair indent de i espaces
if (a.estNoeud()){
String resul=blancs(i)+a.info()+"\n";
Parcours<Arbre> p = a.parcoursLesFils();
while(!p.estEnFin()){
resul=resul+indente(p.elementCourant(),i+4);
p.suivant();
}
return resul;
}
else /* a.estFeuille() */{
return blancs(i)+a.info()+"\n";
}
}
static String blancs(int i){
// rsultat
: une chane de i espaces
String resul="";
for(int k=0; k<i; k++){resul=resul+" ";}
return resul;
}
Cest une fonction naturellement rcursive. Plus exactement la fonction proprement rcursive est
static String indente(Arbre a,int i)
qui a un paramtre de plus, i, qui est la quantit initiale dsire despaces gauche.
La fonction static String indente(Arbre a) appelle cette dernire avec i=0.
248
Module A.P.I
Universit de Rennes 1
14.7
Sorte sorte;
Universit de Rennes 1
249
La ralisation de aPartirDe est un peu plus complexe. La mthode utilise est similaire celle
de ArbreBinaire , mais au lieu dextraire les chanes qui reprsentent les fils gauche et
droite dun nud, il faut extraire une quantit non dtermine lavance de chanes qui reprsentent les fils du nud.
250
Module A.P.I
Universit de Rennes 1
Universit de Rennes 1
251
252
Module A.P.I
Universit de Rennes 1
CHAPITRE 15
15.1
15.1.1
XII
une suite de deux chiffres dcimaux
12
1100
Il ne faut pas confondre nombre, entit abstraite, et reprsentation de nombre, marque concrte qui
permet de faire des calculs au moyen de machines (ventuellement humaines) excutant des algorithmes. Si on accepte cette distinction, il ny a pas de nombres dans les machines, et il ny en aura
jamais, il ny a que des reprsentations de nombres. Ce nest pas un problme technologique, cest
par nature quun nombre (ou toute autre entit abstraite) na pas sa place dans une machine.
15.1.2
Numrations positionnelles
Les reprsentations des nombres les plus utilises sont les reprsentations positionnelles. Dans une
telle reprsentation, on utilise une collection finie (et gnralement petite) de symboles appels
chiffres.
Universit de Rennes 1
253
2 3 4 5 6 7 8 9 A B C D E F ...
chiffres binaires
chiffres dcimaux
chiffres hexadcimaux
Le nombre de chiffres utiliss sappelle la base.
Les bases les plus utilises sont la base 2 (deux chiffres 0 et 1 appels chiffres binaires), la base 10
(dix chiffres de 0 9 appels chiffres dcimaux) et la base 16 (seize chiffres de 0 9 puis de A F
appels chiffres hexadcimaux).
La base 60 est galement utilise, de faon limite mais quotidienne, pour compter le temps en heures/minutes/secondes.
Dans une reprsentation positionnelle en base b, chaque chiffre on associe une valeur de 0 b-1 :
0 1 2 3 4 5 6 7 8 9 A B C D E F
val(c)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
chiffre
valeur entire
associe
Un nombre est reprsent par une succession de chiffres cn-1cn-2...c1c0. Le nombre reprsent est :
On a coutume dappeler interprtation la fonction qui va des marques concrtes de la reprsentation (succession de chiffres ici) vers les valeurs abstraites reprsentes (un nombre entier ici). Pour
distinguer les diverses fonctions dinterprtation associes aux diverses bases, nous avons plac la
base en indice du nom de la fonction.
Exemples :
interprtation en base 10 de 3058 :
interprtation10(3058) = 3103+0102+510 +8 = 3058
(on sy attendait)
254
Module A.P.I
Universit de Rennes 1
10
305
5
10
30
0
13
1
10
3
3
reprsentation10(3058) = 3058
10
0
(on sy attendait)
2
6
0
2
3
1
2
1
1
2
0
reprsentation2(13) = 1101
Les reprsentations positionnelles sont pratiques pour effectuer les calculs, notamment addition et
soustraction selon les algorithmes bien connus enseigns lcole primaire.
Une invention essentielle de ce mode de reprsentation fut le chiffre 0. Il sert, comme on le sait,
indiquer quil ny a aucun terme bi en position i. Son rle est donc essentiellement doccuper une
place o il ny a rien. Avant linvention du 0, il fallait user de priphrases pour citer certains
nombres : 246 scrivait 246, alors que 206 devait snoncer par quelque chose comme 2 centaines
et 6.
15.1.3
Hexadcimal
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
Exemple :
le nombre qui se reprsente en binaire par
0101 1011 0011 0001
se reprsente en hexadcimal par :
5B31
Remarque : ceci est une proprit gnrale. Le
passage de la reprsentation en base b la reprsentation en base bk se fait en regroupant les chiffres par paquets de k chiffres et en remplaant
chaque paquet par le chiffre correspondant de la
base bk. Ici nous sommes passs de la base b=2
la base bk=24=16.
Universit de Rennes 1
255
Mmoire
15.2
Mmoire
La mmoire est le composant dun ordinateur dans lequel le processeur range et rcupre les informations. Le plus petit lment de mmorisation est capable de conserver un bit. Cest un lment
lectronique deux tats stables dans lequel linformation est reprsente par un potentiel lectrique valant 0v ou +5v. Une mmoire de un bit permet donc la reprsentation dune valeur binaire,
selon une convention, par exemple 0 : 0v et 1 : +5v.
Les bits sont regroups en paquets de taille fixe appels mots.
Les tailles les plus courantes sont 8 bits, appel aussi octet (byte en anglais), 16 bits et 32 bits.
0110 0011 0100 1011 0000 1000 0101 0111
8 bits (octet)
16 bits
32 bits
Les mots dune mmoire sont reprs par un numro appel adresse. Depuis plusieurs annes,
loctet sest impos comme unit adressable. Pour lire ou crire des donnes dans la mmoire, le
processeur indique ladresse du mot concern et change la donne au moyen dun bus de donnes.
processeur
manipule les donnes
0
1
2
3
4
adresse
repre les donnes
0110
1110
0110
0000
0100
0011
0001
1011
1011
1111
0010 0011
0110 0001
15.3
caractres,
nombres entiers positifs,
nombres entiers relatifs,
nombres rels.
Dans un ordinateur, tous les types de donnes sont ncessairement reprsents par des suites finies
de bits. Une suite de n bits peut prendre 2n valeurs et peut donc reprsenter un domaine dau plus 2n
lments. part cette contrainte sur sa taille, le domaine reprsent peut tre quelconque : il suffit
dattribuer une signification particulire chacune des suites de bits.
256
Module A.P.I
Universit de Rennes 1
Exemples :
Avec 2 bits x1x0, on dispose de 22 = 4 valeurs, avec lesquels on peut reprsenter les domaines
suivants :
bits
ensemble de
ensemble de
x1x0
4 couleurs
4 lettres
4 nombres
00
rouge
avancer
01
bleu
reculer
10
vert
tourner
11
jaune
arrter
4 instructions
Comme le montrent ces exemples, une suite de bits (plus gnralement une collection de marques
concrtes) na pas de signification en soi. Cest seulement travers une interprtation particulire
quelle prend un sens. Il est important de remarquer que les interprtations ne sont pas du domaine
des machines. Ce sont toujours des tres humains, ou des phnomnes physiques dans le cas
dapplication de contrle dappareils, qui en dernier ressort interprtent linformation.
Dans les langages de programmation, cest grce en partie la notion de type que le programmeur
indique linterprtation quil attribue ses donnes. Ceci permet au compilateur de choisir la reprsentation convenable en terme de bits, et sert de garde fou en nautorisant sur ces reprsentations
que les oprations qui ont un sens dans le cadre de ces interprtations : addition et soustraction pour
les entiers, test pour les boolens, concatnation pour les chanes de caractres...
Exemple :
Avec les reprsentations sur 2 bits voques prcdemment, le programmeur ayant dclar une
variable coul, de type couleur , il pourra excuter laffectation coul=vert . Le compilateur
choisira une mmoire de deux bits dadresse coul (deux bits choisis dans un octet puisque la
mmoire est adressable par octets).
Laffectation :
sera traduite par le compilateur en :
coul=vert;
ranger dans la mmoire dadresse coul les bits 10
Le programmeur pourra utiliser toute opration ayant un sens pour les couleurs, par exemple les
fonctions estCouleurFroide ou estCouleurChaude rsultat boolen qui indiquent respectivement si une couleur est froide (vert, bleu) ou chaude (rouge, jaune). Il pourra crire :
if (estCouleurFroide(coul)) {...}
cela sera accept et traduit en
si la mmoire dadresse coul contient 01 ou 10 : ...
En revanche, le compilateur refusera linstruction :
coul = coul+1;
car cest un non-sens dincrmenter une couleur, bien que la machine sache incrmenter 10 pour
donner 11.
15.3.1
Universit de Rennes 1
257
tres sur 7 bits (128=27). La reprsentation est indique sur la table suivante :
b6-4
b3-0
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
110 111
`
p
a
q
b
r
c
s
d
t
e
u
f
v
g
w
h
x
i
y
j
z
k
{
l
m
}
n
o
DEL
Les 7 bits sont nots b6b5b4b3b2b1b0. Par exemple, 1000001 reprsente 'A', 1000010 reprsente
'B', 110001 reprsente 'a'... Certains caractres ne sont pas des marques imprimables mais des
caractres de contrle ou de mise en page : CR (Carriage Return) positionnement en dbut de ligne,
LF (Line Feed) passage la ligne suivante, BEL (Bell) sonnerie...
Ce jeu de caractres est cependant limit 127 lments. Il ne permet pas de reprsenter les caractres accentus ni les caractres spcifiques certaines langues.
Lunit de stockage est loctet, et non pas 7 bits. Lorsquune reprsentation ASCII de caractre est
range dans un octet, le bit de poids fort de loctet, le bit 7, inutilis, est mis 0. La reprsentation
ASCII tendue sur 8 bits permet dtendre le rpertoire 256 caractres.
Plus rcemment est apparue une nouvelle reprsentation, sur 32 et 16 bits, appele UNICODE.
Cest un standard destin remplacer peu peu lusage de lASCII. Il est deux fois plus coteux en
place mais il permet de reprsenter 216 caractres, soit plus de 65000, ce qui permet dinclure non
seulement les caractres accentus ou spcifiques certaines langues europennes, mais galement
tous les idogrammes des langues orientales. Pour faciliter le passage de la reprsentation ASCII
la reprsentation UNICODE, cette dernire est telle que les caractres du rpertoire ASCII sont
reprsents par les 7 bits de la reprsentation ASCII en poids faible, complts par des 0 en poids
forts :
0 0 0 0 0 0 0 0
UNICODE
0 b6 b5 b4 b3 b2 b1 b0
ASCII
15.3.2
258
Module A.P.I
Universit de Rennes 1
15.3.3
sentation binaire,
pour un nombre ngatif, de -2n-1 -1, la reprsentation en complment 2 de k est la reprsentation binaire de 2n-|k|.
exemple sur 4 bits
nombre complment 2
-8
1000
-7
1001
-6
1010
-5
1011
-4
1100
-3
1101
-2
1110
-1
1111
0
0000
1
0001
2
0010
3
0011
4
0100
5
0101
6
0110
7
0111
interp. binaire
8
9
10
11
12
13
14
15
0
1
2
3
4
5
6
7
En complment 2, le bit de rang n-1 (bit de poids fort) est significatif du signe :
Si xn-1=0, le nombre reprsent est positif et il vaut, comme en binaire, xn-2.2n-2+...+ x1.2 + x0
Si xn-1=1, le nombre reprsent est ngatif et il vaut -2n-1 +xn-2.2n-2+...+ x1.2 + x0
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
259
Pour cette raison on a coutume dappeler bit de signe le bit de poids fort dune suite de bits.
Une formule quivalente permtant dinterprter en complment 2 une suite de bits est :
interprtation en complment (xn-1xn-2....x1.x0) = -xn-12n-1 +xn-2.2n-2+...+ x1.2 + x0
cette formule considre simplement le chiffre de poids fort avec un poids ngatif.
Les avantages de cette reprsentation sont lunicit de la reprsentation de 0 et surtout que le mme
oprateur matriel daddition fonctionne aussi bien pour la reprsentation binaire simple que pour
la reprsentation en complment 2. Ceci est quasiment miraculeux : un seul oprateur, cest--dire
un seul algorithme, donne le bon rsultat pour les deux interprtations de ces suites de bits.
Exemple sur 4 bits :
opration machine
interprtation binaire
interprtation en complment 2
1001
+ 0011
9
+3
-7
+3
1100
12
-4
Sans chercher faire la dmonstration de cette proprit remarquable (ce genre de dmonstration
est assez pnible suivre, et sans grand intrt), on peut signaler quil sagit l de proprits arithmtiques des classes de congruence modulo 2n.
Dpassements de capacit
En fait, au lieu de dire que le mme oprateur marche aussi bien pour les deux reprsentations, on
devrait plutt dire quil ne marche pas plus mal pour lune que pour lautre. En effet, dans chacune des reprsentations il se pose le problme de dpassement de capacit : la somme peut sortir
de lintervalle de reprsentation. Bien videmment dans ce cas, le rsultat ne peut pas tre correct
puis quil nest pas reprsentable sur n bits.
Cest propos des dpassements de capacit que loprateur daddition diffre. Les conditions de
dpassement ne sont pas les mmes dans les deux reprsentations.
Pour la reprsentation binaire, le dpassement de capacit a lieu lorsque la somme des nombres
reprsents par les oprandes est suprieure ou gale 2n. Cette condition est dtecte sur la
machine par le fait que lalgorithme daddition binaire gnre un report 1 dans laddition des
chiffres de poids fort (carry en Anglais).
des nombres reprsents par les oprandes est soit strictement infrieure -2n-1, soit suprieure
ou gale 2n-1. Cette condition sappelle un dbordement (overflowen anglais). Elle peut tre
dtecte sur la machine de deux faons :
Premire faon : les oprandes sont de mme signe et le rsultat de lopration a un bit de signe
diffrent. De toute vidence le rsultat est incorrect dans ce cas. Ce qui est plus difficile cest de
montrer que ce sont l les seuls cas de dpassement.
260
Module A.P.I
Universit de Rennes 1
binaire complment 2
0110
+6
1110
14
-2
0011
+3
1011
11
-5
1001
-7
1001
-7
report = 0
correct
dbordnt=1
report = 1
incorrect
incorrect
dbordnt=0
correct
1011
+ 1
1100, reprsentation de -4
Cette proprit peut se justifier ainsi : si on considre la somme des interprtations en complment
2 dune suite de n bits xn-1...x1 x0 et de son complment bit bit /xn-1.../x1 /x0 on a :
interprtation(xn-1...x1 x0) + interprtation(/xn-1.../x1 /x0) = 111...11 = -2n-1 +2n-2+...+ 2 +1 = -1
Universit de Rennes 1
261
Reprsentations de 0 et de -1 :
Quelque soit le nombre de bits, la reprsentation de 0 est de la forme 000...0 (que des 0) et celle de
-1 est 111...1 (que des 1).
En Java il y a quatre types dentiers relatifs :
byte : sur 8 bits, reprsente lintervalle -128...+127,
short : sur 16 bits, reprsente lintervalle -32 668...+32 767,
int : sur 32 bits, reprsente lintervalle -2 147 483 648...+2 147 483 647,
long : sur 64 bits, reprsente lintervalle
-9 223 372 036 854 775 808 ...+9 223 372 036 854 775 807.
En Java, comme dans de nombreux autres langages de programmation, les oprations +, -, *, /
sont celle de larithmtique modulo 2n, n tant le nombre de bits de la reprsentation. Ceci signifie
que les dpassements de capacit ne provoquent pas de dtection derreur pendant lexcution mais
donnent le rsultat modulo 2n de lopration, compris entre -2n-1 et 2n-1-1.
Par exemple, pour le type byte, reprsent sur 8 bits :
lopration 127+1 donne -128, et 127+2 donne -1.
15.3.4
Module A.P.I
Universit de Rennes 1
signe
S
31 30
8 bits
exposant
E
23 bits
mantisse
M
23 22
Les 23 bits de mantisse sont lquivalent denviron 7 chiffres dcimaux, ce qui donne une prcision
relative d'environ 10-7, ce qui est peu (la moindre calculette est gnralement plus prcise).
Lexposant, reprsent sur 8 bits, peut prendre des valeurs comprises entre -126 et +127, ce qui
offre une tendue de 2127 1038
Flottant IEEE double prcision : la reprsentation occupe 64 bits, un bit pour le signe du nombre,
11 bits pour lexposant et 52 bits pour la mantisse.
signe
S
63 62
11 bits
exposant
E
52 bits
mantisse
M
52 51
Les 52 bits de mantisse sont lquivalent denviron 16 chiffres dcimaux, ce qui donne une prcision relative d'environ 10-16.
Lexposant, reprsent sur 11 bits, peut prendre des valeurs comprises entre -1022 et +1023, ce qui
offre une tendue de 21023 10308
Universit de Rennes 1
263
Interprtation flottante
Voici plus prcisment comment fonctionne la reprsentation, pour le cas du flottant simple prcision (cest le mme principe pour le double prcision en changeant les nombres de bits).
Pour une reprsentation normalise :
lexposant E est interprt en un entier e [-126,+127] selon la formule :
e = interprtation binaire(E)-127
Cette reprsentation particulire des entiers relatifs sappelle reprsentation par excs 127.
La mantisse M est interprte en un nombre fractionnaire m [1, 2 [ selon la formule :
m = 1 + interprtation binaire(M) / 2
23
La reprsentation de nombres non normaliss, pour reprsenter de tous petits nombres mais
avec une prcision relative dgrade.
La reprsentation de 0 : le rel 0 est reprsent par 0000......00.
La reprsentation de valeurs spciales : les infinis signs, les cas derreurs (appels NaNs abrviation du terme anglais Not a Number, cest--dire un non-nombre).
Toutes ces reprsentations spciales sont distingues des reprsentations normalises car elles ont
un exposant E de la forme 00000000 ou 1111111, formes non utilises pour les reprsentations normalises.
Voici quelques exemples :
reprsentation flottant
IEEE simple prcision
nombre
1 = +1.020= +1.0 2127-127
0.5 =
+1.02-1=
+1.0
2126-127
+1.52-1=
+1.5
2126-127
0 01111111 0000...0
0 01111110 0000...0
0 10000001 0000...0
0 01111110 1000...0
0 10000001 0010...0
2128-127
0 10000000 0110...0
2.75 = +1.3752=+1.375
Module A.P.I
Universit de Rennes 1
15.4
15.4.1
1000
adresseVigor + 0
1000
orientation
adresseVigor + 4
1004
adresseVigor + 12
1012
Universit de Rennes 1
265
15.4.2
adresseMusique - 4
2400000
musique.length
adresseMusique + 0
musique[0]
adresseMusique + 4
musique[1]
adresseMusique + 8
musique[2]
adresseMusique +
4 2399999
musique[2399999]
Lexemple illustre un tableau appel musique de 2400000 lments de type int. Chaque lment
occupe 32 bits, soit 4 octets. Le dbut du tableau, qui correspond au premier lment musique[0] , est plac ladresse adresseMusique. Chaque lment musique[ i] est place
ladresse adresseMusique+4i, le facteur 4 tant la taille de reprsentation du type int en octets.
Dans un langage comme Java, la taille dun tableau est indique au moment de sa cration. La taille
doit tre note en association avec le tableau, en un endroit que lexcuteur du programme puisse
facilement retrouver. La taille peut par exemple tre place en mmoire juste avant le tableau,
ladresse dbut du tableau- 4 si la taille est un entier sur 32 bits.
266
Module A.P.I
Universit de Rennes 1
15.5
15.5.1
15.5.2
101
101
101
10-2
5.000
Multiplication - Division
Ces oprations sont ralises selon la mthode suivante :
1.589 100
2.485196 100
15.5.3
2.0 101
arrondi en 2.485
3.0 100
6.6666666 100 arrondi en 6.666
Universit de Rennes 1
267
Lerreur relative due lopration elle-mme est majore par la valeur reprsente par lunit du
15.5.4
Y = 1.404 103
0.001 103
104
+ 0.002404 104
1.234404 104
Ce qui aprs arrondi donne 1.234 104
268
Module A.P.I
Universit de Rennes 1
S =
--i-
i=1
10 000
100 000
10 000 000
10 000 000
9.787613
14.35736
15.40368
15.40368
9.787604
14.39265
16.68603
18.80792
valeur exacte
9.787606
14.39273
16.69531
18.99789
=> x1 = x2 = 100
x2 = (205+5) / 2 = 105
Universit de Rennes 1
269
270
Module A.P.I
Universit de Rennes 1
Annexes
Installations
ANNEXE 1
1.1
Installation de Java
On peut tlcharger Java depuis le site de Sun Micro-System :
http://java.sun.com/j2se/1.5.0/download.jsp
le lien ci-dessus est la version de dbut 2006. Bien videmment il convient de prendre la plus
rcente version du moment. Le site propose une installation pour la plupart des systmes : Windows, Linux, Mac-OS, Sun-OS. Le fichier tlcharg est un programme dinstallation quil suffit
dexcuter.
1.2
Universit de Rennes 1
271
Annexes
1.3
Ajout de paquetages
Pour faire certains exercices, nous utiliserons des classes regroupes dans des paquetages (package). Ces paquetages se trouvent dans le rpertoire paquetagesMaison . Voici ce quoffrent
ces paquetages :
es : lecture de donnes depuis le clavier et depuis des fichier, criture de donnes sur des fichiers,
list : listes de donnes de types quelconque,
ens : ensembles de valeurs de divers types,
ihm : placement de composants graphiques.
Chaque paquetage est un rpertoire qui contient des classes destines tre utilises dans des applications. Pour utiliser un tel paquetage, il faut en dbut du texte du programme, placer une directive :
import nomDuPaquetage.*;
Le programme suivant utilise la procdure Lecture.unEntier du paquetage es pour lire des
donnes frappes au clavier.
import es.*;
class Test2 {
public static void main(String [] arg){
System.out.print("entrer deux nombres
int nombre1=Lecture.unEntier();
int nombre2=Lecture.unEntier();
System.out.print("leur somme = ");
System.out.println(nombre1+nombre2);
}
}
:");
Ce programme lit deux nombres entiers, frapps au clavier, en dcimal, spars par un espace ou
par des passages la ligne, puis il affiche leur somme.
Si on essaye de le compiler comme prcdemment, le compilateur indique une erreur car il ne connat pas la classe Lecture . Il faut en plus lui indiquer le rpertoire o se trouve le paquetage es.
On peut le lui indiquer :
Soit grce la variable denvironnement CLASSPATH : la positionner en lui indiquant le chemin du rpertoire paquetagesMaison ainsi que le rpertoire courant, not .. Sur un systme Windows, la commande est
set CLASSPATH=.../paquetagesMaison;.
.../paquetagesMaison dnote ici le chemin absolu du rpertoire paquetageMaison
(cela dpend de lendroit o le dossier a t plac).
Soit en lanant la commande de compilation avec loption -classpath :
javac -classpath
.../paquetagesMaison;. Test2.java
Dans ce cas, la commande dexcution doit galement se faire avec cette option :
java -classpath
.../paquetagesMaison;. Test2
Le programme Test2 attend lintroduction de deux nombres entiers au clavier, termin par un passage la ligne, et affiche leur somme :
entrer deux nombres
leur somme = 60
: 45 25
Universit de Rennes 1
272
Annexes
1.4
Installation dEclipse
Eclipse est un outil de dveloppement sophistiqu pour de nombreux langages (langages de programmation, principalement pour Java, mais aussi C++, ou bien langages documentaires tels
HTML, XML...). On peut tlcharger Eclipse depuis le site :
http:download.eclipse.org/eclipse/dowloads
Il convient de charger la plus rcente version. En dbut 2006, pour du dveloppement Java, sur Windows, le fichier tlcharger est :
eclipse-SDK-3.1.2.win32.zip
Il existe des installation pour quasiment tous les autres systmes : Linux, Unix-Solaris, MacOS.
Il sagit simplement dun dossier compress appel eclipse quil suffit de dployer, par exemple,
sous windows, dans C:/Programm
File
. Sous Windows, on le lance en excutant
eclipse.exe qui est dans le dossier eclipse.
1.5
A la question voulez vous passer tout de suite la perspective Java ? rpondre yes
La perspective Java utilise essentiellement 3 fentres :
La fentre dexploration du projet ( gauche). Les classes du projet sont visibles dans la rubri-
Universit de Rennes 1
273
Annexes
Les fentres inutiles senlvent en cliquant sur les croix qui leur correspondent. Les fentres se
raffichent par Window - Show View .
File...
Package Explorer
Coucou.java
ProjetCoucou
default package
fentre ddition
class Coucou {
...
}
fentre
dexploration
du projet
Problems
Console
fentre dexcution
1.6
Universit de Rennes 1
274
Annexes
1.7
Excution
Slectionner la fentre ddition du programme excuter (la classe qui contient le main) puis :
Run - Run as - Java application
Pour communiquer avec le programme ou voir les messages derreur dexcution, slectionner
longlet Console sur la fentre du bas.
Arrt forc de lexcution :
(par exemple pour arrter un programme qui boucle indfiniment)
en haut de la fentre Console , cliquer sur le carr rouge.
Pour en savoir plus...
Lire le petit manuel lusage du dveloppeur Java sous Eclipse
de Yves Bekkers - Ifsic
Universit de Rennes 1
275
Annexes
Universit de Rennes 1
276
Annexes
ANNEXE 2
Nous donnons ici les programmes sources des paquetages maison utiliss pour les exercices et les
travaux pratiques. Ce sont :
Paquetage es :
classe Lecture : entres depuis le clavier.
classe LectureFichierTexte : entres depuis un fichier texte.
classe EcritureFichierTexte : sorties sur un fichier texte.
Paquetage list :
classe Liste<T> : listes gnriques
La classe ListeDEntiers en est une spcialisation :
class ListeDEntiers extends Liste<Integer>
Paquetage ens :
classe Ensemble<T> : ensembles gnriques
La classe EnsembleDEntiers en est une spcialisation :
class EnsembleDEntiers extends Ensemble<Integer>
2.1
Universit de Rennes 1
277
Annexes
Universit de Rennes 1
278
Annexes
package es;
import java.io.*;
public class LectureFichierTexte {
private
private
private
private
BufferedReader leFichier;
char prochainCaractere;
boolean finDeFichier;
String nom;
Universit de Rennes 1
279
Annexes
ou jusqu
Universit de Rennes 1
280
Annexes
package es;
import java.io.*;
public class EcritureFichierTexte {
private PrintWriter leFichier;
private String nom;
public EcritureFichierTexte(String nom) {
this.nom=nom;
try {leFichier = new PrintWriter(new FileOutputStream(nom));}
catch(IOException e){
System.out.println(
"erreur lors de la cration du fichier "+nom);
Thread.dumpStack();
}
}
public void ecrire(char c) {leFichier.print(c);}
public void ecrire(String s) {leFichier.print(s);}
public void ecrire(int k) {leFichier.print(k);}
public void ecrire(boolean b) {leFichier.print(b);}
public void ecrire(double x) {leFichier.print(x);}
}
2.2
Listes
La classe Liste prsente ici est une classe gnrique. Le type des lments (dsign par T) peut
tre nimporte quelle classe.
package list;
import parcours.*;
public class Liste<T> {
private static class Maillon<TE> {
Maillon<TE> suivant; Maillon<TE> precedent; TE element;
Maillon(Maillon<TE> s,Maillon<TE> p,TE e) {
suivant=s;precedent=p;element=e;
}
}
private Maillon<T> tete;
private Maillon<T> queue;
public Liste() { // liste vide
tete=null; queue=null;
}
Module A.P.I. Algorithmique Programmation Imprative
Universit de Rennes 1
281
Annexes
Universit de Rennes 1
282
Annexes
public T retireEnQueue() {
// prrequis
: this nest pas vide
// effet
: retire llment de queue
// rsultat
: llment retir
T resul = queue.element;
queue = queue.precedent;
if (queue!=null) {queue.suivant=null;}
else {tete = null;}
return resul;
}
public T retireEnTete() {
// prrequis
: this nest pas vide
// effet
: retire llment de tte
// rsultat
: llment retir
T resul = tete.element;
tete = tete.suivant;
if (tete!=null) {tete.precedent=null;}
else {queue = null;}
return resul;
}
Universit de Rennes 1
283
Annexes
Universit de Rennes 1
284
Annexes
public T elementCourant() {
// prrequis
: this nest pas en fin
// rsultat
: llment courant de this
return courant.element;
}
public void modifElement(T nouvelElement) {
// prrequis
: this nest pas en fin
// effet : remplace
llment
courant
de this
if (courant!=null) {courant.element=nouvelElement;}
}
par
nouvelElem
devient
}
//==============================================================
Universit de Rennes 1
285
co
Annexes
2.3
Ensembles
La classe Ensemble prsente ici est une classe gnrique. Le type des lments (dsign par T)
peut tre nimporte quelle classe dot dune fonction de comparaison appele compareTo qui
induise une relation dordre.
package ens;
import parcours.*;
public class Ensemble<T extends Comparable<T>> {
private Object[] elements;
Universit de Rennes 1
286
Annexes
Universit de Rennes 1
287
Annexes
si e nest
pas
dans
Universit de Rennes 1
288
this
Annexes
Universit de Rennes 1
289
e2)
Annexes
Universit de Rennes 1
290
de lense