Section 2.3: graphes d’objets #
Dans le cas général, des données orientées-objet forme un graphe.
2.3.1 Graphe film/personnage #
On peut compléter ainsi la modélisation des films et celle des personnages présentées aux chapitres précédents.
- Un
Personnage
apparaît dans plusieursFilm
. - Un
Film
contient plusieursPersonnage
.
Voici un exemple de données se conformant à cette modélisation.
- Le
Personnage
James Bond apparaît dans deux films : Dr. No et Bon Baisers de Russie. - Le
Film
Dr. No contient deux personnages : James Bond et Dr. No.
2.3.2 Exemple : Fibonacci #
Dans le cas général, il n’est pas facile de visualiser un graphe d’objet avec des cartes. Dans notre approche, il est donc nécessaire de s’en tenir à des cas particuliers. Comme exemple, nous développons une modélisation de la séquence de Fibonacci.
2.3.3 Définition #
Voici le début de la suite de Fibonacci :
0 1 1 2 3 5 8 13 21 34 55 89 144 ...
La définition mathématique est récursive :
\( F_0 = 0\\~\\
F_1 = 1\\~\\
F_n = F_{n-1} + F_{n-2}\\~\\
\)
Autrement dit :
0
et1
sont deux cas spéciaux.Sinon le prochain nombre de la suite est toujours l’addition deux nombres précédents
2.3.4 Nombre d’or #
La suite de Fibonacci est utilisée pour calculer le nombre d’or, soit environ
1.618
- Le nombre d’or est reconnu, entre autres choses, comme une proportion hauteur/largeur agréable à l’oeil.
Comme pour π, on peut calculer le nombre d’or avec autant de précision que désirée, c.-à-d. avec autant de chiffres après le point que désiré.
Pour calculer une approximation du nombre d’or, on fait tout simplement :
\( \text{nombre d'or} \approx \dfrac{F_{n}}{F_{n-1}} \text{~~~pour~~~} n\geq 2 \)Plus on prend un
n
élevé, plus la précision est bonne.Autrement dit, le nombre d’or est à peu près égal à un nombre de la suite de Fibonacci, divisé par le nombre qui le précède.
- Plus on prend un nombre loin dans la suite, plus l’approximation est bonne
2.3.5 Modéliser la suite de Fibonacci #
- Pour modéliser la suite en Java, on va créer une structure de données récursive :
Pour
n = 0
, on a le graphe d’objets suivant :Pour
n = 1
, on a le graphe d’objets suivant :Pour
n = 2
, on a le graphe d’objets suivant :- NOTE : la suite se lit de droite à gauche.
Pour
n = 3
, on a le graphe d’objets suivant :Et ainsi de suite.
2.3.6 Pour calculer la réponse et le nombre d’or #
Calculer la réponse pour
n >= 2
est simple :reponse = moinsUn.getReponse() + moinsDeux.getReponse();
Même chose pour le nombre d’or :
nombreOr = Double.valueOf(reponse) / Double.valueOf(moinsUn.getReponse());
Le défi est qu’il faut d’abord construire le graphe d’objet.
2.3.7 Construire le graphe d’objets récursivement #
Avec des appels récursifs, on va construire d’abord, puis calculer :
- On crée d’abord l’objet
n
, puisn-1
, et ainsi de suite jusqu’à l’objet0
- On crée d’abord l’objet
Pour le cas
n >= 2
, voici comment procéder :Créer un nouvel objet
MonFibonacci
et le mémoriser dansmoinsUn
Enregistrer que le
n
de cemoinsUn
estn-1
(len
courant moins1
).Créer le reste du graphe récursivement en appelant
moinsUn.construireGrapheRecursivement()
Enregister que le
moinsDeux
courant estmoinsUn.getMoinsUn()
(lemoinsUn
dumoinsUn
courant).Calculer la réponse courante à partir des réponses de
moinsUn
etmoinsDeux
L’appel récursif est plus proche de la définition mathématique :
- Pour calculer la réponse en
n
, il faut d’abord calculer la réponse enn-1
- Pour calculer la réponse en
L’inconvénient est qu’on peut déborder la pile d’appel :
Exception in thread "main" java.lang.StackOverflowError at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) at ca.ntro.cards.fibonacci.solution.MonFibonacci.construireGrapheRecursivement(MonFibonacci.java:31) ...
- RAPPEL : le code n’est pas bogué, mais limité par la mémoire attribuée à la pile d’appel.
2.3.8 Construire le graphe d’objets dynamiquement #
En programmation dynamique, on calcule en même temps qu’on construit :
- On crée d’abord l’objet
0
, puis1
, et ainsi de suite jusqu’à l’objetn
- On crée d’abord l’objet
L’idée est qu’on fait une boucle pour créer le graphe d’objets.
On crée une
nouvelleTete
Le
moinsUn
de lanouvelleTete
est l’anciennetete
Le
moinsDeux
de lanouvelleTete
est lemoinsUn
de l’anciennetete
- c.-à-d. on insère la
nouvelleTete
à gauche, et on « pousse » les objets existants vers la droite.
- c.-à-d. on insère la
Pour le cas
n >= 2
, voici comment procéder :Pour chaque
i
allant de2
àn
(inclusivement) :Créer un nouvel objet
MonFibonacci
pour représenter lanouvelleTete
Enregistrer que le
n
de lanouvelleTete
esti
Enregistrer que le
moinsUn
de lanouvelleTete
est latete
courante.Enregistrer que le
moinsDeux
de lanouvelleTete
est lemoinsUn
de latete
courante.Enregistrer que
tete
pointe maintenant vers lanouvelleTete
Calculer la réponse pour
tete
Le calcul dynamique est moins intuitif (et moins proche de la définition mathématique), mais on a éliminé l’appel récursif, alors on ne peut plus déborder la pile d’appel.