Qual è il modo più efficiente in termini di spazio per implementare una struttura di dati grafici?


14

In genere implemento i grafici come elenchi doppiamente collegati ma questo è abbastanza inefficiente nello spazio nella mia esperienza in quanto ho bisogno di k puntatori / riferimenti per k vicini, quindi per un grafico non indirizzato avrei ~ 2k collegamenti vicini all'interno degli elenchi se la mia matematica è giusta. Esiste un modo migliore per risparmiare spazio? So che alcuni dei collegamenti possono essere resi singolari se il grafico è diretto, ma c'è un modo per fare un lavoro migliore di questo?

Risposte:


12

Bene, se l'efficienza dello spazio è tutto ciò che ti interessa, una struttura di dati compressi sarebbe la migliore - ma ovviamente questo non è molto efficiente per l'accesso o l'aggiornamento .....

Se il tuo grafico ha un numero relativamente piccolo di nodi ed è abbastanza denso (diciamo che esiste almeno il 5% di tutte le connessioni possibili), potresti trovare più efficiente lo spazio per creare una matrice di adiacenza piuttosto che usare gli elenchi dei bordi. Ciò richiederebbe solo un bit per ogni possibile connessione (diretta) e n * n bit totali dove si hanno n nodi.

In caso contrario, se è necessario utilizzare i collegamenti adiacenti, non è possibile fare facilmente meglio di un riferimento per collegamento, poiché si tratta del contenuto minimo di informazioni che è necessario archiviare. Se si desidera backlink, sarà necessario il doppio del numero di link.

Ci sono alcuni trucchi che potresti provare su questo. Ad esempio, potresti provare a condividere sottoinsiemi di collegamenti (se A e B si riferiscono a ciascuno di C, D, E, quindi memorizzare l'elenco dei collegamenti C, D, E una volta .....). Tuttavia, questo diventerà complesso abbastanza rapidamente e dubito che ne varrà la pena nella maggior parte dei casi.

Un altro trucco - supponendo che il tuo grafico abbia un numero ragionevole di nodi, risparmierai sicuramente spazio indicizzando - ad esempio usando un numero indice nodo a 16 bit anziché un puntatore / riferimento completo.


Se tutti i collegamenti non sono diretti, si può risparmiare metà dello spazio salvando il bordo solo dal nodo basso al nodo alto.
Deduplicatore,

6

Dipenderà dalla struttura dei tuoi dati.

Per un grafico denso con bordi non orientati, non puoi davvero battere un elenco di matrici di bit che rappresentano una matrice triangolare. A List<BitArray>per esempio. Logicamente, sarebbe simile a questo:

 0123
0
11
211
3001
41010

Da lì, è possibile utilizzare l'indice del BitArray radice per indicizzare in un elenco che memorizza i dati del nodo.

Ad esempio, ottenere tutti i vicini di un nodo sarebbe come:

// 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];
    }    
}

(nota che puoi anche scegliere il tipo di indice, a seconda della quantità di dati, come byte o ushort o qualcosa del genere poiché tutti gli indici saranno positivi. Non considero questa una micro-ottimizzazione in quanto banale)

Per un grafico diretto, dovresti seguire il percorso di un array * n di bit per memorizzare la connettività ... a meno che non sia molto scarso rispetto al numero di nodi, dove puoi andare a un elenco di indici di adiacenza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.