回答:
空間効率が重要な場合は、圧縮されたデータ構造が最適です。しかし、もちろん、これはアクセスや更新にあまり効率的ではありません。
グラフのノード数が比較的少なく、密度がかなり高い場合(考えられるすべての接続の少なくとも5%が存在するとしましょう)、エッジリストを使用するよりも、隣接行列を作成する方がスペース効率が高いことがわかります。これには、可能な(有向)接続ごとに1ビットだけが必要であり、nノードがある場合は合計でn * nビットです。
それ以外の場合、隣接リンクを使用する必要がある場合、これは保存する必要のある最小限の情報コンテンツであるため、リンクごとに1つ以上の参照を簡単に行うことはできません。バックリンクが必要な場合は、2倍のリンクが必要になります。
この上で試すことができるいくつかのトリックがあります。たとえば、リンクのサブセットを共有してみてください(AとBがC、D、Eのそれぞれを参照している場合、リンクC、D、Eのリストを1回だけ保存します)。しかし、これは非常に迅速に複雑になり、ほとんどの場合、努力する価値があるとは思いません。
もう1つのトリック-グラフに適切な数のノードがあると仮定すると、インデックス作成によってスペースを確実に節約できます。たとえば、完全なポインタ/参照ではなく16ビットのノードインデックス番号を使用します。
データの構造に依存します。
無向エッジの密なグラフの場合、三角行列を表すビット配列のリストに勝るものはありません。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またはそれらの行に沿ったインデックスタイプを選択することもできます。これは些細なことなので、マイクロ最適化とは見なしません)
有向グラフの場合、ノードの数と比較して非常にまばらである場合を除き、インデックスの隣接リストに移動できる場合を除き、接続を格納するためにビット配列のルートに移動します。