set和map(一)

简介: set和map

关联式容器


在之前的学习中,所学习的容器类型都是序列式容器,其底层是线性数据结构存储的是元素本身


本章所学习的是另一种容器关联式容器,关联就意味着元素与元素之间存在着某种关联;存储的是数据是 <key,value>结构的键值对,接下来学习什么是键值对


键值对


键值对用来表示具有一一对应关系的一种结构,此结构中一般只包括两个成员变量 key和 value;key代表键值, value代表与 key对应的信息;通过结构体pair进行定义


1739ba07f6c15faff01b416918b8a108_37130141f22542fc85217149c67901af.png

0ff1737e9025ac34a4255c7464d23825_5c608d02d7e044f4bdb9c3ef95688df7.png


template<class T1,class T2>
struct pair
{
  typedef T1 first_type;
  typedef T2 second_type;
  T1 first;
  T2 second;
  pair()
  :first(T1())
  ,second(T2())
  {}
  pair(const T1&a,const T2&b)
  :first(a)
  ,second(b)
  {}
};


一般在进行对pair赋值并插入时,使用其另一种形式make_pair


3cd2eb12bc310280b40ae2928032bf6d_5bc50befec8a42b5843a9b96b9cfaac4.png


树状结构关联式容器


根据应用场景的不同,STL实现了两种不同结构的管理式容器:树形结构和哈希结构;树形结构的关联式容器主要有四种: set, multiset, map, multimap。这四种容器都是以平衡搜索树作为底层结构来实现的。接下来对这些容器一一介绍


set


介绍


set是按照一定次序存储元素的

在set中,只存放实值value,但在底层实际存放的是键值对<value,value>;插入元素时只需要插入实值value,不需要构造键值对

元素不可以重复,且不允许修改

元素默认按照小于进行比较

底层由二叉搜索树实现


使用


模板参数列表


e12514a5d6ef215e28d7dfcf452a834c_45c839b8306242f7933f34ffab09a1ef.png


T:set中存放的元素的类型是T,既是key也是value

Compare:set中元素默认按照小于进行比较

int main()
{
  set<int>myset;
  myset.insert(5);
  myset.insert(5);
  myset.insert(3);
  myset.insert(4);
  myset.insert(1);
  myset.insert(0);
  myset.insert(0);
  for (auto e : myset)
  {
  cout << e << " ";
  }
  cout << endl;
  auto pos = find(myset.begin(), myset.end(), 3);
  myset.erase(pos);
  for (auto e : myset)
  {
  cout << e << " ";
  }
  return 0;
}

6babb88343cb1211eb67965cdf6a5880_d7bacf40e4b44682aa057d0bc3a335e1.png


通过运行结果可以发现, set会自动对元素进行排序+去重


multiset


介绍


4ee4f70e5efc9830e0ff0953cc754130_872871c18bbc4bfcb0742ae2d37ba03d.png


multiset是按照特定顺序存储元素的容器,元素可以重复

其余的与set一致


使用


int main()
{
  multiset<int>myset;
  myset.insert(5);
  myset.insert(5);
  myset.insert(3);
  myset.insert(4);
  myset.insert(1);
  myset.insert(0);
  myset.insert(0);
  for (auto e : myset)
  {
  cout << e << " ";
  }
  cout << endl;
  auto pos = find(myset.begin(), myset.end(), 3);
  myset.erase(pos);
  for (auto e : myset)
  {
  cout << e << " ";
  }
  return 0;
}


b1f6a2b90d544f1efb411e0440149f90_04b4bfdd1e96405a996b3c65acc1add8.png


通过结果可以发现,相比于set,multiset只是进行简单的排序,并不会进行去重操作


map


介绍


关联式容器,按照 key的比较次序来存储由键值 key和值 value组成的键值对,通过成员类型 value_type,称为 pair

typedef pair<const key,T>value_type;


键值 key用于排序和标识元素;值 value存储与键值关联的内容;两者的类型可能不同

在内部,map中的元素总是按照键值key进行比较排序的,默认是按照小于进行排序的

map中存放的元素是键值对pair<key,value>

支持下标访问,即可以通过键值key访问与之对应的value


使用


模板参数说明


2a7f029ebe756eb804d989337fef7311_4ce51453890940cba12fba81385717e9.png


Key:key的类型
T:value的类型
Compare:比较器,通过key进行比较
int main()
{
  map<string, string>dict;
  dict.insert(make_pair("east", "东"));
  dict.insert(make_pair("west", "西"));
  dict.insert(make_pair("south", "南"));
  dict.insert(make_pair("north", "北"));
  for (const auto& e : dict)
  {
  cout << e.first << " " << e.second << endl;
  }
  return 0;
}

41321a49b7ee757a67cfff1d7129abc5_915e5ec23f4a497f8d43b3453f79af04.png


multimap


介绍



aaeb46e4824249be8f9278cb4a8a087d_b0e54731cca54150a82adb35da8a28e7.png


multimap是按照特定顺序存储键值对pair<key,value>的序列式容器,元素可以重复

其余的与map一致


使用


统计球的次数


int main()
{
  string arr[] = { "篮球","羽毛球","乒乓球","羽毛球","乒乓球","羽毛球", "羽毛球","乒乓球" };
  multimap<string, int>coutmap;
  for (auto& e : arr)
  {
  auto it = coutmap.find(e);
  if (it == coutmap.end())
  {
    coutmap.insert(make_pair(e, 1));
  }
  else
  {
    it->second++;
  }
  }
  for (const auto& e : coutmap)
  {
  cout << e.first << " " << e.second << endl;
  }
  return 0;
}

a46aea3cb3daec6121128bc8d27a0359_7cf77b8cddf44b74a643ba4173c3cf22.png


这里还有另一种方式进行统计,需要使用operator[],使用之前,先介绍其原理,做到知其然知其所以然


98dab7622d8d9f0bcc8aee6f3fc7fdaa_a1f38cc99ef647bdb74f3f11f8a57b5c.png


下标访问返回值:


(*((this->insert(make_pair(k,mapped_type()))).first)).second

逐步进行分析:


make_pair(k,mapped_type()),根据键值k和实值类型相同的临时对象mapped_type()创建一个元素

insert(make_pair(k,mapped_type())),将该元素插入到map中去,这里还需要了解到插入操作会返回一个pair,第一个元素是迭代器,指向插入的新元素或者键值重复的旧元素;第二个元素标识着插入的成功与否

pair<iterator,bool> insert (const value_type& val);


(this->insert(make_pair(k,mapped_type()))).first,取得插入返回 pair中的第一个元素,即迭代器,指向插入的元素

(*((this->insert(make_pair(k,mapped_type()))).first)).second,对迭代器进行解引用,获得一个 map元素,由键值 key和实值 value组成的 pair取得其第二个元素,也就是实值

对上面的代码进行修改


int main()
{
  string arr[] = { "篮球","羽毛球","乒乓球","羽毛球","乒乓球","羽毛球" ,"羽毛球","乒乓球" };
  map<string, int>coutmap;
  for (auto& e : arr)
  {
  coutmap[e]++;
  }
  for (const auto& e : coutmap)
  {
  cout << e.first << " " << e.second << endl;
  }
  return 0;
}

0f85790b41abce62aaa4a0d94ca80691_2665ee8d2964406abc66918a3d56f0ce.png


底层容器


前面的set/multiset/map/multimap有个共同特点:底层都是通过二叉搜索树来实现的,二叉搜索树本身也存在着缺陷,如果插入值不够随机,或者经过某些插入或删除操作导致二叉搜索树失去平衡,造成搜寻效率低的情况,因此set/map的底层结构是对二叉搜索树进行了平衡处理的平衡树来实现的

c40fa24019e28c3cad00800ac1e2e978_265768ab010244c3ade76a95bf18b164.png


目录
打赏
0
0
0
0
4
分享
相关文章
Set和Map有什么区别?
Set和Map有什么区别?
19 1
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
115 2
在JavaScript中,Set和Map的性能有什么区别?
在JavaScript中,Set和Map的性能有什么区别?
27 0
for...of循环在遍历Set和Map时的注意事项有哪些?
for...of循环在遍历Set和Map时的注意事项有哪些?
56 0
|
1月前
|
unordered_set、unordered_multiset、unordered_map、unordered_multimap的介绍及使用
unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素。在unordered_set中,元素的值同时也是唯一地标识它的key。在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低。它的迭代器至少是前向迭代器。前向迭代器的特性。
75 0
用一棵红黑树同时封装出map和set
再完成上面的代码后,我们的底层代码已经完成了,这时候已经是一个底层STL的红黑树了,已经已符合库里面的要求了,这时候我们是需要给他穿上对应的“衣服”,比如穿上set的“衣服”,那么这个穿上set的“衣服”,那么他就符合库里面set的要求了,同样map一样,这时候我们就需要实现set与map了。因此,上层容器map需要向底层红黑树提供一个仿函数,用于获取T当中的键值Key,这样一来,当底层红黑树当中需要比较两个结点的键值时,就可以通过这个仿函数来获取T当中的键值了。我们就可以使用仿函数了。
30 0
set、map、multiset、multimap的介绍及使用以及区别,注意事项
set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列。set当中存储元素的value都是唯一的,不可以重复,因此可以使用set进行去重。set默认是升序的,但是其内部默认不是按照大于比较,而是按照小于比较。set中的元素不能被修改,因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。
75 0
哈希表模拟封装unordered_map和unordered_set
哈希表模拟封装unordered_map和unordered_set
|
7月前
|
你对Collection中Set、List、Map理解?
你对Collection中Set、List、Map理解?
137 18
你对Collection中Set、List、Map理解?
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问