您的位置:首页 > 理论基础 > 数据结构算法

STL关联式容器——set和map

2016-08-02 15:47 267 查看
“说话的方式简单点!”

set和map,面试中常被问及的两个容器。虽然看过多变,但没被问及,依旧千头万绪,不知从何说起。在此,我想尽可能简单通俗的再记录下这部分知识,算是总结和二次学习。

STL容器是什么就不说了,所谓容器就是用来放东西的,只不过这里的东西是指各种数据结构。STL中的容器大概可以分为两种,一种是序列式容器(线性的数据存放),一种是关联式容器(非线性的二叉树结构)。而关联式容器最具代表性的便是set和map,所以他们在面试中总是一起出现。

先说必须要知道的重点:set和map底层的实现(就是存放数据的样子)都是红黑树,之所以如此,是因为树型结构方便查找。(全文终。。。)

红黑树

那么先记住什么是红黑树。红黑树是一种(平衡)二叉查找树,所谓“红”和“黑”指的是节点的颜色,就是说树中的节点,除了存储了节点的值以外,还有一个存储位用来记录这个节点是红的还是黑的。(至于节点红色黑色到底是什么意思?红黑树又有哪些性质?你们还是自己去专门学习吧,毕竟这是一篇科普文。我建议学习过程是:二叉树->搜索二叉树->平衡二叉树->2-3树(这很关键,算了贴篇文章吧)->红黑树)。

而红黑树的操作无非是节点的插入、删除和查找,这很复杂而且记不住而且用不到(对我来说),所以不管了,反正重点就是不管你怎么插入、删除,树要保持平衡。由于RB-tree的各种操作时常需要上溯到其父节点,所以节点数据结构中要存一个指向父节点的指针。

总结一下,红黑树的节点数据结构看起来应该是这个样子:有红黑二色,有左右子节点,有父节点。

typedef bool _rb_tree_color_type;
const _rb_tree_color_type _rb_tree_red = false;     //红色为0
const _rb_tree_color_type _rb_tree_black = true;    //黑色为1

class _rb_tree_node{
typedef _rb_tree_color_type color_type;

color_type color;           //节点颜色
_rb_tree_node*  parent;     //RB树的许多操作必须知道父节点
_rb_tree_node*  left;       //指向左节点
_rb_tree_node*  right;      //指向右节点
//......
};


set

重要的事说第二遍:set和map的底层是用红黑树实现的。

set,中文我们叫“集合”。它按照元素的键值自动排序存放,而且元素值不能重复。比如讲
{1,2,3,3,4,4,5,6}
序列存入一个set,等同于存序列
{1,2,3,4,5,6}
在存入一个元素时,如果发现set中已经有了这个元素,就不会再重复存了,multiset允许重复值

元素存入后自动排好了序,这也很好理解,因为红黑树本身就是一种二叉查找树。不过这里需要注意的是,我们不能够通过set的迭代器来改变元素的值。因为元素是拍好了序存在红黑树中的,如果你改变了一个节点的值,那么整棵树就要重新排序,这严重破坏了树的结构。

然后需要记住的一点是:当对set进行元素新增或删除操作时,迭代器并不会失效。当然被删除的那个元素除外。我们都知道迭代器的实现很复杂,但我们不管,我们就理解迭代器是一个指向容器内节点的指针。而当我们进行插入删除操作的时候,改变的不是节点的存储位置,改变的是它的三个指针(左右子女和父节点)的指向,所以迭代器指向的还是那个节点,不会失效。当然如果被指向的节点被删除了,那自另当别论。

然后在实际的应用中,关于set我们常用的方法:

#include <set>      //包含头文件
......
ietrator begin();   //返回指向第一个元素的指针(最小的元素)
ietrator end();     //指向set最后一个元素紧接着的后面位置
clear();            //删除容器中所有元素
empty();            //return begin() == end();所以set为空返回true,不空返回false;
insert();           //插入一个元素
erase();            //删除一个元素;
//iterator erase( const_iterator pos )可以删除一个迭代器指向的位置,返回下一个位置的迭代器;
//或者指定删除某个值的元素,size_type erase( const key_type& key );
//或删除一个范围,void erase( iterator first, iterator last );
find();             //查找某个元素


map

重要的事说第三遍:set和map的底层是用红黑树实现的.

map,映射表。与set每个元素只有一个值不同的是,map每个元素存入的值都是一对值(两个值),
pair<key,value>;
第一个元素是键值(按照它来排序),第二个元素是实值,键值是不允许重复的,multimap允许重复键值

哎呀,作为一篇科普文,实在是没什么好说的了。因为map就是存入一对值,其它要注意的地方都和set差不多。不能通过map的迭代器更改元素键值内容,因为关系到元素的排列。插入、删除操作不会使迭代器失效,原因同set。

硬是要多学点的话,看看map的实际使用吧:

#include <map>//头文件

//用起来像这样
map<std::string, int> mymap;  //map存一对数,使用模板的时候自然要确定两个参数类型

begin();//不多谈
end();

empty();//还是return begin()==end();

clear();//清空

inset();//这个有点复杂
//插入一个对数据("michael",
4000
23333);有多种方法
//可以用构造
mymap("michael") = 23333;
//或者使用pair
mymap.inset(pair<string,int>("michael",23333));

find(); //查找某个键值

//还有使用元素的第一个值(键值)和第二个值(实值)的方法,利用迭代器it
it->first;
it->second;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  stl 面试 数据结构 set map