目录
1 概述
多集是按照特定顺序存储元素的容器,其中多个元素可以具有等效值。
在多集合中,元素的值也标识它(值本身就是键,类型为T)。多集合中元素的值不能在容器中修改(这些元素总是常量),但可以从容器中插入或删除它们。
在内部,多集合中的元素总是按照其内部比较对象(类型为Compare)指示的特定严格弱排序标准进行排序。
multiset容器通过关键字访问单个元素的速度通常unordered_multiset容器慢,但它们允许根据子集的顺序直接迭代。
多集通常被实现为二叉搜索树
容器特性:
- 关联性 关联容器中的元素由它们的键(Key)引用,而不是由它们在容器中的绝对位置引用。
- 有序性 容器中的元素始终遵循严格的顺序。所有插入的元素都按此顺序给定一个位置。
- 集合性 元素的值也是用来识别它的键(Key)。
- 多值性 容器中的多个元素可以具有等效的键
- 分配器感知 容器使用分配器对象来动态处理其存储需求。
其类图如下:
2 使用实例
void MultiSetSuite::find()
{
std::multiset<int> a = { 1, 2, 3, 4, 5, 5 };
auto it = a.find(5);
TEST_ASSERT_EQUALS(5, *it)
++it;
TEST_ASSERT_EQUALS(5, *it)
it = a.find(6);
TEST_ASSERT_EQUALS(true, it == a.end())
}
3 接口使用
3.1 construct
namespace details{
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 MultiSetSuite::construct()
{
std::multiset<int> a;
int values [] = { 10, 20, 30, 40, 50, 50};
std::multiset<int> b(values, values + 5);
std::multiset<int> c(values, values + 6);
std::multiset<int> d(b);
std::multiset<int> e(b.begin(), b.end());
std::multiset<int, details::object_compare> f;
std::multiset<int, bool (*)(int, int)> g(details::function_compare);
std::multiset<int> h = { 1, 2, 3, 4, 5, 6 };
TEST_ASSERT_EQUALS(true, a.empty())
TEST_ASSERT_EQUALS(5, b.size())
TEST_ASSERT_EQUALS(6, c.size())
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 MultiSetSuite::assigns()
{
int values[] = { 5, 3, 2, 2, 8, 9 };
std::multiset<int> a(std::begin(values), std::end(values));
std::multiset<int> b;
std::multiset<int> c;
b = a;
c = { 5, 3, 2, 2, 8, 9 };
TEST_ASSERT_EQUALS(6, a.size())
a = std::multiset<int>();
TEST_ASSERT_EQUALS(0, a.size())
TEST_ASSERT_EQUALS(6, b.size())
TEST_ASSERT_EQUALS(6, c.size())
}
3.3 iterators
void MultiSetSuite::iterators()
{
int values[] = { 5, 3, 2, 1, 8, 9, 9 };
int array[] = { 1, 2, 3, 5, 8, 9, 9 };
int rarray[] = { 9, 9, 8, 5, 3, 2, 1 };
std::multiset<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 MultiSetSuite::capacity()
{
std::multiset<int> a;
std::multiset<int> b = { 1, 2, 3, 4, 5, 5 };
TEST_ASSERT_EQUALS(true, a.empty())
TEST_ASSERT_EQUALS(0, a.size())
TEST_ASSERT_EQUALS(6, b.size())
TEST_ASSERT_EQUALS(b.max_size(), a.max_size())
}
3.5 insert
void MultiSetSuite::insert()
{
std::multiset<int> a;
std::multiset<int> b;
std::multiset<int> c;
std::multiset<int>::iterator it;
for(int i = 1; i <= 5; i++) a.insert(i * 10); //10 20 30 40 50
it = a.insert(20);//10 20 20 30 40 50
TEST_ASSERT_EQUALS(20, *it)
a.insert(it, 27);//10 20 20 27 30 40 50
a.insert(it, 26);//10 20 20 26 27 30 40 50
it = a.insert(it, 28);//10 20 20 26 27 28 30 40 50
TEST_ASSERT_EQUALS(28, *it)
b.insert(a.begin(), a.end());
int array[] = { 10, 20, 20, 26, 27, 28, 30, 40, 50};
c.insert({ 10, 20, 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)
}
说明:
- 返回iterator,指向新加入元素。
3.6 erase
void MultiSetSuite::erase()
{
std::multiset<int> a = { 10, 20, 26, 26, 27, 28, 30, 40, 50 };
auto it = a.erase(a.begin()); //20, 26, 26, 27, 28, 30, 40, 50
TEST_ASSERT_EQUALS(20, *it)
TEST_ASSERT_EQUALS(2, 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 MultiSetSuite::swap()
{
std::multiset<int> a = { 1, 2, 3, 4, 5, 5 };
std::multiset<int> b;
TEST_ASSERT_EQUALS(6, a.size())
TEST_ASSERT_EQUALS(0, b.size())
a.swap(b);
TEST_ASSERT_EQUALS(0, a.size())
TEST_ASSERT_EQUALS(6, b.size())
}
3.8 clear
void MultiSetSuite::clear()
{
std::multiset<int> a = { 1, 2, 3, 4, 5, 5 };
TEST_ASSERT_EQUALS(6, a.size())
a.clear();
TEST_ASSERT_EQUALS(0, a.size())
}
3.9 emplace
void MultiSetSuite::emplace()
{
std::multiset<std::string> names;
names.emplace("James");
names.emplace("Tom");
TEST_ASSERT_EQUALS(2, names.size())
auto it = names.emplace("James");
TEST_ASSERT_EQUALS("James", *it)
TEST_ASSERT_EQUALS(3, names.size())
}
说明:
- 返回iterator,指向新加入元素。
3.1 emplace_hint
void MultiSetSuite::emplace_hint()
{
std::multiset<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)
TEST_ASSERT_EQUALS(4, names.size())
}
说明:
- 返回值为iterator对象,指向新加入元素。
3.10 key_comp/value_comp
void MultiSetSuite::key_comp()
{
int array [] = { 1, 2, 3, 4, 4, 5, 5 };
std::multiset<int> a(array, array + 7);
std::multiset<int> b;
std::multiset<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(5, b.size())
}
void MultiSetSuite::value_comp()
{
int array [] = { 1, 2, 3, 4, 4, 5, 5 };
std::multiset<int> a(array, array + 7);
std::multiset<int> b;
std::multiset<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(5, b.size())
}
说明:
- 对multiset来说,key就是value,所以key_comp和value_comp是等效的
3.11 find/count
void MultiSetSuite::find()
{
std::multiset<int> a = { 1, 2, 3, 4, 5, 5 };
auto it = a.find(5);
TEST_ASSERT_EQUALS(5, *it)
++it;
TEST_ASSERT_EQUALS(5, *it)
it = a.find(6);
TEST_ASSERT_EQUALS(true, it == a.end())
}
void MultiSetSuite::count()
{
std::multiset<int> a = { 1, 2, 3, 4, 5, 5 };
TEST_ASSERT_EQUALS(2, a.count(5))
TEST_ASSERT_EQUALS(0, a.count(6))
}
3.12 lower_bound/upper_bound/equal_range
void MultiSetSuite::lower_bound()
{
std::multiset<int> a = { 10, 20, 30, 40, 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;
TEST_ASSERT_EQUALS(40, *it)
it = a.lower_bound(60);
TEST_ASSERT_EQUALS(true, it == a.end())
}
void MultiSetSuite::upper_bound()
{
std::multiset<int> a = { 10, 20, 30, 30, 40, 40, 50 };
auto it = a.upper_bound(30); // > 30
TEST_ASSERT_EQUALS(40, *it)
++it;
TEST_ASSERT_EQUALS(40, *it)
it = a.upper_bound(60);// > 60
TEST_ASSERT_EQUALS(true, it == a.end())
}
void MultiSetSuite::equal_range()
{
std::multiset<int> a = { 10, 20, 30, 30, 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 MultiSetSuite::get_allocator()
{
std::multiset<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)
}