如果有很多条目,我会建立一个包含所有唯一目录名称(不是路径)的向量,并使用树(例如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
处理完第一行后,树将有两个节点。处理完第二行后,树将具有三个节点。处理完第 3 行后,树将有四个节点。处理完第 4 行后,树将有五个节点。处理完第 5 行后,树将有六个节点。
如果我碰巧遇到:C:\Models\1\B,则不会向“directory_names”(或“name_to_id_map”)添加新条目,但树现在将有八个节点。
我相信这个实现非常节省内存,因为 1) directory_names 只存储子字符串,而不是完整路径,以及 2) 永远不会为共享同一路径的一部分的两个目录创建多个字符串。本质上,在处理每个新目录时,只存储有关名称和路径的唯一信息(不包括 'name_to_id_map' 的开销,这对于实现适当的运行时与内存平衡似乎很重要)。
注意:我不太明白您所说的“和 2 个带有子树(INPUT)的选择路径”是什么意思。