オブジェクトグラフ表現を隣接リストおよびマトリックス表現と比較する


81

私は現在、技術的なプログラミング面接の準備に関するSteve Yeggeのアドバイスに従っています:http://steve-yegge.blogspot.com/2008/03/get-that-job-at-google.html

グラフに関する彼のセクションで、彼は次のように述べています。

メモリ内のグラフを表現するための3つの基本的な方法(オブジェクトとポインタ、マトリックス、および隣接リスト)があり、各表現とその長所と短所をよく理解する必要があります。

行列と隣接リストの表現の長所と短所はCLRSで説明されていますが、これらをオブジェクトの表現と比較するリソースを見つけることができませんでした。

考えてみるだけで、自分で推測することもできますが、大切なことを見逃していないことを確認したいと思います。誰かがこれを包括的に説明できるか、そうするリソースを私に指摘することができれば、私はそれを大いに感謝します。


帰納的グラフはどうですか—これらは3つのカテゴリーのどれに該当しますか?
Erik Kaplun 2016

回答:


94

オブジェクトとポインタ

これらは、他の回答で述べたhammarのような基本的なデータ構造であり、Javaエッジや頂点などのクラスでこれを表すことになります。たとえば、エッジは2つの頂点を接続し、有向または無向のいずれかであり、ウェイトを含めることができます。頂点にはID、名前などを含めることができます。ほとんどの場合、両方に追加のプロパティがあります。だからあなたはそれらであなたのグラフを構築することができます

Vertex a = new Vertex(1);
Vertex b = new Vertex(2);
Edge edge = new Edge(a,b, 30); // init an edge between ab and be with weight 30  

このアプローチは、オブジェクト指向のユーザーにとってより読みやすく便利であるため、オブジェクト指向の実装に一般的に使用されます;)。

マトリックス

行列は単純な2次元配列です。次のようなint配列として表すことができる頂点IDがあると仮定します。

int[][] adjacencyMatrix = new int[SIZE][SIZE]; // SIZE is the number of vertices in our graph
adjacencyMatrix[0][1] = 30; // sets the weight of a vertex 0 that is adjacent to vertex 1

これは通常、インデックスアクセスが必要な密グラフに使用されます。これを使用して、無向/無向および加重構造を表すことができます。

隣接リスト

これは単純なデータ構造の組み合わせであり、私は通常、を使用してこれを実装しHashMap<Vertex, List<Vertex>>ます。同様に使用されるのHashMultimapはグアバです。

O(1)(償却)頂点ルックアップがあり、要求したこの特定の頂点に隣接するすべての頂点のリストが返されるため、このアプローチは便利です。

ArrayList<Vertex> list = new ArrayList<>();
list.add(new Vertex(2));
list.add(new Vertex(3));
map.put(new Vertex(1), list); // vertex 1 is adjacent to 2 and 3

これはスパースグラフを表すために使用されます。Googleで申請する場合は、ウェブグラフがスパースであることを知っておく必要があります。BigTableを使用すると、よりスケーラブルな方法でそれらを処理できます。

ああ、ところで、ここにファンシーピクチャー付きのこの投稿の非常に良い要約があります;)


このアプローチはクールです。O(1)頂点ルックアップがあるため、この複雑さはわずかに間違っています。特に、アルファ=ハッシュマップのスロット数/頂点数であるO(1 + alpha)です。したがって、ハッシュマップの代わりに配列を使用することを提案します
Timofey 2013

@TimはO(1)で償却されます。複雑さの計算は、実装に大きく依存します。HashMapdocs.oracle.com/javase/7/docs/api/java/util/HashMap.html)のjavadocを参照してください:This implementation provides constant-time performance for the basic operations= O(1)償却済み。
Thomas Jungblut 2013

6
@Timここの誰もが、配列アクセスがどのHashTable使用法よりも速いことを知っていると思います。したがって、無視できる小さな一定のアルファオーバーヘッドで周りをくすぐる必要はありません。
Thomas Jungblut 2013

2
誤解しないでください、私はあなたに良い答えを怒らせませんが、私はあなたの答えが改善されるかもしれないと感じているので、ここでそれを言及しないのはなぜ
ですか

2
@Tim私は償却済みのメモを回答に追加しました。ありがとう。
Thomas Jungblut 2013

7

オブジェクトとポインタは、少なくともこれらの表現を使用するアルゴリズムを比較する目的では、隣接リストとほとんど同じです。

比較する

struct Node {
    Node *neighbours[];
};

struct Node {
    Node *left;
    Node *right;
};

後者の場合、名前付きポインターよりも操作が簡単であれば、その場でネイバーのリストを簡単に作成できます。


4

オブジェクト表現(インシデントリスト)の利点は、2つの隣接する頂点がエッジの同じインスタンスを共有することです。これにより、無向エッジデータ(長さ、コスト、フロー、さらには方向)を簡単に操作できます。ただし、ポインタ用に余分なメモリを使用します。


5
「インシデントリスト」という名前の隣接リスト表現へのリンクがあるのはなぜですか。おそらく、この1つのalgorithmist.com/index.php/Graph_data_structures#Incidence_List
Timofey 2013

1

もう1つの優れたリソース:カーンアカデミー-「グラフの表現」

隣接リストと隣接行列に加えて、3番目のタイプのグラフ表現として「エッジリスト」をリストします。エッジリストは、Thomasの「オブジェクトとポインタ」の回答のような「エッジオブジェクト」のリストとして解釈できます。

利点:エッジに関するより多くの情報を保存できます(Michalが言及)

短所:使用するデータ構造が非常に遅い:

  • エッジを検索する:O(log e)
  • エッジを削除します:O(e)
  • 特定のノードに隣接するすべてのノードを検索します:O(e)
  • 2つのノード間にパスが存在するかどうかを判別します:O(e ^ 2)

e =エッジの数

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.