【发布时间】:2010-10-04 03:37:13
【问题描述】:
我有一个文件列表(存储为 c 样式字符串),我将对其执行搜索,我将删除那些与我的参数不匹配的文件。用于此目的的最佳容器是什么?我现在正在考虑设置。请注意,文件列表永远不会比初始化时大。我只会从容器中删除。
【问题讨论】:
标签: c++ list vector set containers
我有一个文件列表(存储为 c 样式字符串),我将对其执行搜索,我将删除那些与我的参数不匹配的文件。用于此目的的最佳容器是什么?我现在正在考虑设置。请注意,文件列表永远不会比初始化时大。我只会从容器中删除。
【问题讨论】:
标签: c++ list vector set containers
我将从扔掉向量开始,因为它是一个顺序容器。设置,我相信接近于顺序或散列。我会避免这种情况。一个双向链表,stl 列表就是其中之一,有两个指针和节点。基本上,要删除一个项目,它会破坏链,然后用指针重新连接两个部分。
【讨论】:
std::set 中的元素必须是唯一的,因此除非文件名是全局唯一的,否则这将无法满足您的需求。
我可能会推荐一个 std::list。
【讨论】:
来自SGI:
vector 是一个序列,它支持随机访问元素、在末尾恒定时间插入和移除元素,以及在开头或中间线性时间插入和移除元素。
list 是一个双向链表。也就是说,它是一个既支持前向遍历又支持后向遍历的序列,以及(摊销的)常量时间在开头或结尾或中间插入和移除元素。
slist 是一个单链表:每个元素都链接到下一个元素,但不链接到前一个元素。也就是说,它是一个支持前向但不支持后向遍历,以及(摊销)常数时间插入和移除元素的序列。
Set 是一个排序关联容器,用于存储 Key 类型的对象。 Set 是一个简单关联容器,这意味着它的值类型以及它的键类型都是 Key。它也是一个独特的关联容器,这意味着没有两个元素是相同的。
Multiset 是一个排序关联容器,用于存储 Key 类型的对象。 Multiset 是一个简单关联容器,这意味着它的值类型以及它的键类型都是 Key。它也是一个多关联容器,这意味着两个或多个元素可能相同。
Hash_set 是一个散列关联容器,用于存储 Key 类型的对象。 Hash_set 是一个简单关联容器,这意味着它的值类型以及它的键类型都是 Key。它也是一个唯一关联容器,这意味着没有两个元素使用二元谓词 EqualKey 比较相等。
Hash_multiset 是一个散列关联容器,用于存储 Key 类型的对象。 Hash_multiset 是一个简单的关联容器,这意味着它的值类型以及它的键类型都是 Key。它也是一个多关联容器,这意味着两个或多个元素可以使用二元谓词 EqualKey 比较相等。
(有些容器被省略了。)
如果您只想拥有一个快速且不包含多个相同键的容器,我会选择hash_set。 hash_multiset 如果你这样做,set 或 multiset 如果你希望字符串被排序,或者list 或 slist 如果你希望字符串保持它们的插入顺序。
创建列表/集后,使用remove_if 根据您的条件过滤掉您的项目。
【讨论】:
假设您的搜索条件不依赖于文件名(即您搜索内容、文件大小等),因此您不能使用集合,我会选择list。构建整个列表需要 O(N),每次删除需要 O(1)。
如果你想让它更快,并且不坚持使用现成的 STL 容器,我会:
vector
remove_if 的项目
这应该会给你最好的空间/时间/缓存性能。 (尽管您应该对其进行分析以确保)
【讨论】:
你可以使用两个列表/向量/随便什么:
using namespace std;
vector<const char *> files;
files.push_back("foo.bat");
files.push_back("bar.txt");
vector<const char *> good_files; // Maybe reserve elements given files.size()?
for(vector<const char *>::const_iterator i = files.begin(); i != files.end(); ++i) {
if(file_is_good(*i)) {
new_files.push_back(*i);
}
}
【讨论】:
我绝对不会使用集合——你不需要对它进行排序,所以使用集合没有意义。 Set 通常实现为自平衡树,在您的情况下不需要自平衡算法。
如果您要执行一次此操作,我将使用带有 remove_if 的 std::vector(来自
std::vector<const char*> files;
files.erase(remove_if(files.begin(), files.end(), RemovePredicate()), files.end());
如果你想利用它的 O(1) 删除时间属性,编写代码来用 std::list 做同样的事情会有点困难。鉴于您只是在执行此一次性操作,可能会花费很少的时间您甚至不会注意到它,我建议您这样做,因为这是最简单的方法。
老实说,我认为您不会看到 std::list 和 std::vector 方法之间的速度差异太大。矢量方法只复制每个值一次,因此它实际上非常快,但占用的空间要少得多。在我看来,只有当您在整个应用程序的生命周期中进行大量添加和删除操作时,才真正合理地使用 std::list 并使用三倍的空间。
【讨论】: