C++容器之集合(std::set)

1 概述

  集合(set)是按照特定顺序存储唯一元素的容器。
  在集合中,元素的值也标识它(值本身就是键,类型为T),并且每个值都必须是唯一的。集合中元素的值不能在容器中修改(元素总是常量),但可以从容器中插入或删除它们。
  在内部,集合中的元素总是按照其内部比较对象(类型为Compare)指示的特定严格弱排序标准进行排序。
  集合容器通常比无序集合容器(unordered_set)通过关键字访问单个元素的速度慢,但它们允许根据子集的顺序直接迭代。
集合通常被实现为二叉搜索树
容器特性:

  • 关联性 关联容器中的元素由它们的键(Key)引用,而不是由它们在容器中的绝对位置引用。
  • 有序性 容器中的元素始终遵循严格的顺序。所有插入的元素都按此顺序给定一个位置。
  • 集合 元素的值也是用来识别它的键(Key)。
  • 唯一性 容器中没有两个元素可以具有等效的键。
  • 分配器感知 容器使用分配器对象来动态处理其存储需求。

其类图如下:
在这里插入图片描述

2 使用实例

void SetSuite::find()
{
    std::set<int> a = { 1, 2, 3, 4, 5 };
    auto it =  a.find(5);
    TEST_ASSERT_EQUALS(5, *it)
    it =  a.find(6);
    TEST_ASSERT_EQUALS(true, it == a.end())
}

3 接口使用

3.1 construct

bool function_compare(int l, int r) { return l < r; }
struct object_compare
{
    bool operator()(const int& l, const int& r) { return l < r; }
};
void SetSuite::construct()
{
    std::set<int> a;
    int values [] = { 10, 20, 30, 40, 50, 50};
    std::set<int> b(values, values + 5);
    std::set<int> c(values, values + 6);
    std::set<int> d(b);
    std::set<int> e(b.begin(), b.end());
    std::set<int, object_compare> f;
    std::set<int, bool (*)(int, int)> g(function_compare);
    std::set<int> h = { 1, 2, 3, 4, 5, 6 };

    TEST_ASSERT_EQUALS(true, a.empty())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(5, c.size())//Unique vaue
    TEST_ASSERT_EQUALS(5, d.size())
    TEST_ASSERT_EQUALS(5, e.size())
    TEST_ASSERT_EQUALS(true, f.empty())
    TEST_ASSERT_EQUALS(true, g.empty())
    TEST_ASSERT_EQUALS(6, h.size())
}

说明:

  • 构造时可以指定函数对象作为比较函数
  • 构造时可以指定函数指针作为比较函数

3.2 assigns

void SetSuite::assigns()
{
    int values[] = { 5, 3, 2, 1, 8, 9 };
    std::set<int> a(std::begin(values), std::end(values));
    std::set<int> b;
    std::set<int> c;
    
    b = a;
    c = { 5, 3, 2, 1, 8, 9 };
    TEST_ASSERT_EQUALS(6, a.size())
    a = std::set<int>();
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(6, b.size())
    TEST_ASSERT_EQUALS(6, c.size())
}

3.3 iterators

void SetSuite::iterators()
{
    int values[] = { 5, 3, 2, 1, 8, 9 };
    int array[] =  { 1, 2, 3, 5, 8, 9 };
    int rarray[] = { 9, 8, 5, 3, 2, 1 };

    std::set<int> a(std::begin(values), std::end(values));

    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
    
    index = 0;
    for(auto it = a.cbegin(); it != a.cend(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)

    index = 0;
    for(auto it = a.rbegin(); it != a.rend(); ++it)
        TEST_ASSERT_EQUALS(rarray[index++], *it)
    
    index = 0;
    for(auto it = a.crbegin(); it != a.crend(); ++it)
        TEST_ASSERT_EQUALS(rarray[index++], *it)
}

3.4 capacity

void SetSuite::capacity()
{
    std::set<int> a;
    std::set<int> b = { 1, 2, 3, 4, 5 };

    TEST_ASSERT_EQUALS(true, a.empty())
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
    TEST_ASSERT_EQUALS(b.max_size(), a.max_size())
}

3.5 insert

void SetSuite::insert()
{
    std::set<int> a;
    std::set<int> b;
    std::set<int> c;
    std::set<int>::iterator it;
    
    for(int i = 1; i <= 5; i++) a.insert(i * 10); //10 20 30 40 50
    std::pair<std::set<int>::iterator,bool> r = a.insert(20);//20 no inserted
    if(r.second == false)
    {
        it = r.first;
        TEST_ASSERT_EQUALS(20, *it)//*it = 20
    }
    a.insert(it, 27);//10 20 27 30 40 50
    a.insert(it, 26);//10 20 26 27 30 40 50
    a.insert(it, 28);//10 20 26 27 28 30 40 50
    b.insert(a.begin(), a.end());
    int array[] = { 10, 20, 26, 27, 28, 30, 40, 50};
    c.insert({ 10, 20, 26, 27, 28, 30, 40, 50});

    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)

    index = 0;
    for(auto it = b.begin(); it != b.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
    
    index = 0;
    for(auto it = c.begin(); it != c.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
}

说明:

  • 不带位置参数插入函数,返回std::pair对象,pair::first指新加入元素或集合中已存在元素,pair::second为true说明插入成功,为false说明集合中已有该元素
  • 带位置参数插入函数,返回iterator,指向新加入元素或集合中已存在元素。

3.6 erase

void SetSuite::erase()
{
    std::set<int> a = { 10, 20, 26, 27, 28, 30, 40, 50 };
    auto it = a.erase(a.begin()); //20, 26, 27, 28, 30, 40, 50
    TEST_ASSERT_EQUALS(20, *it)
    TEST_ASSERT_EQUALS(1, a.erase(26)) //20, 27, 28, 30, 40, 50
    TEST_ASSERT_EQUALS(0, a.erase(26)) //20, 27, 28, 30, 40, 50
    it = a.begin();
    ++it;
    TEST_ASSERT_EQUALS(27, *it)
    it = a.erase(it, a.end()); //20
    TEST_ASSERT_EQUALS(true, it == a.end())
    TEST_ASSERT_EQUALS(1, a.size())
}

说明:

  • 按值删除返回删除元素个数
  • 按位置删除返回iterator指向被删除元素的下一位置

3.7 swap

void SetSuite::swap()
{
    std::set<int> a = { 1, 2, 3, 4, 5 };
    std::set<int> b;

    TEST_ASSERT_EQUALS(5, a.size())
    TEST_ASSERT_EQUALS(0, b.size())

    a.swap(b);
    TEST_ASSERT_EQUALS(0, a.size())
    TEST_ASSERT_EQUALS(5, b.size())
}

3.8 clear

void SetSuite::clear()
{
    std::set<int> a = { 1, 2, 3, 4, 5 };
    TEST_ASSERT_EQUALS(5, a.size())
    a.clear();
    TEST_ASSERT_EQUALS(0, a.size())
}

3.9 emplace

void SetSuite::emplace()
{
    std::set<std::string> names;

    names.emplace("James");
    names.emplace("Tom");

    TEST_ASSERT_EQUALS(2, names.size())
    auto it = names.emplace("James");
    TEST_ASSERT_EQUALS(false, it.second)
    TEST_ASSERT_EQUALS(2, names.size())
}

说明:

  • 返回值为std::pair对象,pair::first指新加入元素或集合中已存在元素,pair::second为true说明插入成功,为false说明集合中已有该元素

3.1 emplace_hint

void SetSuite::emplace_hint()
{
    std::set<std::string> names = { "James", "Tom"};
    auto it = names.emplace_hint(names.begin(), "Rose");
    TEST_ASSERT_EQUALS("Rose", *it)
    it = names.emplace_hint(it, "Tom");
    TEST_ASSERT_EQUALS("Tom", *it)
}

说明:

  • 返回值为iterator对象,指向新加入元素或集合中已存在元素。

3.10 key_comp/value_comp

void SetSuite::key_comp()
{
    int array [] = { 1, 2, 3, 4, 5 };
    std::set<int> a(array, array + 5);
    std::set<int> b;
    std::set<int>::key_compare compare = a.key_comp();

    for(int i : a)
    {
        if(compare(i ,5))
            b.insert(i);
    }
    int index = 0;
    for(int i : b)
    {
        TEST_ASSERT_EQUALS(array[index++], i)
    }
    TEST_ASSERT_EQUALS(4, b.size())
}

void SetSuite::value_comp()
{
    int array [] = { 1, 2, 3, 4, 5 };
    std::set<int> a(array, array + 5);
    std::set<int> b;
    std::set<int>::value_compare compare = a.value_comp();

    for(int i : a)
    {
        if(compare(i ,5))
            b.insert(i);
    }

    int index = 0;
    for(int i : b)
    {
        TEST_ASSERT_EQUALS(array[index++], i)
    }
    TEST_ASSERT_EQUALS(4, b.size())
}

说明:

  • 对set来说,key就是value,所以key_comp和value_comp是等效的

3.11 find/count

void SetSuite::find()
{
    std::set<int> a = { 1, 2, 3, 4, 5 };
    auto it =  a.find(5);
    TEST_ASSERT_EQUALS(5, *it)
    it =  a.find(6);
    TEST_ASSERT_EQUALS(true, it == a.end())
}

void SetSuite::count()
{
    std::set<int> a = { 1, 2, 3, 4, 5 };
    TEST_ASSERT_EQUALS(1, a.count(5))
    TEST_ASSERT_EQUALS(0, a.count(6))
}

3.12 lower_bound/upper_bound/equal_range

void SetSuite::lower_bound()
{
    std::set<int> a = { 10, 20, 30, 40, 50 };

    auto it =  a.lower_bound(25);//>=25
    TEST_ASSERT_EQUALS(30, *it)

    it =  a.lower_bound(40);//>=40
    TEST_ASSERT_EQUALS(40, *it)

    it =  a.lower_bound(60);
    TEST_ASSERT_EQUALS(true, it == a.end())
}

void SetSuite::upper_bound()
{
    std::set<int> a = { 10, 20, 30, 40, 50 };

    auto it =  a.upper_bound(30); // > 30
    TEST_ASSERT_EQUALS(40, *it)

    it =  a.upper_bound(60);// > 60
    TEST_ASSERT_EQUALS(true, it == a.end())
}

void SetSuite::equal_range()
{
    std::set<int> a = { 10, 20, 30, 40, 50 };
    auto it =  a.equal_range(30); // >=30 & > 30
    TEST_ASSERT_EQUALS(30, *it.first)
    TEST_ASSERT_EQUALS(40, *it.second )

    it =  a.equal_range(25); // >= 25 & > 25
    TEST_ASSERT_EQUALS(30, *it.first)
    TEST_ASSERT_EQUALS(30, *it.second)
}

说明:

  • lower_bound 返回第一个大于等(>=)于指定值的iterator
  • upper_bound 返回第一个大于(>)指定值的iterator
  • equal_range 返回std::pair对象, pair::first是第一个大于等(>=)于指定值的iterator,pair::second是第一个大于(>)指定值的iterator

3.13 get_allocator

void SetSuite::get_allocator()
{
    std::set<int> a;
    auto allocator = a.get_allocator();
    int *p = allocator.allocate(5);

    TEST_ASSERT_EQUALS(true, p != nullptr)
    for(int i = 1; i <= 5; i++)
       p[i] = i * 10;
    
    allocator.deallocate(p, 5);

    try
    {
        p = allocator.allocate(allocator.max_size() + 1);
    }
    catch(...)
    {
        p = nullptr;
    }
    TEST_ASSERT_EQUALS(true, p == nullptr)
}
  • 26
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值