最近学习了C++中关联容器的一些知识,在此总结加深记忆并方便复习,同时也希望能帮助到想了解C++关联容器相关知识的朋友。
类型
C++11中共有八种关联容器,分别为map,set,multiset,multimap,unordered_map,unordered_set,unordered_multimap,unordered_multiset。其中带multi的表示关键字可重复,带unordered表示为无序容器,无序容器使用哈希函数组织。map与set之间的不同主要是map为键值对,而set只有键。
声明及初始化
与vector,list等一样,map与set也是模板,下面定义了一个关键字(key)为string类型,值(value)为int类型的map以及类型为string的set:
std::map <std::string,int> m_map;
std::set <std::string> m_set;
可以用下面的方式来进行初始化:
std::map <std::string,int> m_map={{“Hi",1},{"Ha",3},{"He",10}};
std::set<std::string> m_set={"La","Ha","Hi"};
关键字类型与自定义比较函数
对于有序容器(map,set,multimap,multiset),关键字类型必须定义元素比较的方法,默认情况下,标准库使用关键字类型的<运算符来比较元素。无序容器的要求我暂时还没弄明白。。由于这个要求,当我们的键值类型为我们自己定义的类或某些没有定义<的类型时,我们必须为该类型重载<运算符或定义比较函数,且要遵循严格弱序。
例子如下:
class Sales_data
{
private:
int isbn;
public:
int GetIsbn()
{
return isbn;
}
}
bool Compare(const Sales_data &s1,const Sales_data &s2)
{
return s1.GetIsbn()<s2.GetIsbn();
}
std::multiset<Sales_data,decltype(Compare)*> bookStore(Compare);
使用decltype来指出自定义操作类型,加上星号来表示这是一个函数指针,然后使用Compare来初始化bookStore对象,当向bookStore中添加元素时将调用Compare来为对象排序。
操作
类型
key_type //map中为第一个参数的类型,set即为其唯一的参数类型
mapped_type //map独有的类型,就是其值类型
value_type //map为pair<const key_type,mapped_type>,set即为key_type
set<string>::key_type //即为string
set<string>::value_type //即为string
map<string,int>::key_type //即为string
map<string,int>::mapped_type //即为int
map<string,int>::value_type //即为pair<const string,int>
迭代器
与顺序容器一样,但set中迭代器为const,map不能改变键值。
map<std::string,int> m_map;
m_map.begin() //获取容器中首个元素的迭代器
m_map.cbegin() //获取const类型的迭代器,同理cend()。
m_map.end() //获取容器中最后一个元素的==下一位==的迭代器
//遍历容器
auto m_iterator=m_map.cbegin();
while(m_iterator!=m_map.end())
{
std::cout<<m_iterator->first<<m_iterator->second<<std::endl;
m_iterator++;
}
添加元素
使用insert方法,如插入一个map:
std::map<std::string,int> m_map;
m_map.insert({"Ha",5});
还可以向insert中传递两个迭代器,表示将两个迭代器中间的值都插入容器(按之前说明的比较方法)。
对不含重复关键字的容器来说,单个插入的insert将返回一个pair类型,其first成员为一个迭代器,指向具有该关键字的元素,second成员为一个bool类型,表示该元素是否本就存在于容器中。
对允许包含重复关键字的容器,单个插入的insert将返回一个迭代器,指向新元素的位置,不再返回bool值。因为对允许重复关键字来说,插入必然成功。
删除元素
关联容器定义了三个版本的迭代器,可以传入一个迭代器,指定要删除的元素,或传入一个迭代器对,指定删除范围。这两个版本均返回void。
第三个版本为传入一个关联容器的key_type参数,将删除所有匹配的元素,返回被删除的元素的数量。
某一类型元素数量
使用count,如:
auto number=m_map.count();
访问对象
使用下标访问
注意不能对允许重复的关键字的map使用下标,因为对应元素将不止一个。此外set也不可以使用下标。若下标所指元素不存在,将在容器中创建该键值对,并且值默认初始化。但注意使用at则不同,如m_map.at(“Ee”);由于不存在该元素,将抛出out_of_range异常。
下标操作符返回类型为该map的mapped_type类型,为左值,故可以改变其值,
使用find访问
m_map.find("Ha");
find的返回类型是一个迭代器,若存在有这个键值的元素,则返回指向该元素的迭代器(对于允许重复关键字的容器,返回第一个关键字为给定参数的迭代器),若不存在这样的元素,则返回尾后迭代器,即m_map.end()。
指定边界访问
m_map.lower_bound(k) //返回第一个关键字不小于k的迭代器
m_map.upper_bound(k) //返回第一个关键字大于k的迭代器
m_map.equal_range(k) //返回一个迭代器对的pair,表示关键字等于k的元素的范围,若不存在该元素,则两个迭代器均为m_map.end()
对multimap进行查找
//找出所有关键字为"Ha"的键值对
std::string searchType="Ha";
auto number=m_map.count();
auto m_iterator=m_map.find(searchType);
while(number)
{
std::cout<<m_iterator->first<<m_iterator->second<<std::endl;
m_iterator++;
number--;
}