Dans la partie 1 nous avons appris à surcharger le count
ainsi que les différentes méthodes de ArrayAccess
. Pour faire un exemple un peu plus concret, je vais impémenter les listes chainées. Les listes doublement chainée sont déja implémentées dans la SPL via SplDoublyLinkedList.
Le liste chainée (linked list en anglais) est une structure de donnée. Nous allons essayer d’implémenter une liste chainée en PHP. Cela nous permettra de comprendre l’idée. Nous allons implémenter l’interface Countable
. (J’implémente ArrayAccess
et Iterator
dans le post suivant).
Une liste chainée est constituée de Node
ou noeud/chainon.
Un node a deux propriétés.
- Sa valeurs
- Le liens vers le noeud suivant
En php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
pour créer une liste rien de bien compliqué.
1 2 3 4 5 |
|
Résultat le dessin suivant (wikipedia)
Implementation de la liste
Nous allons créer des méthodes pour ajouter simplement nos chainons.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Nous allons traquer le premier élément de la chaine ($this->first
) et le dernier ($this->last
)
Ajout d’un chainon à la fin
C’est assez simple.
- Créer un nouveau noeud
- Récupérer le dernier chainon
- Faire pointer la propriété
next
du dernier chainon vers notre nouveau noeud. - Notre nouveau noeud devient le dernier noeud.
- On augmente la taille de 1
en code cela donne
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Exemple
1 2 3 |
|
Ajout d’un chainon au début
C’est un peu près la même idée.
- Créer un nouveau noeud
- Récupérer le premier noeud.
- Notre noeud pointe vers le premier noeud.
- On pointe le
first
vers notre nouveau noeud.
En code
1 2 3 4 5 6 7 8 9 10 11 |
|
Un exemple
1 2 3 |
|
Suppression d’un chainon au début.
Il faut faire dans l’autre sens.
En code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Suppression d’un chainon à la fin
Comme le dernier chainon ne connait pas son prédécesseur. C’est beaucoup plus compliqué. On est obligé de repartir depuis le début. Donc pour supprimer le dernier chainon d’un liste d’un million de chainon, il nous faut parcourir les 1 millions de chainons.
En Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Ajouter une valeurs au milieu de la chaine
Même punition que pour supprimer un lien à la fin de la liste. Si on a une liste de 1 Millions de chainons. Pour insérer à la position 99999, nous sommes obligés de parcourir les 99999 chainons. Et pour la suppression ce sera pareil..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Implementer le count
Si vous avez lu le post précédent il suffit d’ajouter une méthode count
1 2 3 4 |
|
Des applications avec la Liste chainée.
Si on renomme la méthode insertAtEnd($data)
par enqueue($job)
et la méthode removeFirstValue()
par dequeue()
On obtient une file d’attente ou une Queue
en anglais.
1 2 3 4 5 6 7 |
|
Si on renomme la méthode insertFirstValue
en push
et la méthode removeFirstValue()
par pop()
On obtient une Stack.
Voici le code pour inverser un array sans utiliser array_reverse
1 2 3 4 5 6 7 8 9 10 |
|
Conclusion
Un ancien livre est titré
Algorithms + Data Structures = Programs
On a tendance en language php à penser tout en Object et en Array. Parfois la façon dont on représente nos données est importante.
- Certaines opérations comme ajouter un lien au début/fin de la chaine sont très peu couteuses (une étape) on parle de complexité O(1);
- supprimer un lien à la fin de la liste par contre prend N étapes On dit que la complexité est de O(N)
Pour résoudre ce problème on a inventé les listes doublements chainées. Voir le dessin (Wikipédia);
Cela prend beaucoup plus de mémoire, mais on simplifie beaucoup l’ajout et la suppression au début et à la fin de liste. par contre la recherche dans une liste chainée est toujours aussi longue.
Mon post sur les Stack.
Dans le post suivant on implémentera les méthodes de ArrayAccess
et Iterator
, ce qui nous permettra de faire des foreach
ou isset($list[2])
etc ..