STL - map学习总结

前言: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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值