Qual é a maneira mais eficiente em termos de espaço para implementar uma estrutura de dados gráficos?


14

Normalmente, implico gráficos como listas duplamente vinculadas, mas isso é bastante ineficiente na minha experiência, pois preciso de k ponteiros / referências para k vizinhos; portanto, para um gráfico não direcionado, eu teria ~ 2k links de vizinhos nas listas se minha matemática estiver correta. Existe uma maneira melhor de economizar espaço? Eu sei que alguns dos links podem ser singularizados se o gráfico for direcionado, mas existe uma maneira de fazer um trabalho melhor disso?

Respostas:


12

Bem, se você precisa de eficiência de espaço, uma melhor estrutura de dados compactada seria a melhor - mas é claro que isso não é muito eficiente para acessar ou atualizar ...

Se o seu gráfico tiver um número relativamente pequeno de nós e for bastante denso (digamos que pelo menos 5% de todas as conexões possíveis existam), você poderá achar que é mais eficiente em termos de espaço criar uma matriz de adjacência do que usar listas de arestas. Isso exigiria apenas um bit por conexão possível (direcionada) e um total de n * n bits onde você possui n nós.

Caso contrário, se você precisar usar links vizinhos, não poderá facilmente fazer melhor que uma referência por link, pois esse é o conteúdo mínimo de informações que você precisa armazenar. Se você quiser links de volta, precisará do dobro de links.

Existem alguns truques que você pode tentar sobre isso. Por exemplo, você pode tentar compartilhar subconjuntos de links (se A e B se referirem a cada um de C, D, E, em seguida, armazene apenas a lista de links C, D, E uma vez .....). No entanto, isso ficará complexo rapidamente e duvido que valha a pena o esforço na maioria dos casos.

Outro truque - supondo que seu gráfico tenha um número razoável de nós, você certamente economizará espaço ao indexar - por exemplo, usando um número de índice de nó de 16 bits em vez de um ponteiro / referência completo.


Se todos os links não forem direcionados, é possível economizar metade do espaço, salvando apenas a borda do nó baixo para o alto.
Deduplicator

6

Vai depender da estrutura dos seus dados.

Para um gráfico denso com bordas não direcionadas, não é possível superar uma lista de matrizes de bits que representam uma matriz triangular. A List<BitArray>por exemplo. Logicamente, ficaria assim:

 0123
0
11
211
3001
41010

A partir daí, você pode usar o índice do BitArray raiz para indexar em uma lista que armazena os dados do nó.

Por exemplo, obter todos os vizinhos de um nó seria como:

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

(observe que você também pode escolher o tipo de índice, dependendo da quantidade de dados, como um byte ou ushort ou algo nesse sentido, pois todos os índices serão positivos. Não considero isso uma micro-otimização, pois é trivial)

Para um gráfico direcionado, você seguiria a rota de uma matriz de bits * n para armazenar a conectividade ... a menos que seja muito esparsa em comparação com o número de nós, onde você pode acessar uma lista de índices adjacentes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.