map/set
map/set????? 到底说的是什么呢 ???、
很多人在刷题的时候可能会见过这两个名词、??? ,,,,但是你大概不知道这是什么意思????
那么,,我就来向你解释一下这两个名词到底是什么意思了!!!!!!!!
其实,说到底,,,,这两个就是系统为我们实现的两种二叉树《《《《;;;;;
但是这两种有一个共同之处,,,,那就是这两种结构的底层实现都是 使用的红黑树 ,,,,,通俗点说的话就是,这两种结构就是两种不同形态的红黑树。。。。。
那么,,,,,现在我们先了解一下这个set使用方法》》》》》
set
set的第一条规则就是这是一个 K 结构的红黑树。。。。。
下面我们我们通过一段代码来初步了解一下set的功能。。。。。
#pragma once
#include <iostream>
using namespace std;
#include<set> //如果要是使用 set的结构 ,,,就要添加此头文件
void Testset()
{
set<int> testset;
int arr[] = {1,45,6,87,45,56,55,0,7,5};
for(size_t i = 0 ;i < sizeof(arr)/sizeof(arr[0]);++i)
{
testset.insert(arr[i]);
}
//其实set就是这个一个容器 ,,,,在这里使用迭代器输出这个set;;;;
set<int>::iterator it= testset.begin();
while(it!= testset.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
};
最后生成的结果是 :::
通过这个结果显示,,我们可以明确的看出 ,生成的set的结构 中没有将数组中 重复的数字 输出。。。。
因此 ,我们可以看出set结构插入的时候 ,,,不会插入相同的元素 (红黑树都有这个特性)
另外 ,输出的结果都是有序的,,,,,
因此,,,,我们可以得出set的几个功能:::
1、、、消除冗余的效果 ;;;;
2、、、对于一组不重复的数,达成排序的效果 。。。。
下面我们来看看库中,,,为我们实现的set的结构的一些操作函数。。。
在此图中我们可以看出 ,,,,set类的一系列组成;;;
其中 ,,,,
T 表示 的就是 set树中 的存储元素。。。。
Compare 表示 的就是 输出的元素顺序,,,(是升序还是降序,,,,,,在这里的缺省值是升序)
Alloc 表示 的就是 空间适配器。。。。。。。 (现在还不是很懂 )
下面是些 set的一些基本函数的用法;;;;;
这些就是 set 实现的函数 ;;;;
我在这里来 主要讲一下 insert函数 ::::
库函数 为 我们提供的insert函数 ,,,重载了三种方式 ;;;
下面我就向大家 来分别来 演示 一下 这三类重载函数的应用场景:::
场景1 、、、、函数原型 是
pair<iterator,bool> insert (const value_type& val);
此处的
value_type 表示类型就是 我们经常说的 K 类型 ,,,也就是set定义的T类型
此函数的返回值 类型为 pair<iterator,bool>
可能 你之前没有 听过pair这个 东西 ,点此来由我向你解释一下吧
pair
void Testset()
{
set<int> testset;
int arr[] = {1,45,6,87,45,56,55,0,7,5};
for(size_t i = 0 ;i < sizeof(arr)/sizeof(arr[0]);++i)
{
testset.insert(arr[i]);
}
pair<set<int>::iterator,bool> ret = testset.insert(100);
cout<< * ret.first<<","<<ret.second<<endl;
ret = testset.insert(100);
cout<< * ret.first<<","<<ret.second<<endl;
}
显示的结果:
通过此我们可以看出 :::
如果 要是插入的元素已存在,,那么返回的pair类型 中的迭代器first为原有元素的迭代器,bool量second为false
如果 要是插入的元素不存在,,那么返回的pair类型 中的迭代器first为插入元素的迭代器,bool量second为true
此种用法我们可以用来解决下列问题:::
1、判断插入的数据 是否重复;;;
2、用来删除一组数据中重复的元素;;;;
3、排序一组无重复的数;;;;
场景2、、、、、函数原型
iterator insert (iterator position, const value_type& val);
这就是我们 ,,,一般熟悉的一种场景 ,,,,在一个迭代器的之前插入这个数据,,,,返回插入元素的迭代器。。。。
场景3、、、函数
template <class InputIterator> void insert (InputIterator first, InputIterator last);
这是一个模板函数,,,,,,可以将一段数据插入到这个set红黑树中 ,,,,
使用实例:::
void Testset()
{
set<int> testset;
int arr[] = {1,45,6,87,45,56,55,0,7,5};
for(size_t i = 0 ;i < sizeof(arr)/sizeof(arr[0]);++i)
{
testset.insert(arr[i]);
}
int a[] = {100,200,300,400};
testset.insert(a,a+4);
set<int>::iterator it= testset.begin();
while(it!= testset.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
}
插入后输出的结果::
使用此类函数时,,,,需要注意的是:::
插入的迭代器必须可以 运用(++)(!=)这两个运算符;;;
set给我们
提供的删除函数 erase(),,也向我们提供了几种方法
提供的删除函数 erase(),,也向我们提供了几种方法
重载的这些方法 ,,,我们 也很容易理解 ,,,,
(1) 参数是一个迭代器
这就是 要删除 迭代器参数位置上的那个数据;;;
如果给的迭代器无效 ,,,,编译器就会报错 ,,,
(2) 参数是 一个数据,,,
也就是 要一个在set中值为val的节点 ;;;返回值为删除节点的个数
(3) 参数为一段迭代器区间
也就是 是 说 要删除 set的一段数据 ,,,,但是 所给的迭代器必须有效;;;
下面是这些方法使用实例:::
void Print(set<int> &s)
{
set<int>::iterator it= s.begin();
while(it!= s.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
}
void Testset()
{
set<int> testset;
int arr[] = {1,45,6,87,45,56,55,0,7,5};
for(size_t i = 0 ;i < sizeof(arr)/sizeof(arr[0]);++i)
{
testset.insert(arr[i]);
}
Print(testset);
set<int>::iterator it = testset.find(5);
testset.erase(it);//场景1的使用
Print(testset);
size_t n = testset.erase(45);//场景2的使用
Print(testset);
testset.erase(testset.begin(),testset.end());//场景3的使用
Print(testset);
}
生成的结果:
如果要是场景一的删除的迭代器无效,,,,系统会提示这样的一个断言错误:::
另外,,,,,要是想要显示输出的数据元素 ,,,按照降序排列的话 ,,
可以 这样建立一个set的对象 :::
set<int,greater<int>> s;
map
关于map这种结构,,我呢,,,就不要详细说了 ,,,,它的使用几乎与 set是一致的。。。。
但大概还有一些区别 ,,,
下图为map的声明的原型 ,,,
上面的大部分和set是一模一样的;;;
只是这里的map是 K—V结构的一种 红黑树吧!!!
另外,,,,map的插入函数,,也和 set有区别:::
如果使用的 是 像 set一样的插入的话 ,,,,
代码该是这样的:
map<int ,int> m; m.insert(1,2);
但是,,如果这样写的话,,,编译器会提示报错 ,,,,
为什么呢 ???
我们看看系统为我们提供的这种 插入函数就知道是怎么回事了 ???
大概一看,,和 set是一样的,,,但是 这里的value_type 指的是 一个pair 结构
key_type | The first template parameter (Key) | |
mapped_type | The second template parameter (T) | |
value_type | pair<const key_type,mapped_type> |
map<int ,int> m; m.insert(pair<int,int>(1,2));
为什么要这样写呢 ???
1】是为了 可观。。。。
2】是为与set对应。。。。
其他的一个十分重要的一点(与set相对比)是 :::
就是 map在这里 ,,,重载了 operator[] ,,,,这是一个很关键的地方 。。。。
下面是函数的原型:::
在这里的作用有很多,,,,我们来这重载的代码来演示一下吧!!!!
T& operator[](const K& key)
{
iterator it = find(key);//先在map里查找这个元素key
if(it == end())//没找到的话
{
it = insert(pair<k,T>(key,T())); //将这个数据插入到map中,,T为缺省值
}
return it->second;//返回值,,,,元素key的节点 V的引用
}
也就是说,我们可以快速的通过 [key] 来找到它所对应的T值,,,,
这就是map、set的大概的知识 ;;;;
当然了,,我们学习它 ,,,,就是为了用它,,
如果,,你对此感兴趣的话,,可以来看看》》》》》