map与set

Map介绍

Map是一组成对的键值对对象,允许使用键(key)来查找(value)。它提供了一个映射表,可以通过某个对象来查找另一个对象。它也被称作关联数组,因为它将某些对象与另外一些对象关联在一起;或者称作字典,通过键对象来查找值对象,就像在字典中使用单词来定义一样。

Map特点

  1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类value_type绑定在一起,
    为其取别名称为pair:
    typedef pair value_type;
  3. 在内部,map中的元素总是按照键值key进行比较排序的。
  4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  6. map通常是以红黑树为底层实现的,查找效率比较高O(log2N)。

Map的构造

1.Map的构造
1)构造一个空的map
2)用[first,last]区间中的元素构造map
3)map的拷贝构造

#include <string> 
#include <map> 
void TestMap()
{
    // key和value的类型都给成字符串 
    map<string, string> m1;

    // C++11 的类表初始化
    map<string, string> m2{ { "apple", "苹果" },
                            { "banan", "香蕉" },
                            { "orange", "橘子" },
                            { "peach", "桃子" },
                            { "waterme", "水蜜桃" } };

    cout << m2["apple"] << endl; 
    cout << m2["waterme"] << endl; 
    map<string, string> m3(m2);
}

Map的迭代器

在这里插入图片描述
注:当用户对map进行了增加和删除后,所有的迭代器依然有效,被删除的结点的迭代器是例外。
利用迭代器进行遍历:

void TestMap()
{
    map<string, string> m{ { "apple", "苹果" },
                            { "banan", "香蕉" },
                            { "orange", "橘子" },
                            { "peach", "桃子" },
                            { "waterme", "水蜜桃" } };

    for (auto it = m.begin(); it != m.end(); ++it) 
        cout << (*it).first << "--->" << it->second << endl; 
    cout << endl;
}

Map的常用操作

在这里插入图片描述
以上是map的所有常见操作,现在对insert和operator[]进一步说明。
insert的原型

//指定元素插入  返回值为pair 第二个参数bool值可以判断元素是否插入成功
pair<iterator,bool> insert (const value_type& val);


//指定位置插入,但位置可能是不合适的,会导致插入失败,插入成功返回新位置的迭代器
iterator insert (iterator position, const value_type& val);


//指定迭代器区间插入
template <class InputIterator>
  void insert (InputIterator first, InputIterator last);

这里我们要说的是第一种插入方式,直接给一个val作为参数,插入则返回一个pair,pair的第一个参数是迭代器,倘若本次插入成功,则返回新插入位置的迭代器,倘若插入失败,那么就说明该值已经在map中,直接返回val所在位置的迭代器,而第二个参数bool则说明是否插入成功,1标识插入成功,0标识插入失败。
现在我们就可以来讲一讲operator[ ]了,map中的operator[ ]让我们能够像数组那样,通过key值(可以理解成数组里的下标值),找到value值(可以理解成a[ i ])。
那operator[ ]的底层原理是:

1.先构建一个pair<key.T()>的插入对象。
2.用上面的插入函数尝试插入到map中。
3.倘若插入成功,则返回新插入位置的迭代器和 1 ,operator[ ]返回此迭代器中second成员(也就是value)的引用。
4.倘若插入失败,则说明map中已经有以key为键值的pair对象了,则返回该pair的迭代器和 0,operator[ ]返回该迭代器中的second成员(也就是value)的引用。
operator[]的实现源码:

T& operator[](const key_type& k)
 {

   return (*((insert(value_type(k, T()))).first)).second;

  }

1.insert( value_type( k, T() ) ): 插入以k和T()构成的pair的键值对,我们将这部分结果记作x。
2.*( (x).first ) : x的first是指向pair迭代器,我们将他解引用后的结果记作y
3.return (y).second; y的second就是value了。

#include <string>
#include <map>
void TestMap()
{
	// 构造一个空的map,此时m中一个元素都没有
	map<string, string> m;
/*
operator[]的原理是:
用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中
如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
operator[]函数最后将insert返回值键值对中的value返回
*/

// 将<"apple", "">插入map中,插入成功,返回value的引用,将“苹果”赋值给该引用结果,
// 即修改与"apple"对应的value""为"苹果"

	m["apple"] = "苹果";
	
// 将<"apple", "">插入map中,插入失败,将<"apple", "苹果">中的"苹果"返回

	cout << m["apple"] << endl;
	cout << m.size() << endl;
	
// “banan不在map中,该函数抛异常”
	m.at("banan");
}

注意:有一个与operator[]类似的操作at()(该函数不常用)函数,都是通过key找到与key 对应的value然后返回其引用,不同的是:当key不存在时,operator[]用默认value与key构造键值对 然后插入,返回该默认value,at()函数直接抛异常。

Set介绍

set也属于关联式容器,底层由红黑树实现,与map相似,但是set存储的数据只有key值,但底层仍然按照键值对pair<value,value>来存储,即键值与实值相等,所以set不支持修改,否则会导致搜索树的乱序,同时也不支持operator[]。

Set特点

  1. 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但
    在底层实际存放的是由<value, value>构成的键值对。
  2. set中插入元素时,只需要插入value即可,不需要构造键值对。
  3. set中的元素不可以重复(因此可以使用set进行去重)。
  4. 使用set的迭代器遍历set中的元素,可以得到有序序列
  5. set中的元素默认按照小于来比较
  6. set中查找某个元素,时间复杂度为:
  7. set中的元素不允许修改(为什么?)
  8. set中的底层使用二叉搜索树(红黑树)来实现。

Set的迭代器

Set的常用操作

在这里插入图片描述

map与multimap的区别在于前者不允许key值重复,后者允许。
set与multiset的区别在于前者不允许value值重复,后者允许。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值