Quelle est la manière la plus économe en espace d'implémenter une structure de données de graphique?


14

J'implémente généralement des graphiques sous forme de listes doublement liées, mais mon expérience est assez peu efficace car j'ai besoin de k pointeurs / références pour k voisins, donc pour un graphique non orienté, j'aurais ~ 2k liens de voisins dans les listes si mes calculs sont corrects. Existe-t-il un meilleur moyen d'économiser de l'espace? Je sais que certains des liens peuvent être rendus singuliers si le graphique est orienté, mais existe-t-il un moyen de mieux faire cela?

Réponses:


12

Eh bien, si l'efficacité de l'espace est tout ce dont vous vous souciez, une structure de données compressée serait la meilleure - mais bien sûr, ce n'est pas très efficace pour l'accès ou la mise à jour .....

Si votre graphique a un nombre relativement petit de nœuds et est assez dense (disons qu'au moins 5% de toutes les connexions possibles existent), vous constaterez peut-être que l'espace est plus efficace pour créer une matrice d'adjacence plutôt que d'utiliser des listes de bords. Cela nécessiterait un seul bit par connexion possible (dirigée) et un total de n * n bits lorsque vous avez n nœuds.

Sinon, si vous devez utiliser des liens voisins, vous ne pouvez pas facilement faire mieux qu'une référence par lien, car il s'agit du contenu d'informations minimum que vous devez stocker. Si vous voulez des back-links, vous aurez besoin de deux fois plus de liens.

Il y a quelques astuces que vous pouvez essayer en plus de cela. Par exemple, vous pouvez essayer de partager des sous-ensembles de liens (si A et B font référence à chacun de C, D, E, puis ne stocker la liste des liens C, D, E qu'une seule fois .....). Cependant, cela deviendra complexe assez rapidement et je doute que cela en vaille la peine dans la plupart des cas.

Une autre astuce - en supposant que votre graphique a un nombre raisonnable de nœuds, vous économiserez certainement de l'espace en indexant - par exemple en utilisant un numéro d'index de nœud 16 bits plutôt qu'un pointeur / référence complet.


Si toutes les liaisons ne sont pas dirigées, on peut économiser la moitié de l'espace en enregistrant uniquement le bord du nœud bas au nœud haut.
Déduplicateur

6

Cela dépendra de la structure de vos données.

Pour un graphique dense avec des bords non orientés, vous ne pouvez pas vraiment battre une liste de tableaux de bits représentant une matrice triangulaire. Un List<BitArray>par exemple. Logiquement, cela ressemblerait à ceci:

 0123
0
11
211
3001
41010

À partir de là, vous pouvez utiliser l'index du BitArray racine pour indexer dans une liste qui stocke vos données de nœud.

Par exemple, obtenir tous les voisins d'un nœud irait comme:

// C#
List<Node> Nodes = /* populated elsewhere */
List<BitArray> bits = /* populated elsewhere */
public static IEnumerable<Node> GetNeighbours(int x)    
{
    for (int i = 0; i < bits[idx].Count; i++)
    {
        if (this.bits[idx][i])
            yield return this.Nodes[i];
    }

    for (int i = 0; i < this.Nodes.Count; i++)
    {
        if (idx < this.bits[i].Count && this.bits[i][idx])
            yield return this.Nodes[i];
    }    
}

(notez que vous pouvez également choisir le type d'index, en fonction de la quantité de données, pour être un octet ou un raccourci ou quelque chose dans ce sens car tous les index seront positifs. Je ne considère pas cela comme une micro-optimisation car c'est trivial)

Pour un graphe orienté, vous iriez sur la route d'un * n tableau de bits pour stocker la connectivité ... à moins qu'il soit très clairsemé par rapport au nombre de nœuds, où vous pouvez aller à une liste d'indexation d'adjacence.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.