STL +有序集+没有重复

时间:2010-12-16 16:54:25

标签: c++ collections stl duplicates std

我需要一组有序的值而不重复。 那么,什么是快速/最佳方法:

1 - 创建一个向量,对其进行排序并删除重复项? 2 - 使用一种“排序”向量(如果存在)?

哪一个可以更有效率?

10 个答案:

答案 0 :(得分:17)

为什么不使用std::set

答案 1 :(得分:5)

如果你要加载一次列表然后多次使用它,那么使用std :: vector而不是std :: set可能会更有效地使用内存并迭代它。

如果你要不断添加和删除元素,你一定要使用std :: set。

对于一般用途std :: set因为它的工作量较少(构建向量需要在完成附加所有元素后对其进行排序和删除),除非你特别需要低内存使用效率或其他一些表明需要矢量的表现。

答案 2 :(得分:3)

使用std :: set。它是有序的,它不允许重复。

唯一的缺点是你没有随机访问元素,虽然这没有被指定为一个要求。

答案 3 :(得分:1)

通常,如果我需要快速一次性使用,我会同时使用集合列表,并执行类似 this 的操作:

#include <set>
#include <list>
#include <string>
#include <iostream>

using namespace std;

int main() {

    // set prevents dupes, list preserves order
    set<string> theset;
    list<set<string>::iterator> thelist;
    
    // insertion is like this:
    auto insert = [&] (const string &str) {
        auto inserted = theset.insert(str);
        if (inserted.second)
            thelist.push_back(inserted.first);
    };

    // then, for example:
    insert("zebra");       // first zebra
    insert("chair a");     // first chair a
    insert("desk");        // first desk
    insert("desk");
    insert("chair b");     // first chair b
    insert("chair a");
    insert("chair a");
    insert("table");       // first table
    insert("chair a");
    insert("xylophone");   // first xylophone
    insert("zebra");
    
    // access can be done like:
    for (auto istr : thelist)
        cout << *istr << endl;
    
}

您不必在那里使用 lambda,在此示例中键入更容易。无论如何,输出:

zebra
chair a
desk
chair b
table
xylophone

这里的关键点是:

  • set::insert 返回一个有用的 <iterator,bool> 对,其中第一个值是新迭代器(如果插入)或现有迭代器(如果没有),第二个值为真(如果插入)或错误(如果不是)。
  • set::insert 不会使集合中的任何其他迭代器失效,无论插入是否发生。
  • 我们可以使用 set 来快速避免重复,使用 list 来保持顺序。
  • 将集合的迭代器存储在列表中只是为了避免复制值。

然后,实现是:

  • 构造一个 set 用于值(用于重复检查)和一个 list 迭代器(用于顺序保存)。
  • 插入时,始终尝试添加到集合中,但仅当它不在集合中时才添加到列表中(即,如果它不是受骗者)。
  • 在访问时,只需记住它是一个迭代器列表,而不是一个值列表,因此 list<set::iterator>::iterator 确实需要两级取消引用才能访问该值。

优点和缺点是:

  • 优点:易于实施。
  • 专业人士:有效。
  • 优点:不复制值。
  • Pro:使用普通旧 set 的唯一性语义。
  • 缺点:会使访问语法复杂化。
  • 缺点:如果要将整个列表转换为值列表,则必须遍历整个列表一次。
  • 缺点:你必须拖着两个容器四处走动。
  • 缺点:拥有自己的透明容器接口还不够花哨,也就是说,它本身并不是一个容器。

您必须以必须编写额外代码为代价来增强此功能并减少一些缺点的选项:

  • 使用 class 方法和其他任何您想要的方法将两个容器粘贴在 struct/insert 中,以便更轻松地携带它。
  • 如果您希望调用者能够知道它是否被插入,则从您的插入函数返回 .second(例如,如果没有插入,您可能必须删除它们或其他东西)。
  • 模板表示 class/struct 支持任何值类型。如果您想使用其他类型的集合或列表,您还可以为唯一的和有序的容器类型设置模板。
  • 如果您需要合适的 STL 容器的所有功能,请将整个内容包装在一个符合标准的 Container 接口中。

此外,您可以在那里找到有序集实现(此处的其他一些答案提供了链接)。当我只是快速编码时,我会使用我在这里描述的那个;这很简单,对我来说,这样做通常比获取现有实现更快。

答案 4 :(得分:0)

这取决于你想要的效率。如果你想要“快速”的东西,请使用std :: set&lt;&gt; (正如其他人已经建议的那样)。

然而,如果你需要chache一致性或者将事物保存在一个向量中(保证对齐的内存)而不是一个集合(没有任何保证,如果我没记错的话,实现为树)那么你将不得不直接std ::向量与一些标准算法相结合,假设您提供的容器已经排序(然后使检查更快),如std::binary_search()

答案 5 :(得分:0)

插入一个set take log(n)。排序是免费的。

插入向量(push_back)需要恒定的时间。对向量进行排序需要n * log(n)。 但是你仍然需要删除重复项。

如果你一次插入然后排序,你也可以考虑矢量。如果插入频繁设置是正确的。

答案 6 :(得分:0)

效率取决于您拥有的插入/访问的比率(即,您需要对矢量进行排序的次数)。如果性能在那里非常重要,我建议您尝试这两种方法,并使用最快的方法来实际应用程序使用。

注意:std::set不是排序向量,因为它在内存中不是连续的(它是树)。 你想要的“排序矢量”是一个超过std::vector的堆。请参阅:http://stdcxx.apache.org/doc/stdlibug/14-7.html

答案 7 :(得分:0)

始终有Loki::AssocVector

否则你可以轻松自己动手:

  • 使用std::vectorstd::deque作为基本容器
  • 使用lower_bound / upper_bound / equal_rangebinary_search通用算法查找对象
  • 当您已经知道该值不存在时,inplace_merge也很棒

但实际上,请使用std::set:)

答案 8 :(得分:0)

在.h或.hpp中尝试此操作:

struct TestWithTime
{
    TestWithTime(unsigned long long timeSecs) : m_timeSecs(timeSecs) {}

    unsigned long long m_timeSecs;
}

struct OrderedByTime
{
    bool operator() (const TestWithTime* first,  const TestWithTime* second) const
    {
        // Important: if the time is equal
        if (first->m_timeSecs == second->m_timeSecs)
        {
            // then compare the pointers
            return first < second;
        }
        return first->m_timeSecs < second->m_timeSecs;
    }
};

typedef std::set<TestWithTime*, OrderedByTime> OrderedDataByTime;

现在你可以使用你的OrderedDataByTime设置!!

答案 9 :(得分:-1)

有序集基本上是g ++中基于策略的数据结构,可将唯一元素保持在已排序的顺序中。它与STL中的set数据结构非常接近,后者以select location from dept where regexp_like(location,'ViCtoria|Tasmania','i') 复杂度执行操作,并且还以log(n)复杂度执行另外两个操作。 :)

  • log(n):小于order_of_key (n)
  • 的项目数
  • n:集合中第find_by_order(n)个元素(索引为0)

有关更多详细信息,follow this link