【问题标题】:Is there a sorted container in the STL?STL 中是否有排序容器?
【发布时间】:2013-03-13 00:39:38
【问题描述】:

STL 中有排序容器吗?

我的意思是:我有一个std::vector<Foo>,其中Foo 是一个定制类。我还有一个比较器,可以比较 Foo 类的字段。

现在,我正在代码中的某个地方:

std::sort( myvec.begin(), myvec.end(), comparator );

它将根据我在比较器中定义的规则对向量进行排序。

现在我想将Foo 类的元素插入到该向量中。如果可以的话,我只想写:

 mysortedvector.push_back( Foo() );

然后向量会根据比较器将这个新元素放到它的位置。

相反,现在我必须写:

myvec.push_back( Foo() );
std::sort( myvec.begin(), myvec.end(), comparator );

这只是浪费时间,因为向量已经排序,我只需要适当地放置新元素。

现在,由于我的程序的性质,我不能使用 std::map<>,因为我没有键/值对,只有一个简单的向量。

如果我使用stl::list,我需要在每次插入后再次调用排序。

【问题讨论】:

  • std::set 呢?
  • 如果你知道它会去哪里,你可以使用 insert()
  • @us2012,我查看了 std::set。问题是这些对象将呈现在一个网格中,用户可以在其中根据所有类成员对它们进行排序,并以他们认为合适的任何方式对其进行修改。由于 std::set 成员定义为 const,因此此容器不适合我。
  • @Igor 如果用户可以修改值,那么他们可以使容器未排序。这就是为什么std::set的元素是const

标签: c++ sorting vector stl container-data-type


【解决方案1】:

我想扩展 Jason 的 answer。我同意 Jason,std::setstd::multiset 是您特定场景的最佳选择。我想提供一个示例,以帮助您进一步缩小选择范围。

假设您有以下类Foo

class Foo {
public:
    Foo(int v1, int v2) : val1(v1), val2(v2) {};
    bool operator<(const Foo &foo) const { return val2 < foo.val2; }
    int val1;
    int val2;
};

这里,Foo 重载了 &lt; 运算符。这样,您无需指定显式比较器函数。因此,您可以通过以下方式简单地使用std::multiset 而不是std::vector。您只需将push_back() 替换为insert()

int main()
{
    std::multiset<Foo> ms;
    ms.insert(Foo(1, 6));
    ms.insert(Foo(1, 5));
    ms.insert(Foo(3, 4));
    ms.insert(Foo(2, 4));

    for (auto const &foo : ms)
        std::cout << foo.val1 << " " << foo.val2 << std::endl;

    return 0;
}

输出:

3 4
2 4
1 5
1 6

如您所见,容器根据&lt; 运算符按Foo 类的成员val2 排序。但是,如果您使用std::set 而不是std::multiset,那么您将获得不同的输出:

int main()
{
    std::set<Foo> s;
    s.insert(Foo(1, 6));
    s.insert(Foo(1, 5));
    s.insert(Foo(3, 4));
    s.insert(Foo(2, 4));

    for (auto const &foo : s)
        std::cout << foo.val1 << " " << foo.val2 << std::endl;

    return 0;
}

输出:

3 4
1 5
1 6

这里,val2 为 4 的第二个 Foo 对象丢失了,因为 std::set 只允许唯一的条目。条目是否唯一取决于提供的&lt; 运算符。在此示例中,&lt; 运算符将val2 成员相互比较。因此,如果两个Foo 对象的val2 成员具有相同的值,则它们是相等的。

因此,您的选择取决于您是否要存储基于&lt; 运算符可能相等的Foo 对象。

Code on Ideone

【讨论】:

    【解决方案2】:

    C++ 确实有排序容器,例如 std::set 和 std::map

    int main() 
    { 
        //ordered set
        set<int> s; 
        s.insert(5); 
        s.insert(1); 
        s.insert(6); 
        s.insert(3); 
        s.insert(7); 
        s.insert(2); 
    
        cout << "Elements of set in sorted order: "; 
        for (auto it : s) 
            cout << it << " "; 
    
        return 0; 
    } 
    

    输出: 按排序顺序设置的元素: 1 2 3 5 6 7

    int main() 
    { 
        // Ordered map 
        std::map<int, int> order; 
    
        // Mapping values to keys 
        order[5] = 10; 
        order[3] = 5; 
        order[20] = 100; 
        order[1] = 1; 
    
       // Iterating the map and printing ordered values 
       for (auto i = order.begin(); i != order.end(); i++) { 
           std::cout << i->first << " : " << i->second << '\n'; 
    } 
    

    输出:
    1:1

    3 : 5

    5 : 10

    20 : 100

    【讨论】:

      【解决方案3】:

      是的,std::setstd::multisetstd::mapstd::multimap 都使用std::less 作为默认比较操作进行排序。使用的底层数据结构通常是平衡的二叉搜索树,例如红黑树。因此,如果您将一个元素添加到这些数据结构中,然后遍历包含的元素,则输出将按排序顺序排列。将 N 个元素添加到数据结构的复杂度将为 O(N log N),或者与使用任何常见的 O(log N) 复杂度排序对 N 个元素的向量进行排序相同。

      在您的特定场景中,由于您没有键/值对,std::setstd::multiset 可能是您最好的选择。

      【讨论】:

      • 还有priority_queue?
      • 我同意@LushaLi:接受的答案还应该指向std::priority_queue,还应该指向std::make_heapstd::push_heapstd::pop_heap 依赖项。
      • @LushaLi std::priority_queue 不是Container,只能观察top 元素
      • 有趣的是,没有一个以易于使用的方式承认冗余密钥。 multimap 是唯一允许冗余键的,但作为列表使用并不容易。
      • @thang multiset 也承认冗余键(set 的键也是它的值)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      • 2010-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多