stl中map的使用

来源:互联网 发布:gis软件开发工程师 编辑:程序博客网 时间:2024/04/30 07:10

map是一种关联式容器,值以 键值对 "pair" 的形式储存,STL 的 map 以红黑树作为地底层结构。

  • 完整代码

概述

map中的元素以键值对 (pair) 的形式被储存。键值对的第一元素 first 为键值, 第二元素 second 为实值,第一元素键值不允许被改变,原因是 map 内部元素依据键值排序,若改变键值会影响 map 的结构。而第二元素可以被改变。

由于红黑树是一棵平衡二叉查找树,在查找上拥有 O(LogN) 的时间复杂度,故以它作为红黑树的底层结构最合适不过了。

map结构

现在以我们自己设计的红黑树为底层结构模拟实现一个 map
下面是红黑树的部分源代码(详细代码点击此处,红黑树介绍点这)

//红黑树主体template<class Key, class Value, class _KeyOfValue = __KeyOfValue<Value>>class RBTree{    typedef __RBTreeNode<Value> Node;    //插入    /*    返回值是一个键值对,若插入成功其第一元素为插入节点的迭代器,第二元素为 true, 若插入失败(说明树中已经存在要插得那个节点),则返以存在节点的迭代器,第二元素为 false    */    pair<Iterator, bool> Insert(const Value& value)    {...}protected:    Node *_header;//红黑树头结点

以上述的红黑树为底层结构,现设计的 map 如下:

template<class Key, class Value>class Map{    struct __KeyOfPair//从ValueType取得键值的方法(仿函数)    {        Key operator()(const pair<Key, Value> kv){            return kv.first;        }    };    typedef pair<const Key, Value> ValueType;//真正储存在红黑树节点中的值,是一个键值对    typedef RBTree<Key, ValueType, __KeyOfPair> RepType;//容器类型    //...public:    pair<Iterator, bool> Insert(const ValueType& kv)    {        return _t.Insert(kv);    }    Iterator Find(const Key& key)    {        _t.Find(key);    }    //下面才是map的特色    Value& operator[](const Key& key)    {        return (_t.Insert(make_pair(key, Value())).first)->second;    }    //...private:    RepType _t;

如上是我们自己实现的 map 。可以看到几乎所有操作都只是简单调用了红黑树的接口,但不同的是, map 增加了一个接口: operator[],这个才是 map 最大的特色。

map的使用

对于数组我们可以这样使用:

int a[10];a[0] = 10;a[1] = 20;//...

它最大的特点就是,可以在 O(1) 的时间复杂度上实现对数组任意下标位置数据的访问,哈希表中的直接定址法就是利用这种思想。
其实换个角度想想,我们可以认为“数组里的值是以键值对的形式储存”,键值对的第一元素(first)为下标,即 a[1] = 10; 中的下标 1,它不可以被改变,键值对的第二元素为该下标中储存的实值,即 a[1] = 10; 中的 10 ,但这种形式有个弊端——下标的类型只能是固定的 size_t。而map解决了这种弊端,只不过牺牲了一点时间(它对数据访问的时间复杂度为 O(LogN))。请看下面:

这里写图片描述

如上图所示,我们可以像访问数组那样去访问 map ,而且它的下标可以是任意类型。

下面我们看看它的实现代码:

    Value& operator[](const Key& key)    {        return (_t.Insert(make_pair(key, Value())).first)->second;    }

理解:

  • map 重载 operator[] 实现像数组那样通过下标访问元素;
  • 底层调用红黑树的 insert() 接口,尝试插入 key,该接口返回一个键值对,若插入成功键值对第一元素为插入节点的迭代器,第二元素为 true, 若插入失败(说明树中已经存在要插得那个节点),则返已存在节点 (即 key) 的迭代器,第二元素为 false。
  • 由上我们得出,(_t.Insert(make_pair(key, Value())).first) ,该句先调用红黑树的插入接口,其返回一个键值对,再通过 .first 取得键值对的第一元素,即被插入节点的迭代器;
  • (_t.Insert(make_pair(key, Value())).first)->second, 再通过 ->second 取得迭代器的第二元素,这次取得的元素是 map 的实值;
  • operator[] 返回值是 Value 类型的引用, 即 map 实值的引用,通过这个引用就可以改变其实值了;
  • 总结上述,通过下标 key 可以访问到其对应的实值 value,并且可以被改变,是不是和数组一样了。

其它插入方法法:
(以下以VS2013库中的为例)

调用 insert() 接口,但重点是对待插入元素的构造,提供以下几种构造方法。

这里写图片描述

对于其它的“删改查”操作,则是直接调用底层红黑树的接口。


【作者:果冻 http://blog.csdn.net/jelly_9】

——完!


原创粉丝点击