SET的节点是一个数据.
Map使用关键值Key来唯一标识每一个成员 map可以重复。
set是集合
都属于关联容器
只不过,map的形式 map<type1, type2> mymap;
set的形式 set<type> myset;
set(集合)——包含了经过排序了的数据,这些数据的值(value)必须是唯一的。
map(映射)——经过排序了的二元组的集合,map中的每个元素都是由两个值组成,其中的key(键值,一个map中的键值必须是唯一的)是在排序或搜索时使用,它的值可以在容器中重新获取;而另一个值是该元素关联的数值。比如,除了可以ar[43] = "overripe"这样找到一个数据,map还可以通过ar["banana"] = "overripe"这样的方法找到一个数据。如果你想获得其中的元素信息,通过输入元素的全名就可以轻松实现。
map是映射集合中的元素不能重复,set可以进行集合的各种操作(交并补等),当然你也可以用list或vector实现set,但是效率会很低。set一般是用平衡树或哈西表实现的。
映射是一种一一对应的关系,哈西表也可以看作是映射的一种。映射通常可用来实现字典结构(dictionary)
(1) 只有两个键都匹配才命中目标
(2) 两个键中任意一个匹配就命中目标
可以扩展到多键
(一) 介绍
特点:
1.map将Key的object和T的Object绑定到一起,因此是一种Pair Associative Container, 表示其value type为 pair。
2.它同时也是Unique Associative Container,表示没有两个元素具有相同的Key。
3.它还是一种Sorted Associative Container,因此第三个参数只能是less,greater之类的functor, 相比较而言,
hash table是 equal_to, not_equal_to之类的functor。
(二) 基本用法
通过以下范例,可以看出map的一些基本用法: 插入、查找、删除、遍历等等。
2 #pragma warning(disable: 4786)
3 #endif
4 #include < iostream >
5 #include < map >
6 #include < algorithm >
7 int main( int argc, char * argv[])
8 {
9 /* define a map */
10 std::map _map;
11
12 /* insert */
13 _map.insert( std::map::value_type( 0 , 32.8 ) );
14 _map.insert( std::map::value_type( 1 , 33.2 ) );
15 _map.insert( std::map::value_type( 2 , 35.8 ) );
16 _map.insert( std::map::value_type( 3 , 36.4 ) );
17 _map.insert( std::map::value_type( 4 , 37.8 ) );
18 _map.insert( std::map::value_type( 5 , 35.8 ) );
19
20 /* 这个是常用的一种map赋值方法 */
21 _map[ 7 ] = 245.3 ;
22
23 /* find by key */
24 std::map::iterator itr;
25 itr = _map.find( 4 );
26
27 if ( itr != _map.end() )
28 {
29 std::cout << " Item: " << itr -> first << " found, content: " << itr -> second << std::endl;
30 }
31
32 std::cout << std::endl;
33
34 /* delete item from map */
35 if ( itr != _map.end() )
36 {
37 _map.erase(itr);
38 }
39
40 /* travel through a map */
41 std::map::iterator itr1 = _map.begin();
42 for ( ; itr1 != _map.end(); ++ itr1 )
43 {
44 std::cout << " Item: " << itr1 -> first << " , content: " << itr1 -> second << std::endl;
45 }
46
47 std::cout << std::endl;
48
49 /* empty a map */
50 _map.clear();
51
52 return 0 ;
53 }
(三) 当Key是结构时该如何定义结构
比如 Key是结构MyStruct类型, 此时map可以定义如下:
std::map > _map;
其中Compare 缺省是std::less,这里可以不写,自定义的结构必须实现Compare指定的比较操作,因此自定义结构
MyStruct必须按照如下写法:
2 {
3 int key;
4
5 bool operator < ( const MyStruct rhs) const
6 {
7 return key < rhs.key;
8 }
9 };
当然也可以实现全局operator <
2 {
3 return lhs.key < rhs.key;
4 }
另外,当Compare 是std::greater时,需要实现 operator >
(四) 如何实现两个Key的map, 只有两个Key都匹配才命中目标
可以定义结构MyStruct如下:
2 {
3 int key1;
4 double key2
5
6 bool operator < ( const MyStruct rhs) const
7 {
8 /* 两个key必须都匹配才命中 */
9 return ( key1 < rhs.key1 || key2 < rhs.key2 );
10 }
11 };
(五) 如何实现两个Key的map, 两个Key中任意一个匹配就命中目标
可以定义结构MyStruct如下:
2 {
3 int key1;
4 double key2
5
6 bool operator < ( const MyStruct rhs) const
7 {
8 /* 两个key任意一个匹配就命中 */
9 return ( ( key1 < rhs.key1 || (key1 > rhs.key1 && key2 < rhs.key2 ) ) && ( key2 < rhs.key2 ) );
10 }
11 };
set集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点的左子树的高度与有字数的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。
平衡二叉检索树的检索使用中序遍历算法,检索效率高于vector、deque、和list的容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值从小到大的顺序排列。
构造set集合的主要目的是为了快速检索,使用set前,需要在程序头文件中包含声明“#include<set>”。
1.创建set集合对象
创建set对象时,需要指定元素的类型,这一点和其他容器一样。
2.元素的插入与中序遍历
采用inset()方法把元素插入到集合中,插入规则在默认的比较规则下,是按元素值从小到大插入,如果自己指定了比较规则函数,则按自定义比较规则函数插入。使用前向迭代器对集合中序遍历,结果正好是元素排序后的结果。
3.元素的方向遍历
使用反向迭代器reverse_iterator可以反向遍历集合,输出的结果正好是集合元素的反向排序结果。它需要用到rbegin()和rend()两个方法,它们分别给出了反向遍历的开始位置和结束位置。
4.元素的删除
与插入元素的处理一样,集合具有高效的删除处理功能,并自动重新调整内部的红黑树的平衡。删除的对象可以是某个迭代器位置上的元素、等于某键值的元素、一个区间上的元素和清空集合。
5.元素的检索
使用find()方法对集合进行检索,如果找到查找的的键值,则返回该键值的迭代器位置;否则,返回集合最后一个元素后面的一个位置,即end()。
下面这种方法也能判断一个数是否在集合中:
6.自定义比较函数
使用insert将元素插入到集合中去的时候,集合会根据设定的比较函数奖该元素放到该放的节点上去。在定义集合的时候,如果没有指定比较函数,那么采用默认的比较函数,即按键值从小到大的顺序插入元素。但在很多情况下,需要自己编写比较函数。
编写比较函数有两种方法。
(1)如果元素不是结构体,那么可以编写比较函数。下面的程序比较规则为按键值从大到小的顺序插入到集合中。
(2)如果元素是结构体,那么可以直接把比较函数写在结构体内。