エントリが多数ある場合は、すべての一意のディレクトリ名 (パスではない) のベクトルを作成し、ツリー (例: http://tree.phi-sci.com/ ) を使用して、表示されたすべてのパスをベクトルへの ID のシーケンス。既存のディレクトリが既に表示されているかどうかを判断するには、ハッシュ マップを使用して、現在のパス内のディレクトリ名ごとに一連の ID を作成します。パスが完全に一致する場合はスキップします。そうでない場合は、関連するノードをツリーに追加して、新しいパスを反映させます。注: これにより、ツリー内の複数のノードが同じ ID を参照する場合があります。
コードは次のとおりです。
std::vector< std::string > directories; // THIS IS THE INPUT!
std::vector< std::string > directory_names;
std::unordered_map< std::string, size_t > name_to_id_map;
tree< size_t > directory_paths;
for (auto idir = directories.begin(); idir != directories.end(); ++idir) {
// Convert directories to a sequence of IDs (if new names are found, add
// them to 'directory_names' and 'name_to_id_map'. This is pretty mechanical code.
std::vector< size_t > id_sequence = convert( *idir );
// Walk the tree looking for this ID sequence.
tree<size_t>::sibling_iterator current_tree_node;
bool found = true;
for (auto iid = id_sequence.begin(); iid != id_sequence.end(); ++iid) {
if ( found ) {
if ( !directory_paths.is_valid( current_tree_node ) ) {
// Find a match among the roots of the tree. Note: There might be a more elegant way to do this.
tree<size_t>::sibling_iterator iroot( directory_paths.head );
tree<size_t>::sibling_iterator iroot_end( directory_paths.feet );
++iroot_end;
// Note: If the tree is sorted, we can use equal_range!
current_tree_node = std::find( iroot, iroot_end, *iid );
found = ( current_tree_node != iroot_end );
}
else {
// Find a match among the siblings of 'current_tree_node'.
tree<size_t>::sibling_iterator ichild = directory_paths.begin_child( current_tree_node );
tree<size_t>::sibling_iterator ichild_end = directory_paths.end_child( current_tree_node );
// Note: If the tree is sorted, we can use equal_range!
current_tree_node = std::find( ichild, ichild_end, *iid );
found = ( current_tree_node != ichild_end );
}
}
if ( !found ) {
// Add this node to the tree as a child of current_tree_node.
if ( directory_paths.is_valid( current_tree_node ) ) {
current_tree_node = directory_paths.insert_after( current_tree_node, *iid );
}
else if ( !directory_paths.empty() ) {
current_tree_node = directory_paths.insert_after( directory_paths.feet, *iid );
}
else {
current_tree_node = directory_paths.set_head( *iid );
}
}
}
if ( !found ) {
// This directory path (i.e. *idir) has not been seen before.
...
}
}
たとえば、次の入力では、5 つの一意の名前 (C:、Models、A、1、B) が作成されます。
C:\Models\
C:\Models\A
C:\Models\A\1
C:\Models\B
C:\Models\B\1
最初の行が処理されると、ツリーには 2 つのノードが含まれます。2 行目が処理されると、ツリーには 3 つのノードが含まれます。3 行目が処理されると、ツリーには 4 つのノードが含まれます。4 行目が処理されると、ツリーには 5 つのノードが含まれます。5 行目が処理されると、ツリーには 6 つのノードが含まれます。
C:\Models\1\B に遭遇した場合、'directory_names' (または 'name_to_id_map') に新しいエントリは追加されませんが、ツリーには 8 つのノードが含まれます。
1) directory_names はフル パスではなく部分文字列のみを保存し、2) 同じパスの一部を共有する 2 つのディレクトリに対して複数の文字列が作成されることはないため、この実装は非常にメモリ効率が良いと思います。基本的に、新しいディレクトリが処理されるたびに、名前とパスに関する一意の情報のみが保存されます (「name_to_id_map」のオーバーヘッドは除きます。これは、適切なランタイムとメモリのバランスを実現するために重要と思われます)。
注:「およびサブツリー(INPUT)を持つ2つの選択されたパス」の意味がよくわかりませんでした。