Multiset(中)——STL中的multiset
2015-08-27 13:20
253 查看
Multiset的中文名是多重集合,其实就是集合的扩展版。唯一的不同是集合中一个值只能出现一次,而多重集合中一个值可以出现多次(在实现时,每个节点保存的是一个指针,指向一块内存,每个元素之间是连续的)。
粗略看了看MSDN,在STL中,multiset和set的成员函数声明也是基本一样的,一些需要注意的地方是:
set::insert(key)的返回值是一个pair<iterator, bool>,其中pair中的bool成员表明了key被插入之前,set中是否已存在相同的key。根据我在VS2010上的实验结果,如果set中已经存在相同key的元素,那么插入操作是会失败的,新的元素不会被插进去。而multiset::insert的返回值只是一个iterator,插入操作总是会成功的。
multiset::count(key)的返回值可能大于1。
multiset::size()的返回值是多重集合的势(cardinality),即multiset中元素的个数,而不是值的个数。比如,{1, 1, 2}的size是3,而不是2。
multiset::erase(key)会将对应的key全部删掉,所以对{1, 1, 2}调用erase(1)之后,它就变成了{2}。
只要key存在于集合中,set::equal_range(key)的返回值pair<iterator1, iterator2>总是会有++iterator1 == iterator2。但是对multiset来说就不一定了。
什么时候需要用multiset?当然是需要用set,但是又允许重复key存在的时候了。什么时候用set?我的答案是:需要随时往容器中插入元素,随时对元素进行快速查找,又需要按某种顺序对元素进行遍历的时候——如果没有第三项需求的话可以用非标准库的hash_或标准库的unordered_开头的容器。
举一个Wikipedia上的例子:假设我们需要将一个很大的数n分解为多个质数因子的乘积,并将这些质数因子存储在容器中,供以后查询和遍历用。比如对于n = 120 = 2
x 2 x 2 x 3 x 5,我们可以将它的质数因子存储为primeFactorMultiset = { 2, 2, 2, 3, 5 }。当然也可以用map,将质数因子本身存为key,将该因子的出现次数存为value。但是考虑一下下面的需求:
我们想知道n可以分解为多少个质数因子的乘积。如果用map的话,代码如下:
[cpp] view
plaincopy
int numPrimeFactors = 0;
for (auto iter = primeFactorMap.begin(); primeFactorMap.end() != iter; ++iter)
{
numPrimeFactors += iter->second;
}
for循环执行完后的numPrimeFactors才是我们想要的结果。
如果用multiset,我们只需要调用primeFactorMultiset.size()。
[align=left]我们想打印出2 2 2 3 5这样的序列。[/align]
用map要两重循环:
[cpp] view
plaincopy
for (auto iter = primeFactorMap.begin(); primeFactorMap.end() != iter; ++iter)
{
for (int i = 0; i < iter->second; ++i)
{
cout << iter->first << ' ';
}
}
用multiset只要一重循环,代码又简洁了一点:
[cpp] view
plaincopy
for (auto iter = primeFactorMultiset.begin(); primeFactorMultiset.end() != iter; ++iter)
{
cout << *iter << ' ';
}
对于insert中插入位置的解释:
对于set如果位置点的元素,将遵循插入元素(或结束,如果它将是最后)。注意,这只是一个提示,并不会强制将新的元素插入到集合容器内的位置(集合中的元素总是遵循特定的顺序)。成员类型的迭代器,const_iterator定义在地图作为一个双向迭代器指向的元素类型。而对于multiset除了上面的这个作用外,还可以根据插入的位置影响到它在链表的位置(同一个key的时候);
粗略看了看MSDN,在STL中,multiset和set的成员函数声明也是基本一样的,一些需要注意的地方是:
set::insert(key)的返回值是一个pair<iterator, bool>,其中pair中的bool成员表明了key被插入之前,set中是否已存在相同的key。根据我在VS2010上的实验结果,如果set中已经存在相同key的元素,那么插入操作是会失败的,新的元素不会被插进去。而multiset::insert的返回值只是一个iterator,插入操作总是会成功的。
multiset::count(key)的返回值可能大于1。
multiset::size()的返回值是多重集合的势(cardinality),即multiset中元素的个数,而不是值的个数。比如,{1, 1, 2}的size是3,而不是2。
multiset::erase(key)会将对应的key全部删掉,所以对{1, 1, 2}调用erase(1)之后,它就变成了{2}。
只要key存在于集合中,set::equal_range(key)的返回值pair<iterator1, iterator2>总是会有++iterator1 == iterator2。但是对multiset来说就不一定了。
什么时候需要用multiset?当然是需要用set,但是又允许重复key存在的时候了。什么时候用set?我的答案是:需要随时往容器中插入元素,随时对元素进行快速查找,又需要按某种顺序对元素进行遍历的时候——如果没有第三项需求的话可以用非标准库的hash_或标准库的unordered_开头的容器。
举一个Wikipedia上的例子:假设我们需要将一个很大的数n分解为多个质数因子的乘积,并将这些质数因子存储在容器中,供以后查询和遍历用。比如对于n = 120 = 2
x 2 x 2 x 3 x 5,我们可以将它的质数因子存储为primeFactorMultiset = { 2, 2, 2, 3, 5 }。当然也可以用map,将质数因子本身存为key,将该因子的出现次数存为value。但是考虑一下下面的需求:
我们想知道n可以分解为多少个质数因子的乘积。如果用map的话,代码如下:
[cpp] view
plaincopy
int numPrimeFactors = 0;
for (auto iter = primeFactorMap.begin(); primeFactorMap.end() != iter; ++iter)
{
numPrimeFactors += iter->second;
}
for循环执行完后的numPrimeFactors才是我们想要的结果。
如果用multiset,我们只需要调用primeFactorMultiset.size()。
[align=left]我们想打印出2 2 2 3 5这样的序列。[/align]
用map要两重循环:
[cpp] view
plaincopy
for (auto iter = primeFactorMap.begin(); primeFactorMap.end() != iter; ++iter)
{
for (int i = 0; i < iter->second; ++i)
{
cout << iter->first << ' ';
}
}
用multiset只要一重循环,代码又简洁了一点:
[cpp] view
plaincopy
for (auto iter = primeFactorMultiset.begin(); primeFactorMultiset.end() != iter; ++iter)
{
cout << *iter << ' ';
}
对于insert中插入位置的解释:
对于set如果位置点的元素,将遵循插入元素(或结束,如果它将是最后)。注意,这只是一个提示,并不会强制将新的元素插入到集合容器内的位置(集合中的元素总是遵循特定的顺序)。成员类型的迭代器,const_iterator定义在地图作为一个双向迭代器指向的元素类型。而对于multiset除了上面的这个作用外,还可以根据插入的位置影响到它在链表的位置(同一个key的时候);
相关文章推荐
- 学习-索引
- 桥设备透传802.1x报文
- 使用Octopress搭建静态博客网站
- html5 canvas 详细使用教程
- linux编程学习
- Apache与Tomcat有什么关系和区别
- react-native试玩(4)-新建项目
- js要入门?
- JSON example with Jersey + Jackson
- 架构师好比两面神
- 数据结构学习之路-第二章:静态单链表
- uva 10084 - Hotter Colder(多边形切割)
- nginx+tomcat java报Broken pipe错误
- Android View 的事件处理和分发原理简析
- 编码风格——linux内核开发的coding style
- OGG安装配置文档
- Android studio中正确引入so文件的方法
- 华为OJ(删除字符串中出现次数最少的字符)
- python文件中的__name__=='__main__'的使用及调用其他py文件中的函数方法
- java中的抽象类和接口