前言:map是STL的一种关联式容器,他提供一对一的Hash映射,因此使用中也常常可pair数据结构结合使用,map内部自建一棵红黑树,这棵树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,也基于此,不能直接改变元素的key,因为这会破坏正确次序,要修改元素的key,必须先移除该key的元素,然后插入拥有新的key/value的元素;任何两个元素没有相同的key值;
1:模板头定义
namespace std
{
template<typename Key, typename T,
typename Compare = less<key> >,
typename Allocator = allocator<pair<const Key, T> > >
class map;
}
要求:
1:key/value必须具备assignable(可赋值的),和copyable(可复制的)性质;
2:对于排序准则而言,key必须是comparable(可比较的);
3:第三或第四个参数缺省,排序准则使用operator<进行比较;
2:map构造函数和析构函数
// 以下构造函数对于multimap也是一样的意义
map c; // 产生一个空的map,其中暂时不包含任何元素
map c(op); // 以op为排序准则,产生一个空的map
map c1(c2); // 产生某个map的副本,所有元素均被复制
map c(beg, end); // 以区间[beg, end)内的元素产生一个map
// 以op为排序准则,利用[beg, end)内的元素生成一个map
map c(beg, end, op);
c.~map(); // 销毁所有元素,释放内存
3:数据的插入
三种数据插入方法:
// 方法一:
// 用insert函数插入pair数据
map<int, string> c;
c.insert(pair<int, string>(1, "Hello map"));
// 方法二:
// 用insert函数插入value_type数据
/*
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map
{
public:
typedef Key key_type;
typedef pair<const Key, T> value_type;
......
};
// 可以看到map的value_type的方法,实际上就是第一种方法的变身
注:因为每个容器迭代器的*运算符得到的结果都是该容器的value_type值;
*/
c.insert(map<int, string>::value_type(2, "second test"));
// 方法三:
// 使用索引的方式,以operator[]进行数据的插入
c[3] = "third test";
注意:
1)以上三种方式虽然都可以实现数据的插入,但是它们是有区别的,第一种和第二种都是使用insert方法来插入,效果基本上是一样的,这个时候插入的的新元素的key如果已经存在待插入数据的map中了,则insert操作失败,map中不能插入相同key的元素;
2)但是如果是使用operator[] 插入数据值,当待插入新元素的key已经存在于map中,则它可以覆盖以前该关键字对应的值;
// 示例代码:
map<int, string> c;
c.insert(pair<int, string>(1, "Hello map"));
cout << c[1] << endl;
c.insert(map<int, string>::value_type(2, "second test"));
cout << c[2] << endl;
c[3] = "third test";
cout << c[3] << endl;
// 不影响原来关键字对应的值,也不会报错或警告
c.insert(pair<int, string>(1, "Hello map else"));
cout << c[1] << endl;
// 不影响原来关键字对应的值
c.insert(map<int, string>::value_type(2, "second test else"));
cout << c[2] << endl;
// 覆盖了原来关键字为3的值
c[3] = "fourth test";
cout << c[3] << endl;
运行效果:
4:大小相关成员函数
c.size(); // 返回容器的大小
c.empty(); // 判断容器大小是否为零,等同于size() == 0;
c.max_size(); // 返回可容纳的最大元素数量
c1 == c2;
c2 != c2;
c1 < c2;
c1 > c2;
c1 <= c2;
c1 >= c2;
5:数据的遍历
3种方法:
// 方法一:
// 使用前向迭代器
cout << "===============前向迭代器测试===============" << endl;
map<int, string>::iterator it;
for(it = c.begin(); it != c.end(); it++)
{
cout << (*it).first << ": " << it->second << "; ";
}
cout << endl;
cout << "================前向迭代器测试==============" << endl;
// 方法二:
// 使用反向迭代器
cout << "\n===============反向迭代器测试===============" << endl;
map<int, string>::reverse_iterator iter;
for(iter=c.rbegin(); iter != c.rend(); iter++)
{
cout << iter->first << ": " << (*iter).second << "; ";
}
cout << endl;
cout << "===============反向迭代器测试===============" << endl;
// 方法三
// 使用operator[]下标索引方式遍历, 有局限,如key中为int时不连续?
// 但用该方法进行数据的访问还是很方便的;
cout << "\n===============operator[]测试===============" << endl;
int size = c.size();
for(int i = 1; i<= size; i++)
{
cout << c[i] << " ";
}
cout << endl;
cout << "===============operator[]测试===============" << endl;
// 注意:以上这段代码中for语句中只针对特定代码,不具有普遍意义
遍历小结:
// map迭代器相关
c.begin(); // 返回一个双向迭代器,指向第一个元素
c.end(); // 返回一个双向迭代器,指向最后元素的下一位置
c.rbegin(); // 返回一个逆向迭代器,指向逆向遍历时的第一个元素
c.rend(); // 返回一个逆向迭代器,指向逆向遍历时的最后元素的下一位置
6:查找相关
c.count(key); // 返回“键值等于key”的元素个数
c.find(key); // 返回“键值等于key”的第一个元素,找不到就返回end()
c.lower_bound(); // 返回“键值为key”的元素的第一个可安插位置,
// 也就是“键值>=key”的第一个元素位置
c.upper_bound(key); // 返回“键值为key”的元素的u自后一个可安插位
// 置,也就是“键值>key”的第一个元素位置
c.equal_range(key); // 返回“键值为key”的元素的第一个可安插位置和最
// 后一个可安插位置,也就是“键值==key”的元素区间
另外: 如果想要查找拥有某特定value的元素,则需要使用算法find_if();或自己封装一个函数进行查找,封装代码如下:
int my_find(map<int, string>::iterator _begin,
map<int, string>::iterator end, string value)
{
map<int, string>::iterator begin = _begin;
while(begin != end)
{
if(begin->second == value)
{
return begin->first;
}
begin++;
}
return -1;
}
7:数据的插入与移除,清空
c.insert(elem); // 安插一个elem副本,返回新元素位置
c.insert(pos, elem); // 安插一份elem副本,返回新元素位置(pos是个提示,指出安插操作的搜寻起点,如果提示恰当,可大大加快速度)
c.insert(beg, end); // 将区间[beg, end)内所有元素的副本安插到c,无返回值
c.erase(_key); // 移除key == _key相等的所有元素,返回被移除的元素个数
c.erase(pos); // 移除迭代器pos所指示位置上的元素,无返回值
c.erase(beg, end); // 移除区间[beg, end)内所有元素,无返回值
c.clear(); // 移除全部元素,将整个容器清空
/*
注意:对于STL而言位置指的都是迭代器的一个指示,即游标,
如上面的pos,beg, end指的都是迭代器,以上的elem值的不是某一个单独的值,而是一个key/value组成的pair;
*/
8:注意辅助数据结构pair的定义
// pair的定义
template<typename T1, typename T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
// 只有这两个数据成员
T1 first;
T2 second;
// 这里的语法为零初始化,如int(),即T()表示对应数据类型的0值表示
pair():first(T1()),second(T2()){}
pair(const T1& a, const T2& b):first(a), second(b){}
template<typename U, typename V>
pair(const pair<U, V>& p):first(p.first), second(p.second){}
};
// 另外还有一些以外部函数的形式重载的运算符重载函数,比如:
template<typename T1, typename T2>
bool operator<(const pair<T1, T2> &, const pair<T1, T2>&);
template<typename T1, typename T2>
pair<T1, T2> make_pair(const T1& a, const T2& b)
{
return pair<T1, T2>(a, b);
}
小结:
C++ STL集结了开发人员很多的智慧,积极从本文中只能了解到是什么,更多的精华还得在使用时慢慢去体会;实践方能出真知, 加油!
参考资料:
《C++标准程序库》
http://www.kuqin.com/cpluspluslib/20071231/3265.html
http://blog.csdn.net/wallwind/article/details/6876892