我们之前学习的vector list是序列式容器因为其底层为线性序列的数据结构,里面存储的是元素本身。
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是
STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)为其底层结果,容器中的元素是一个有序的序列。
1.构造某一类型的空容器
set<int> s1;
2.构造set的拷贝
set<int> s2(s1);
3.用迭代器区间中的元素构造set
string s("abcd");
set<string> a(s.begin(),s.end());
成员函数 | 功能 |
---|---|
empty | 检测set是否为空,空返回true,否则返回true |
size | 返回set中有效元素的个数 |
insert | 在set中插入元素 |
erase | 删除set中的元素 |
find | 查找指定元素 |
swap | 交换set中元素 |
clear | 将set中的元素清空 |
count | 获取容器中指定元素值的元素个数 |
set<int> s;
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(14);
s.insert(36);
s.insert(4);
s.insert(3);
s.insert(3);
//1.排序+去重
//遍历方式1
set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//遍历方式2
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
//检查单词拼写是否正确
//思路:词库中单词都放进set的对象中,把每个写出来的单词
//去set中查一下,在不在,在就是正确的,不在就是错误的拼写
set<string> strSet;
strSet.insert("sort");
strSet.insert("left");
strSet.insert("right");
strSet.insert("insert");
//先找到,找到了再删
auto pos = s.find(4);
if (pos != s.end())
{
s.erase(pos);
}
set<string>::iterator ret = strSet.find("sort");
if (ret != strSet.end())
{
cout << "找到了" << endl;
}
else
{
cout << "没有找到" << endl;
}
ret = strSet.find("bet");
set<int>::reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
cout << *it << endl;
++it;
}
if (ret != strSet.end())
{
cout << "找到了" << endl;
}
else
{
cout << "没有找到" << endl;
}
multiset容器和set容器的区别是:multiset允许键值冗余,即multiset容器当中存储的元素是可以重复的。
void test_set2()
{
multiset<int> s;
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(14);
s.insert(36);
s.insert(4);
s.insert(3);
multiset<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << s.count(3) << endl;//计算有几个
}
1.构造一个空容器
map<int, int> m1; //构造一个key为int类型,value为int类型的空容器
2.拷贝构造
map<int, int> m2(m1); //拷贝构造key为int类型,value为int类型
3.构造迭代器某一区间
map<int, int> m3(m2.begin(), m2.end()); //使用迭代器拷贝构造m2容器某段区间
插入函数的原型:
pair<iterator,bool> insert (const value_type& val);
value_type 实际上是pair类型的别名,因此,我们向map容器插入元素时,需要用key和value构造一个pair对象,然后再将pair对象作为参数传入insert函数。
1.构造匿名对象插入
map<int, double> m;
//调用pair的构造函数,构造一个匿名对象插入
m.insert(pair<int,double>(1,1.1));
m.insert(pair<int, double>(2, 2.1));
m.insert(pair<int, double>(5, 5.1));
m.insert(pair<int, double>(5, 4.1));//k相同则插入失败
2.用函数模板构造对象
//好处是不需要去声明Pair的参数,让函数模板自己推演,用起来方便些
m.insert(make_pair(2, 2.2));
map<int, double>::iterator it = m.begin();
while (it != m.end())
{
cout << (*it).first<<":"<<(*it).second << endl;
++it;
}
cout << endl;
}
**注意:**insert函数的返回值也是一个pair对象,该pair对象中第一个成员的类型是map的迭代器类型,第二个成员的类型的一个bool类型。
具体含义如下:若待插入元素的键值key在map当中不存在,则insert函数插入成功,并返回插入后元素的迭代器和true。
若待插入元素的键值key在map当中已经存在,则insert函数插入失败,并返回map当中键值为key的元素的迭代器和false。
函数原型:
iterator find (const key_type& k);
map的查找函数是根据所给key值在map当中进行查找,找到了,则返回对应元素的迭代器,若未找到,则返回容器中最后一个元素下一个位置的正向迭代器。
set<string> strSet;
strSet.insert("sort");
strSet.insert("left");
strSet.insert("right");
strSet.insert("insert");
//先找到,找到了再删
auto pos = s.find(4);
if (pos != s.end())
{
s.erase(pos);
}
set<string>::iterator ret = strSet.find("sort");
if (ret != strSet.end())
{
cout << "找到了" << endl;
}
else
{
cout << "没有找到" << endl;
}
函数原型:
(1)
void erase (iterator position);//根据迭代器删除元素
(2)
size_type erase (const key_type& k);//删除该元素的函数值
(3)
void erase (iterator first, iterator last);//删除迭代器区间
int main ()
{
std::map<char,int> mymap;
std::map<char,int>::iterator it;
// insert some values:
mymap['a']=10;
mymap['b']=20;
mymap['c']=30;
mymap['d']=40;
mymap['e']=50;
mymap['f']=60;
it=mymap.find('b');
mymap.erase (it);
mymap.erase ('c');
it=mymap.find ('e');
mymap.erase ( it, mymap.end() );
// show content:
for (it=mymap.begin(); it!=mymap.end(); ++it)
std::cout << it->first << " => " << it->second << '\n';
return 0;
}
函数原型:
mapped_type& operator[] (const key_type& k);
[]的返回值
(*((this->insert(make_pair(k, mapped_type()))).first)).second
解析:
调用insert函数利用函数模板插入键值对。
拿出从insert函数获取到的迭代器(first)。
返回该迭代器位置元素的值value(second)。
int main ()
{
std::map<char,std::string> mymap;
mymap['a']="an element";
mymap['b']="another element";
mymap['c']=mymap['b'];
std::cout << "mymap['a'] is " << mymap['a'] << '\n';
std::cout << "mymap['b'] is " << mymap['b'] << '\n';
std::cout << "mymap['c'] is " << mymap['c'] << '\n';
std::cout << "mymap['d'] is " << mymap['d'] << '\n';
std::cout << "mymap now contains " << mymap.size() << " elements.\n";
return 0;
}
operator[]的原理是:
用
如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
operator[]函数最后将insert返回值键值对中的value返回。
void test_3()
{
//1.统计次数2.找出大家最喜欢(出现次数最多)的三种水果
string arr[] = { "香蕉","苹果","香蕉","榴莲","草莓","苹果","香蕉","苹果","西瓜","西瓜","香蕉" };
map<string, int> countMap;
for (const auto& str : arr)
{
//思路:第一次出现插入,后续再出现就++次数ret->second
map<string, int>::iterator ret = countMap.find(str);
if (ret != countMap.end())
{
ret->second++;
}
else
{
countMap.insert(make_pair(str, 1));
}
}
//方法2
for (const auto& str : arr)
{
auto ret = countMap.insert(make_pair(str, 1));
if (ret.second == false)
{
ret.first->second++;
}
}
//方法3
map<string, int> countMap;
for (const auto& str : arr)
{
countMap[str]++;
}
//对水果次数排序的思路
vector<map<string, int>::iterator> v;
vector<map<string, int>::iterator> v;
map<string, int>::iterator countMapIt = countMap.begin();
while (countMapIt != countMap.end())
{
v.push_back(countMapIt);
++countMapIt;
}
sort(v.begin(), v.end(), MapItCompare());
//利用Map排序 拷贝Pair数据
map<int, string> sortMap;
for (auto e : countMap)
{
sortMap.insert(make_pair(e.second, e.first));
}
//利用set排序 不拷贝pair数据
set<map<string, int>::iterator, MapItCompare> sortSet;
countMapIt = countMap.begin();
while (countMapIt != countMap.end())
{
sortSet.insert(countMapIt);
++countMapIt;
}
//优先级堆列排序
typedef map<string, int>::iterator M_IT;
priority_queue<M_IT, vector<M_IT>, MapItCompare> pq;
countMapIt = countMap.begin();
while (countMapIt != countMap.end())
{
pq.push(countMapIt);
++countMapIt;
}
}
【总结】