た:
- 問題は、2つのノード間の長さNのすべてのパスを見つけることです。サイクルは除外されます。
- は、edgelistとしてデータを読み込みます。 (ノードの名前は一意とみなされます)
- ノード名のハッシュテーブル(またはboostとstl、C++のunordered_map)をキーとして作成し、値としてハッシュテーブルを作成します。
- この2番目のハッシュテーブルには、最初のノードがキーとするすべてのノードが含まれます。
例えば
A->B
A->C
B->D
C->E
E->D
ためのPerl表記で入力されたデータを保持して得られたデータ構造は、「edgelist」などのすべてのデータに読み出した後、次のようになり
:
my %hash = (
'A' => {'B' => 1, 'C' => 1},
'B' => {'D' => 1},
'C' => {'E' => 1},
'E' => {'D' => 1},
);
知見場合ノードのペアは直接接続されています(perl)としておおよそ行えます:
sub search {
my ($from,$to) = @_;
if($to eq '*'){ return defined($x=$hash{$from}) ? [keys $hash{$from}] : [] }
return defined($x=$hash{$from}) && defined($x{$to}) ? [$to] : []
}
上記の関数には、$ toを '*'に設定することによって、ノードが接続されているすべてのノードを返す手段があります。戻り値は、$ fromパラメーターに直接接続されたノードの配列参照です。
2つのノード間のパスを検索するには、上記の関数を再帰的に使用する必要があります。
sub path {
my ($from,$to, $hops, $save_results) = @_;
if($hops < 0){ return 0 }
$results = search($from, '*');
if(""[email protected]$results == 0){ return 0 }
$found = 0;
foreach $result (@$results){
$a_node = new Tree::Nary($result);
if(path($result, $to, $hops-1, $a_node) == 1){
$save_results->insert($save_results, -1, $a_node);
$found = 1;
}
}
return $found;
}
深さがあまりない場合には(すなわち、$は< 6ホップ?)ので、[原文のまま]スタックオーバーフローの再帰を使用しても大丈夫です。
最も難しいのは、結果を読み取って各パスのノードを抽出することです。多くの審議の後、私は結果を格納するためにTree :: Nary(n-aryツリー)を使うことに決めました。すべてのパスを抽出するために
|-> B -> D
A -> |-> C -> E -> D
は、実行します:
- は、各リーフノードから
- スタートは、その親を経由して逆方向に移動するすべてのリーフノードを見つける終わりに、私たちは以下のツリーを持っていますルートノードに追加し、ノード名を保存します。
上記はperlを使用して実装されていますが、ハッシュテーブルにboost :: unordered_mapを使用してC++でも行っています。私はまだC++コードにツリー構造を追加していません。
結果:3281415エッジと18601個のユニークノードの場合、PerlはA - > '*' - > '*' - > Bを見つけるのに3分かかります。準備ができたらC++コードのアップデートを提供します。
これは私が見つけたものです:http://www.vldb.org/conf/1989/P185.PDF – Diego
パスは単純なパスである必要がありますか?あるいは、サイクルを持つことができますか? – templatetypedef
サイクルを持つことは、無限の解を意味します。 – Faylixe