实现图形数据结构的最节省空间的方法是什么?


14

我通常将图实现为双向链接列表,但是根据我的经验,这在空间上效率很低,因为我需要k个邻居的k个指针/引用,因此如果我的数学正确,则对于无向图,列表中将有〜2k个邻居链接。有节省空间的更好方法吗?我知道,如果有向图是定向的,则可以将某些链接设为单数形式,但是有没有办法对此做得更好?

Answers:


12

好吧,如果您只关心空间效率,那么压缩数据结构将是最好的-但是,这当然对访问或更新不是很有效。

如果您的图的节点数量相对较少并且非常密集(假设所有可能的连接中至少有5%存在),则可能会发现创建邻接矩阵比使用边缘列表更节省空间。每个可能的(定向)连接只需要一个位,如果您有n个节点,则总共需要n * n位。

否则,如果您需要使用邻居链接,那么您就很难轻易做到每个链接都只有一个参考,因为这是您需要存储的最少信息内容。如果要反向链接,则需要两倍的链接。

您还可以尝试一些技巧。例如,您可以尝试共享链接的子集(如果A和B分别引用C,D,E,则只存储一次链接C,D,E的列表.....)。但是,这很快就会变得很复杂,我怀疑在大多数情况下是否值得这样做。

另一个技巧-假设您的图形具有合理数量的节点,则一定会通过索引来节省空间-例如,使用16位节点索引号而不是完整的指针/引用。


如果所有链接都是非定向的,则仅保存从低节点到高节点的边缘就可以节省一半的空间。
Deduplicator 2015年

6

这将取决于您的数据结构。

对于具有无向边的密集图形,您无法真正击败代表三角矩阵的位阵列列表。一个List<BitArray>例如。从逻辑上讲,它看起来像这样:

 0123
0
11
211
3001
41010

从那里,您可以使用根BitArray的索引来索引到存储节点数据的列表中。

例如,获取节点的所有邻居将像这样:

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

(请注意,您还可以根据数据量将索引类型选择为字节或ushort或类似的东西,因为所有索引都是正数。我不认为这是微不足道的微细优化)

对于有向图,您将使用* n位数组的路径来存储连接性...除非与节点数相比非常稀疏,否则您可以转到索引的邻接表。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.