Je pense que votre premier exemple est un peu ambigu : les nœuds sont des objets et les bords des pointeurs. Vous pourriez garder la trace de ces derniers en stockant uniquement un pointeur vers un nœud racine, auquel cas l'accès à un nœud donné peut être inefficace (disons que vous voulez le nœud 4 - si l'objet nœud n'est pas fourni, vous devrez peut-être le chercher). Dans ce cas, vous perdriez également des portions du graphe qui ne sont pas accessibles à partir du nœud racine. Je pense que c'est le cas que f64 rainbow suppose quand il dit que la complexité temporelle pour accéder à un noeud donné est O(n).
Sinon, vous pourriez également conserver un tableau (ou hashmap) rempli de pointeurs vers chaque nœud. Cela permet un accès O(1) à un nœud donné, mais augmente un peu l'utilisation de la mémoire. Si n est le nombre de nœuds et e le nombre d'arêtes, la complexité spatiale de cette approche serait de O(n + e).
La complexité spatiale de l'approche matricielle serait de l'ordre de O(n^2) (en supposant que les bords sont unidirectionnels). Si votre graphe est clairsemé, vous aurez beaucoup de cellules vides dans votre matrice. Mais si votre graphe est entièrement connecté (e = n^2), cela se compare favorablement avec la première approche. Comme le dit RG, vous pouvez également avoir moins de ratés de cache avec cette approche si vous allouez la matrice comme un seul morceau de mémoire, ce qui pourrait rendre le suivi de beaucoup d'arêtes autour du graphe plus rapide.
La troisième approche est probablement la plus efficace en termes d'espace pour la plupart des cas - O(e) - mais elle rendrait la recherche de tous les bords d'un nœud donné une tâche O(e). Je ne peux pas penser à un cas où cela serait très utile.
3 votes
Je ne considérerais la matrice que si le graphe était très connecté ou très petit. Pour les graphes faiblement connectés, les approches objet/pointeur ou liste d'arêtes donneraient toutes deux une bien meilleure utilisation de la mémoire. Je suis curieux de savoir ce que j'ai oublié de stocker ;)
2 votes
Ils diffèrent également en termes de complexité temporelle, la matrice est O(1), et les autres représentations peuvent varier considérablement en fonction de ce que vous recherchez.
1 votes
Je me souviens avoir lu un article il y a quelque temps décrivant les avantages matériels de l'implémentation d'un graphe sous forme de matrice par rapport à une liste de pointeurs. Je ne me souviens pas de grand-chose à ce sujet, si ce n'est que, comme vous avez affaire à un bloc de mémoire contigu, à tout moment, une grande partie de votre ensemble de travail peut très bien se trouver dans le cache L2. Par contre, une liste de nœuds/pointeurs peut être dispersée dans la mémoire et nécessitera probablement une récupération qui ne touchera pas le cache. Je ne suis pas sûr d'être d'accord mais c'est une idée intéressante.
2 votes
@Dean J : juste une question sur la "représentation des nœuds comme objets et des arêtes comme pointeurs". Quelle structure de données utilisez-vous pour stocker les pointeurs dans l'objet ? Est-ce une liste ?
5 votes
Les noms communs sont : (1) équivalent à liste d'acceuil , (2) matrice d'adjacence , (3) liste des bords .