STL ③ —— set 和 map

1. 序列式容器与关联式容器的区别

  • 序列式容器:其底层为线性序列的数据结构,里面储存的是元素本身。
    • Eg:vector,list,string,deque,stack,forward_list(C++11)。
  • 关联式容器:其底层为树形序列的数据结构,里面储存的是<key,value>结构的键值对。
    • Eg:map,set,multimap,multist。

2. set 和 map 介绍

  • set和map是C++标准库中的关联容器,它们中的所有元素都会根据元素的键值(key)自动被排序,又由于红黑树(RB-tree)是一种平衡二叉搜索树,自动排序效果非常好,所以标准的STL中的set和map容器都是以红黑树(RB-tree)为底层机制,又由于map和set所开放的各种操作接口,RB-tree也提供了,所以它们几乎所有的操作行为,都只是转调RB-tree的操作行为。
  • set是存储已排序的无重复的元素,它有过滤重复功能,它元素的键值就是实值,实值就是键值(在底层实际存放的是由<value, value>构成的键值对),所以set的迭代器不能改变其元素值,否则会严重破坏其set有序的组织,所以其迭代器被定义为底层RB-tree的const_iterator,杜绝写入操作。
  • map中所有元素都会根据元素的键值自动被排序。map 的所有元素都是 pair,同时拥有实值(value)和键值(key)。pair 的第一元素被视为键值,第二元素被视为实值。map不允许两个元素拥有相同的键值。

3. 红黑树特性

  • 每个节点要么是黑色,要么是红色。
  • 根节点是黑色。
  • 每个叶子节点都是黑色。
  • 每个红色结点的两个子结点一定都是黑色。
  • 任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
  • 插入的节点默认为红色。

4. Set和Map以及MultiSet和MultiMap

  • set和map的联系与区别:
    • 底层都是由红黑树实现的(结构都一样);
    • 都是按照key排序,并且不允许key重复(通过将变量设置为const来实现);
    • set是只有一个key,map是一个pair对,包含key和value;
  • 是否有multi的区别:是否允许key重复,相同key的节点肯定在相邻的地方;

5. Set 和 Map 的使用方法

Set

int arr[5] = {5, 2, 3, 4, 1};
set<int> st1;
set<int> st2(arr, arr+5);
set<int> st3(st2);
// greater<int> 是一个模板参数,它表示使用逆序比较函数来对元素进行排序,即以降序排列。
// 因此,这个 set 将按照整数值的降序存储其元素。
set<int, greater<int>> st4;

// 默认情况下,使用正向迭代器遍历set是进行中序遍历,得到一组升序的数据。
set<int> st1(arr, arr + 5);
set<int, greater<int>> st2(arr, arr + 5);
set<int>::iterator it1 = st1.begin();
while(it1 != st1.end()) cout << *it1++ << endl;  // 正向迭代器遍历st1,得到一组升序数据
set<int, greater<int>> iterator it2 = st2.begin();
while(it2 != st2.end()) cout << *it2++ << endl;  // 正向迭代器遍历st2,得到一组降序数据

st1.insert(5);
st1.erase(0);
st1.erase(st1.begin(), st1.end());
st1.clear();
set<int>::iterator pos1 = st1.find(20); // 查找特定数据
int count = st1.count(20); // 统计set中20出现的次数
int size = st1.size();  // 返回当前set容器中的元素个数  O(1)
set<int>::iterator it1 = st.lower_bound(30);  // 返回大于或等于x的最小节点
set<int>::iterator it3 = st.upper_bound(40);  // 返回大于x的最小节点
pair<set<int>::iterator, set<int>::iterator> pa = st.equal_range(50);  // 返回包含x的区间:pa.first = 50, pa.second = 60

map

map<int, int> mp1;
mp1[1] = 1;
mp1[2] = 3;
map<int, int> mp2(mp1.begin(), mp1.end());
map<int, int> mp3(mp2);
mp4 = mp1;  // 赋值

map<int, int>::iterator it = mp.begin();
while (it != mp.end()){
	// cout << (*it).first << "=>" << (*it).second << endl;
	cout << it->first << "=>" << it->second << endl;
	++it;
}

mp.insert(make_pair(5, 5)); // 插入数据
mp.erase(9);
mp.erase(mp.begin()+1);
mp.clear();

map<int, int>::iterator it = mp.find(3);

6. unordered_set 和 unordered_map

  • multiset:元素可以重复,且元素有序
  • unordered_set:元素无序且只能出现一次
  • unordered_multiset:元素无序可以出现多次

6.1 set 和 unordered_set

  • unordered_set 是不按特定顺序存储唯一元素的容器,允许基于它们的 key 快速检索单个元素
  • 在 unordered_set 中,元素的值与唯一标识它的 key 同时存在,key 是不可变的,因此,unordered_set 中的元素在容器中不能被修改,但是它可以进行插入和删除
  • 在内部,unordered_set 中的元素不按任何特定顺序排序,而是根据它们的哈希值插入到相应的桶中,允许直接根据它们的值快速访问单个元素(平均时间复杂度恒定,即常数O(1) )
  • Unordered_set 容器在通过键访问单个元素时比 set 容器更快,尽管它们在通过元素子集进行范围迭代时通常效率较低
  • 容器中的迭代器至少是前向迭代器(只支持单向迭代器 ++)

6.2 map 和 unordered_map

  • 底层实现不同,Map的底层是红黑树,Unordered_Map的底层是哈希表(散列表);
  • Map是红黑树实现的,所以有排序功能,通过迭代器就可以输出排好序的序列,Unordered_Map没有排序的功能;
  • Map查找和插入的时间复杂度是O(logn),Unordered_Map是接近O(1),跟哈希函数相关,所以不需要排序的时候用Unordered_Map效率会更高;
  • Unordered_Map的数据,如果数据数量超过线性存储表的数量查找效率就会降低,线性存储表的容量就要增加一倍(类似于vector),是根据经验得到的,没有严谨的数学证明。
  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值