Comprendre les structures de données non linéaires en 5 minutes
Les structures de données non linéaires sont grandement sous-estimées, voire complètement ignorées, par beaucoup de développeurs. C’est vraiment une erreur. On avait discuté des structures de données linéaires la semaine dernière, c’était le bien. Aujourd’hui, on fait un saut de l’ange dans les structures de données non linéaires.
Toujours plus
La semaine dernière, on a tout compris des stacks, des queues ou encore des linked lists. Si tu as pas suivi le premier article, va jeter un œil au moins 5 minutes. Ça va être galère à suivre sinon celui d’aujourd’hui.
C’est légèrement plus complexe, mais je réitère ce que je te disais dans l’article précédent. Tu as, ou tu vas avoir, un véritable avantage à maîtriser tout ça le plus rapidement possible. Les structures de données non linéaires, spécifiquement, vont te permettre de résoudre des problèmes encore plus pointus.

C’est quoi la différence entre structure de données linéaires et non linéaires déjà ? Excellente question.
Coté linéaire, la donnée est organisée de façon séquentielle. Dans un array par exemple, chaque élément du tableau vient l’un après l’autre. C’est facile à mettre en oeuvre et tu peux consulter tous les éléments en un passage (une boucle).
Côté non linéaire, la donnée n’est pas organisée de façon séquentielle. Tu vas avoir des liens hiérarchiques, ou simplement des liens spéciaux, qui relient les éléments qui composent la structure. Tu ne pourras pas parcourir toutes les données en une boucle et c’est pas le but d’ailleurs. C’est pas clair ? OK, regardons notre premier exemple.
Tree (arbre)
C’est quoi ?
Un arbre c’est un ensemble de nœuds qui sont liés de façon hiérarchique. Il y a le nœud racine au sommet qui est lié à ses nœuds enfants. Nœuds enfants qui peuvent eux-mêmes avoir autant d’enfants qu’ils veulent et ainsi de suite. Chaque nœud ne peut avoir qu’un seul parent. D’où le côté hiérarchique de cette structure de données.
Comme image mentale tu peux tout de suite imaginer un vrai arbre, comme dans la nature, mais à l’envers. La racine au-dessus, les branches représentant les nœuds enfants et les feuilles représentant les nœuds à l’extrémité. Allez, je me lance dans mon art maison.

Concernant cet arbre, on dit qu’il a une taille de 9, car il a 9 nœuds. On dit qu’il a une hauteur de 4, car il a quatre niveaux de profondeur. On dit aussi que cet arbre est sublime, car esthétiquement c’est bien dessiné.
Les arbres sont utilisés partout. De l’arbre hiérarchique de ta boite jusqu’à arborescence de tes fichiers en passant par les systèmes de tournois, ça donne le tournis tellement ils sont partout.

Y’a plein d’arbres différents, c’est la jungle informatique. Tu te doutes bien, on va pas tous les faire. Aujourd’hui, on va se concentrer seulement sur les arbres binaires pour la bonne raison que c’est la version la plus simple. La particularité d’un arbre binaire c’est que chaque nœud ne peut avoir que deux enfants maximum. OK, comment on code cette affaire ?
Représentation
Ici côté représentation, on va simplement regarder la création d’un arbre binaire. Comme d’habitude en C++, Python et Javascript comme ça tout le monde est content.
C++
#include <iostream> using namespace std; struct Node { int value; struct Node* left; struct Node* right; }; int main() { Node *Russia = new Node(); Russia->value = 2018; Node *Germany = new Node(); Germany->value = 2006; Node *France = new Node(); France->value = 1998; Node *Mexico = new Node(); Mexico->value = 1986; Russia->left = Germany; Russia->right = France; France->left = Mexico; // "2018" // / \ // "2006" "1998" // / // "1986" return 0; }
Python (3.6.9)
class Node: def __init__(self, value = None): self.value = value self.left = None self.right = None Russia = Node(2018) Germany = Node(2006) France = Node(1998) Mexico = Node(1986) Russia.left = Germany Russia.right = France France.left = Mexico # '2018' # / \ # '2006' '1998' # / # '1986'
Javascript (NodeJS 12.14.0)
class Node { constructor (value = null) { this.value = value this.left = null this.right = null } } const Russia = new Node(2018) const Germany = new Node(2006) const France = new Node(1998) const Mexico = new Node(1986) Russia.left = Germany Russia.right = France France.left = Mexico // '2018' // / \ // '2006' '1998' // / // '1986'
Et donc ici c’est bien un arbre binaire que je te montre. En fait, plus particulièrement, c’est une Heap (tas). C’est une heap car les éléments sont triés du plus grand (root => 2018) au plus petit (leaf => 1986).
Je t’avais dit que c’était la jungle. On se focus sur un cas particulier pour que tu comprennes comment ça marche concrètement au lieu de rester dans l’abstrait. Les techniques de recherche, de tri et d’insertion sur ces structures seront pour des articles sur les algorithmes plus tard cet été. Je veux juste que tu aies en tête comment ça fonctionne de façon basique pour le moment.

Y’a une autre structure de données non linéaire que tu dois absolument avoir en tête pour certains entretiens.
Graph (Graphe)
C’est quoi ?
Un graphe c’est un ensemble de nœuds (ou sommets) fini reliés par des arêtes (ou arcs). Chaque nœud porte une valeur, chaque arête fait le lien entre les nœuds. Les liens n’ont pas d’origine hiérarchique, juste relationnelle.
Coté image mentale tu peux imaginer une carte de métro. Les arrêts de métro sont les nœuds qui portent la valeur de nom de station. Toutes les stations sont liées à une ou plusieurs stations via des arêtes. Et il y a aucune hiérarchie particulière, seulement des liens. Check le dump de ce que je vois dans ma tête quand je pense à un graphe.

Ouais les termes sont en anglais, je parle anglais dans ma tête. Tu vas tout le temps voir ces termes en anglais, autant s’habituer.
Les graphes c’est peut-être ce qui est le plus utilisé pour représenter des systèmes réels en informatique. Par exemple on les utilise pour les réseaux informatiques ou pour la cartographie comme google map. L’utilisation des graphes est encore plus grande que celle des arbres !

Et d’ailleurs c’est la même histoire qu’avec les arbres. Je te parle ici de la forme la plus simple de graphe. Mais y’a beaucoup d’autres types de graphes avec des particularités propres à des problématiques particulières.
Représentation
Il y a plusieurs manières de représenter un graphe. Aujourd’hui on va utiliser une matrice d’adjacence pour représenter tout ça. Si tu te rappelles de tes cours de maths, tu vois à peu près de quoi je parle. Sinon t’inquiètes, je te fais un petit dessin.

Si un chemin existe entre deux sommets alors on le représente avec un boolean true. Sinon c’est false. Facile ! Allez, codons ça.
C++
#include <iostream> using namespace std; class Graph { private: int vertices; int** adjacencyMatrix; public: Graph(int vertices) { this->vertices = vertices; adjacencyMatrix = new int*[vertices]; for (int i = 0; i < vertices; i++) { adjacencyMatrix[i] = new int[vertices]; for (int j = 0; j < vertices; j++) adjacencyMatrix[i][j] = false; } } void addEdge(int i, int j) { adjacencyMatrix[i][j] = true; adjacencyMatrix[j][i] = true; } void display() { for (int i = 0; i < vertices; i++) { for (int j = 0; j < vertices; j++) cout << adjacencyMatrix[i][j] << " "; cout << "\n"; } } }; int main() { Graph myGraph(4); myGraph.addEdge(0, 2); myGraph.addEdge(1, 3); myGraph.addEdge(2, 3); myGraph.display(); // 0 0 1 0 // 0 0 0 1 // 1 0 0 1 // 0 1 1 0 }
Python (3.6.9)
class Graph(): def __init__(self, vertices): self.vertices = vertices self.adjacencyMatrix = [] for _ in range(self.vertices): self.adjacencyMatrix.append([0 for i in range(self.vertices)]) def add_edge(self, i, j): self.adjacencyMatrix[i][j] = 1 self.adjacencyMatrix[j][i] = 1 def display(self): for row in self.adjacencyMatrix: displayRow = '' for value in row: displayRow += str(value) + ' ' print(displayRow) myGraph = Graph(4) myGraph.add_edge(0, 2) myGraph.add_edge(1, 3) myGraph.add_edge(2, 3) myGraph.display() # 0 0 1 0 # 0 0 0 1 # 1 0 0 1 # 0 1 1 0
Javascript (NodeJS 12.14.0)
class Graph { constructor(vertices) { this.vertices = vertices this.adjacencyMatrix = [] for (var i = 0; i < this.vertices; i++) { this.adjacencyMatrix[i] = new Array(this.vertices).fill(0) } } addEdge(i, j) { this.adjacencyMatrix[i][j] = 1 this.adjacencyMatrix[j][i] = 1 } display() { for(const row of this.adjacencyMatrix) { let displayRow = '' for(const value of row) { displayRow += value + ' ' } console.log(displayRow) } } } myGraph = new Graph(4) myGraph.addEdge(0, 2) myGraph.addEdge(1, 3) myGraph.addEdge(2, 3) myGraph.display() // 0 0 1 0 // 0 0 0 1 // 1 0 0 1 // 0 1 1 0
Épilogue
Et ainsi se termine notre introduction dans le monde des structures de données. Le truc avec les structures de données c’est que c’est bien de les savoir, c’est encore mieux de connaître les algorithmes qui vont avec. Ça tombe bien on va bientôt parler de ça !
Hello, merci pour cet article!
Petite erreur sur le dessin du graph, les « edges » sont les arêtes et les « vertices » sont les sommets 🙂
Tout à fait ! C’est corrigé, merci!
Petit commentaire sur les examples en C++: il y a des fuites mémoires. Juste changer les pointeurs en unique_ptr et ca devrait marcher. Ensuite, il y a un soucis: ‘value’ peut ne pas être utilisé.
Que penses-tu de cette version? https://godbolt.org/z/b89EeP
En ce qui concerne l’example du graphe, pourquoi ne pas utiliser le type ‘bool’ dans un vecteur plutot que dans un tableau? Ca fait pas beaucoup de changement, mais ca permet de ne pas avoir de fuite de mémoire: https://godbolt.org/z/rzMjGq
Dans cette article, les exemples que je donne sont fait rapidement pour donner une idée d’implémentation. C’est vraiment pas fait pour partir en prod mais pour être le plus simple possible.
Ta solution à l’air bonne ceci dit, je vais regarder tout ça.
YijBVQCiLdc
PwjaP69FmLA
tsBav05mHsl
PPD4LazlO4w
TdOflcFBjEU
JeIhY0dso76
N6QpXTbrL2K
V8UAxvsbyWa
jNA6kPE2i8L
1At2kUb7jfy
DAK85qJCWq7
7iG8hCdzT2L
QzKU4GHmWTJ
KYRuKpFsC01
9fiQXo6Ct2v
DJLacJ2axW3
8UPESTyZwCN
96u8wbig9vM
nbLiviBD3o3
SRv99fAKhEw
nPGfwSbXo8F
CbR2D12nzV9
mM7oh2Q6Rf6
IEOpEEH50rm
9UQmzfsk1cw
O323UHoW9cm
yLZqA2vzYNQ
hIlcnGCkS83
jkD2IHr2s4W
KKcQVKhQAfu
7Rg0NZoBIsQ
oln6WdmbyVF
Xcu1BLPgXKv
Deneme bonusu güncel fırsatları, yeni kullanıcılar için risksiz bahis yapma imkanı sunar. En yeni deneme bonuslarını keşfetmek için sitemizi ziyaret edin!
Free spin veren siteler, slot oyunlarında ekstra dönüş şansı tanır ve kazanç fırsatlarını artırır. En iyi free spin fırsatlarını keşfetmek için sitemizi ziyaret edin!
Güvenilir bonus veren bahis siteleri, yüksek oranlar ve güvenli ödeme yöntemleriyle kazancınızı artırma fırsatı sunar. En güvenilir bonusları keşfetmek için sitemizi ziyaret edin!
Yeni bonus veren siteler, yeni kullanıcılar için cazip promosyonlar sunarak kazanç fırsatlarını artırır. En yeni bonusları keşfetmek için sitemizi ziyaret edin!
Deneme bonusu veren yeni siteler, kullanıcılarına risksiz bahis yapma fırsatları sunar. En yeni deneme bonuslarını keşfetmek için sitemizi ziyaret edin!
Yeni bonus veren siteler, kullanıcılarına cazip promosyonlar sunarak kazançlarını artırma imkanı sağlar. En yeni bonus fırsatlarını keşfetmek için sitemizi ziyaret edin!
En iyi casino siteleri, geniş oyun seçenekleri, yüksek ödeme oranları ve güvenli ödeme yöntemleriyle mükemmel bir oyun deneyimi sunar. En iyi casino sitelerini keşfetmek için sitemizi ziyaret edin!
Deneme bonusu veren yeni siteler, kullanıcılarına risksiz bahis deneyimi sunarak kazanç fırsatlarını artırır. En yeni deneme bonuslarını keşfetmek için sitemizi ziyaret edin!
Bahis forum siteleri, bahis severlerin deneyimlerini paylaştığı, stratejiler ve ipuçları bulabileceğiniz platformlardır. En iyi forumları keşfetmek için sitemizi ziyaret edin!