【问题标题】:Best c++ container to strip items away from?剥离物品的最佳 C++ 容器?
【发布时间】:2010-10-04 03:37:13
【问题描述】:

我有一个文件列表(存储为 c 样式字符串),我将对其执行搜索,我将删除那些与我的参数不匹配的文件。用于此目的的最佳容器是什么?我现在正在考虑设置。请注意,文件列表永远不会比初始化时大。我只会从容器中删除。

【问题讨论】:

    标签: c++ list vector set containers


    【解决方案1】:

    我将从扔掉向量开始,因为它是一个顺序容器。设置,我相信接近于顺序或散列。我会避免这种情况。一个双向链表,stl 列表就是其中之一,有两个指针和节点。基本上,要删除一个项目,它会破坏链,然后用指针重新连接两个部分。

    【讨论】:

      【解决方案2】:

      std::set 中的元素必须是唯一的,因此除非文件名是全局唯一的,否则这将无法满足您的需求。

      我可能会推荐一个 std::list。

      【讨论】:

        【解决方案3】:

        来自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_sethash_multiset 如果你这样做,setmultiset 如果你希望字符串被排序,或者listslist 如果你希望字符串保持它们的插入顺序。

        创建列表/集后,使用remove_if 根据您的条件过滤掉您的项目。

        【讨论】:

          【解决方案4】:

          假设您的搜索条件不依赖于文件名(即您搜索内容、文件大小等),因此您不能使用集合,我会选择list。构建整个列表需要 O(N),每次删除需要 O(1)。

          如果你想让它更快,并且不坚持使用现成的 STL 容器,我会:

          1. 使用vector
          2. 使用假删除,即删除。将项目标记为已删除
          3. 当删除/所有项目的比率超过某个阈值时,我会过滤带有remove_if 的项目

          这应该会给你最好的空间/时间/缓存性能。 (尽管您应该对其进行分析以确保)

          【讨论】:

            【解决方案5】:

            你可以使用两个列表/向量/随便什么:

            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);
                }
            }
            

            【讨论】:

            • 如果您使用列表,您还可以将一个列表中的项目拼接到另一个列表中,而不是复制它们。
            【解决方案6】:

            我绝对不会使用集合——你不需要对它进行排序,所以使用集合没有意义。 Set 通常实现为自平衡树,在您的情况下不需要自平衡算法。

            如果您要执行一次此操作,我将使用带有 remove_if 的 std::vector(来自 ),然后是擦除。如果您以前没有使用过 remove_if,它的作用是遍历所有相关项并将所有相关项向下移动,覆盖该过程中不相关的项。您必须在其后进行擦除以减小矢量的大小。像这样:

            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 并使用三倍的空间。

            【讨论】:

              猜你喜欢
              • 2011-08-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-07-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多