map和set基本使用

二叉搜索树

在学习map和和set的使用之前,我们需要对二叉搜索树有一定的了解。
二叉搜索树也称二叉排序树或者二叉查找树,如果该树不是空树,就应该满足以下条件:非空左子树的所有键值都小于其根结点的键值,非空右子树的所有键值都大于其根结点的键值,且左右子树也都是二叉搜索树。

二叉搜索树的插入和查找逻辑都比较简单,这里不过多讨论,其结点的删除一般采用替换删除法,进行删除时分4种情况:
1.要删除的结点没有孩子
直接删除并将其父结点指向置空即可

2.要删除的结点只有左孩子
将其父结点的指向指向要删除的结点的左孩子后直接删除

3.要删除的结点只有右孩子
将其父结点的指向指向要删除的结点的右孩子后直接删除

4.要删除的结点有左孩子、右孩子
在要删除结点的左子树找到键值最大的结点L或在要删除结点的右子树找到键值最小的结点R,只需要将L或R的键值赋值给要删除的结点,然后删除L或R结点即可,因为L一定没有右孩子,R一定没有左孩子,所以L或R结点的删除一定属于1、2、3情况中的某一种。

由于删除除叶子结点时叶子结点既可以看成只有左孩子(左孩子为空)也可以看成只有右孩子(右孩子为空),所以可以将1、2或者1、3当作同一类情况来看。

二叉搜索树有两种模型:
1.K模型:即只有key作为关键码,结点只需要存储key即可,key就是我们需要的数据。

2.KV模型:每一个关键码key都对应一个只value,我们需要存储key和value,通过key去搜索结点时,value才是我们需要的数据。

使用二叉搜索树,其数据的插入、删除、查找成本都较低,是良好的数据结构,但当其变为单支时,查找效率会大大下降,从而导致插入和删除的效率也下降,由此改进就产生了平衡搜索二叉树,使进行结点插入删除时这棵树依然接近完全二叉树,经典的平衡搜索二叉树有AVL树和红黑树。

我们前面使用的vector、list等容器都是属于序列式容器,其底层为线性结构,里面存储的是元素本身,而关联式容器存储的是<key value>结构的键值对,在进行数据检索时效率比序列式容器高。我们下面介绍的map、multimap、set、multiset属于树形结构的关联式容器,其底层结构为红黑树。

在学习使用这些容器之前,我们先了解2个模板
1.pair
pair是一个类模板,包含在头文件<utility>中

template <class T1, class T2> struct pair;

在这里插入图片描述
这个类模板实例化后可以存储两个类型不同的数据,存放在公共成员变量first和second中,在类外可以直接访问,其构造函数如下:

pair();

template<class U, class V> pair (const pair<U,V>& pr);

pair (const first_type& a, const second_type& b);

//
//Type of member first, aliased as first_type.

//Type of member second, aliased as second_type.

2.make_pair
make_pair是一个函数模板,返回一个pair对象,包含在头文件<utility>中

template <class T1, class T2>
  pair<T1,T2> make_pair (T1 x, T2 y);

set

set在用户使用上看上去是K型搜索二叉树,只存放了key值,但在底层存放的是<key,key>构成的键值对,不过我们用户直接将其当成K型搜索二叉树即可,不需要构建键值对。需要注意的是,set的元素比较默认是按小于进行比较的,且不会插入重复元素,不能修改结点值。

template < class T,                        // set::key_type/value_type
           class Compare = less<T>,        // set::key_compare/value_compare
           class Alloc = allocator<T>      // set::allocator_type
           > class set;

在这里插入图片描述
1.构造

explicit set (const key_compare& comp = key_compare(),
              const allocator_type& alloc = allocator_type());


template <class InputIterator>
  set (InputIterator first, InputIterator last,
       const key_compare& comp = key_compare(),
       const allocator_type& alloc = allocator_type());


set (const set& x);

// InputIterator shall be an input iterator type that points to elements of a type from which value_type objects can be constructed.

2.赋值运算符重载

set& operator= (const set& x);

3.迭代器

//正向迭代器
      iterator begin();
const_iterator begin() const;

      iterator end();
const_iterator end() const;

//反向迭代器
      reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

      reverse_iterator rend();
const_reverse_iterator rend() const;

4.判断是否为空

bool empty() const;

5.获取结点个数

size_type size() const;

6.元素插入

pair<iterator,bool> insert (const value_type& val);
//如果元素是第一次插入,pair的first指向插入的结点,bool设为true
//如果相同key值已经存在,pair的first指向已经存在的结点,bool设为false
	
iterator insert (iterator position, const value_type& val);

template <class InputIterator>
  void insert (InputIterator first, InputIterator last);

7.元素删除


     void erase (iterator position);

size_type erase (const value_type& val);

     void erase (iterator first, iterator last);

8.清空搜索树

void clear();

9.交换两颗树

void swap (set& x);

10.查找某个结点

iterator find (const value_type& val) const;

11.获取某一key值的结点个数

size_type count (const value_type& val) const;
//由于set相同key值的结点只存一个,所以只返回0或1

12.返回第一个大于等于key值的结点

iterator lower_bound (const value_type& val) const;

13.返回第一个大于key值的结点

iterator upper_bound (const value_type& val) const;

multiset

multiset的元素允许重复,需要包含<set>头文件,multiset在底层存放的也是<key,key>构成的键值对,不过我们用户直接将其当成K型搜索二叉树即可,不需要构建键值对,其元素比较默认是按小于进行比较的,不能修改结点值。multiset容器的使用几乎与set一样,我们这里只看常用的有区别的接口。

1.插入

iterator insert (const value_type& val);
//返回结点的迭代器,不再是pair

iterator insert (iterator position, const value_type& val);

template <class InputIterator>
  void insert (InputIterator first, InputIterator last);

2.查找

iterator find (const value_type& val) const;
//如果存在重复元素,也只返回其中一个结点

3.返回key值的结点个数

size_type count (const value_type& val) const;
//不再只是返回0或1

map

map是一种KT型搜索二叉树,在底层存的是<key value>键值对元素比较默认是按小于进行比较的,可以修改value值,但不能修改key值,不允许元素重复(key值相等即为元素相等),如果元素插入时key值相等,但value值不同,不进行任何操作。

template < class Key,                                     // map::key_type
           class T,                                       // map::mapped_type
           class Compare = less<Key>,                     // map::key_compare
           class Alloc = allocator<pair<const Key,T> >    // map::allocator_type
           > class map;

在这里插入图片描述
1.构造

explicit map (const key_compare& comp = key_compare(),
              const allocator_type& alloc = allocator_type());

template <class InputIterator>
  map (InputIterator first, InputIterator last,
       const key_compare& comp = key_compare(),
       const allocator_type& alloc = allocator_type());

map (const map& x);

//c++11支持使用pair对象构造map对象

2.赋值运算符重载

 map& operator= (const map& x);
 //c++11支持使用pair对象进行赋值

3.迭代器

//正向迭代器
      iterator begin();
const_iterator begin() const;

      iterator end();
const_iterator end() const;

//反向迭代器
      reverse_iterator rbegin();
const_reverse_iterator rbegin() const;

      reverse_iterator rend();
const_reverse_iterator rend() const;

4.判断是否为空

bool empty() const;

5.获取结点个数

size_type size() const;

6.插入

pair<iterator,bool> insert (const value_type& val);
//如果元素是第一次插入,pair的first指向插入的结点,bool设为true
//如果相同key值已经存在,pair的first指向已经存在的结点,bool设为false

iterator insert (iterator position, const value_type& val);

template <class InputIterator>
  void insert (InputIterator first, InputIterator last);

//c++11支持使用pair对象进行插入

7.删除

     void erase (iterator position);

size_type erase (const key_type& k);

     void erase (iterator first, iterator last);

8.[]运算符重载

mapped_type& operator[] (const key_type& k);
//利用k值作为下标获取对应的value值的引用
//如果k为key值的结点不存在,会插入key=k,value=默认构造的键值对,然后返回value的引用
//其本质是这个:(*((this-insert(make_pair(k,mapped_type()))).first)).second

9.at下标访问

     mapped_type& at (const key_type& k);
const mapped_type& at (const key_type& k) const;
//找到匹配的k值,返回对应的引用,找不到就报错

10.查找某个结点

      iterator find (const key_type& k);
const_iterator find (const key_type& k) const;

11.获取某一key值的结点个数

size_type count (const value_type& val) const;
//由于set相同key值的结点只存一个,所以只返回0或1

12.返回第一个大于等于key值的结点

      iterator lower_bound (const key_type& k);
const_iterator lower_bound (const key_type& k) const

13.返回第一个大于key值的结点

      iterator upper_bound (const key_type& k);
const_iterator upper_bound (const key_type& k) const;

14.交换两颗树

void swap (map& x);

15.清空搜索树

void clear();

multimap

multimap的元素允许重复,需要包含<map>头文件,其元素比较默认是按小于进行比较的,不能修改结点值。multimap容器的使用几乎与map一样,我们这里只看常用的有区别的接口。
由于key值可以重复,所以multimat不支持[]下标访问和at下标访问
1.插入

iterator insert (const value_type& val);
//也是返回迭代器,不再是pair对象

iterator insert (iterator position, const value_type& val);

template <class InputIterator>
  void insert (InputIterator first, InputIterator last);

2.查找

      iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
//如果存在重复元素,也只返回其中一个结点

3.返回key值的结点个数

size_type count (const value_type& val) const;
//也不再只是返回0或1

这些容器的具体使用可以查看以下文档:
set
map
multiset
multimap

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值