BFSは通常、次のように記述されます(Wikipediaから)。
1 procedure BFS(G,start_v):
2 let Q be a queue
3 label start_v as discovered
4 Q.enqueue(start_v)
5 while Q is not empty
6 v = Q.dequeue()
7 if v is the goal:
8 return v
9 for all edges from v to w in G.adjacentEdges(v) do
10 if w is not labeled as discovered:
11 label w as discovered
12 w.parent = v
13 Q.enqueue(w)
問題はやや微妙な問題です。3行目に隠れています。問題は、発見された頂点を格納するためにどのデータ構造を使用するかです。
最も簡単な解決策は、頂点ごとに1つのエントリを持つブール配列を使用することです。この場合、配列のすべての要素をに初期化する必要がありfalse
、これには時間がかかります。これは、エッジがまったくない場合でもすべてのグラフに適用されるため、間の関係を想定できませんと 実行時間を取得します。Θ (| V| )| V|| E|O (| V| + | E| )
初期化時間を持つデータ構造を回避できますか?最初の試みは、リンクされたリストを使用することかもしれません。ただし、頂点が発見されたかどうかをテストする場合(行10)、以前のように一定の時間ではなく、訪問した頂点の数に比例した時間がかかります。これは、実行時間がになることを意味し、最悪の場合はさらに悪くなります。我々がいることを書き換えたくないこと(注さらに悪化だから:それは悪いなどのようになり、一方、)Θ (| V| )O (| V|| E| )O (| E|2)| V|4| V|| E| ≤ | V|3
動的にサイズ変更された配列を使用すると、リストをソートしたままにできるため、検索にかかる時間はだけですが、それでも実行時間はのみになり、これは標準よりもさらに悪いです。O(ログ|V| )O (| E| ログ| V| )
最後に、動的サイズのハッシュテーブルを使用できます。定数サイズテーブルから始めて、 半分いっぱいになるたびに2倍にします。つまり、テーブルの最終的なサイズは、アルゴリズムが終了する前に検出される頂点の数の最大で2倍であり、開始頂点のコンポーネントの外側には何も検出されないため、これは最大でなります。さらに、ハッシュテーブルをコピーして展開するために行われる作業の合計は、最大で。ハッシュテーブルへの参照と挿入は償却されるため、実際に実行時間を取得します。c| E| +1c + 2 c + 4 c + ⋯ + 2 | E| ≤4 | E| O (1 )O (| E| )
したがって、は可能ですが、実際の実装でそれを実行したいですか?私はおそらくそうは思いません。入力グラフに多数の小さなコンポーネントがあると信じる理由がない限り、ハッシュテーブルを維持するオーバーヘッドにより、実行時間に顕著な定数要素が追加されます。ハッシュテーブルの拡張には時間がかかる可能性がありますルックアップでは、ハッシュ関数を計算し、平均して、テーブル内の複数のスロットを調べる必要があります。ハッシュテーブルのキャッシュパフォーマンスが低いと、実際のコンピューターでも問題が発生する可能性があります。標準配列実装のほとんどの場合、部分はの主要な項ですO (| E| )4 | E|O (| E| )O (| V| + | E| ) これを実行する実際的なコストを考えると、ハッシュテーブルを使用して支配的な用語を削除する価値はありません。