C++(STL源码):28---关联式容器set、map源码剖析

一、set

set的特性

  • set所有元素都会根据元素的键值自动被排序
  • set中的键值就是实值,实值就是键值
  • 默认情况下set不允许两个元素重复

set的迭代器

  • 不能根据set的迭代器改变set元素的值。因为其键值就是实值,实值就是键值,如果改变set元素值,会严重破坏set组织
  • 在后面的源码中会看到,set的迭代器set<T>::iterator被定义为底层RB-tree的const_iterator。因此set的迭代器是一种constant iterators

set拥有与list的相同的某些性质

  • 当客户端对它进行元素新增(insert)操作或删除(erase)操作时,操作之前的所有迭代器在操作完成之后依然有效(当然,被删除的那个元素的迭代器无效)

相关算法

  • STL提供了一组set/multiset相关算法,包括交集(set_intersection)、联集(set_union)、差集(set_difference)、对称差集(set_symmetric_difference)
  • 详情会在后面的“算法”文章中介绍

set的底层结构

  • 由于RB-tree是一种平衡二叉搜索树,自动排序的效果很不错,所以标准的STL set是以RB-tree为底层机制
  • 又由于set所开放的各种操作接口,RB-tree也都提供了,所以几乎所有的set操作行为,都只是转调用RB-tree的操作行为而已
  • RB-tree参阅:https://blog.csdn.net/qq_41453285/article/details/103645839

set源码

  • 下面是set的源代码摘录
//代码摘录于stl_set.h
template <class _Key, class _Compare, class _Alloc>
class set {
  // requirements:

  __STL_CLASS_REQUIRES(_Key, _Assignable);
  __STL_CLASS_BINARY_FUNCTION_CHECK(_Compare, bool, _Key, _Key);

public:
  // typedefs:

  typedef _Key     key_type;
  typedef _Key     value_type;
  typedef _Compare key_compare;
  typedef _Compare value_compare;
private:
  typedef _Rb_tree<key_type, value_type, 
                  _Identity<value_type>, key_compare, _Alloc> _Rep_type;
  _Rep_type _M_t;  // 采用红黑树来表现set
public:
  typedef typename _Rep_type::const_pointer pointer;
  typedef typename _Rep_type::const_pointer const_pointer;
  typedef typename _Rep_type::const_reference reference;
  typedef typename _Rep_type::const_reference const_reference;
  typedef typename _Rep_type::const_iterator iterator;
  //注意上一行,iterator定义为RB-tree的const_iterator,表示
  //set的迭代器无法执行写入操作
  typedef typename _Rep_type::const_iterator const_iterator;
  typedef typename _Rep_type::const_reverse_iterator reverse_iterator;
  typedef typename _Rep_type::const_reverse_iterator const_reverse_iterator;
  typedef typename _Rep_type::size_type size_type;
  typedef typename _Rep_type::difference_type difference_type;
  typedef typename _Rep_type::allocator_type allocator_type;

  // allocation/deallocation
  //注意,set一定使用RB-=tree的insert_unique()而非insert_equal()
  //multiset才使用RB-tree的insert_equal()
  set() : _M_t(_Compare(), allocator_type()) {}
  explicit set(const _Compare& __comp,
               const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) {}

#ifdef __STL_MEMBER_TEMPLATES
  template <class _InputIterator>
  set(_InputIterator __first, _InputIterator __last)
    : _M_t(_Compare(), allocator_type())
    { _M_t.insert_unique(__first, __last); }

  template <class _InputIterator>
  set(_InputIterator __first, _InputIterator __last, const _Compare& __comp,
      const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) { _M_t.insert_unique(__first, __last); }
#else
  set(const value_type* __first, const value_type* __last) 
    : _M_t(_Compare(), allocator_type()) 
    { _M_t.insert_unique(__first, __last); }

  set(const value_type* __first, 
      const value_type* __last, const _Compare& __comp,
      const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) { _M_t.insert_unique(__first, __last); }

  set(const_iterator __first, const_iterator __last)
    : _M_t(_Compare(), allocator_type()) 
    { _M_t.insert_unique(__first, __last); }

  set(const_iterator __first, const_iterator __last, const _Compare& __comp,
      const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) { _M_t.insert_unique(__first, __last); }
#endif /* __STL_MEMBER_TEMPLATES */

  set(const set<_Key,_Compare,_Alloc>& __x) : _M_t(__x._M_t) {}
  set<_Key,_Compare,_Alloc>& operator=(const set<_Key, _Compare, _Alloc>& __x)
  { 
    _M_t = __x._M_t; 
    return *this;
  }

  //以下所有的set操作,RB-tree都已提供,所以set只要传递调用即可
  // accessors:

  key_compare key_comp() const { return _M_t.key_comp(); }
  value_compare value_comp() const { return _M_t.key_comp(); }
  allocator_type get_allocator() const { return _M_t.get_allocator(); }

  iterator begin() const { return _M_t.begin(); }
  iterator end() const { return _M_t.end(); }
  reverse_iterator rbegin() const { return _M_t.rbegin(); } 
  reverse_iterator rend() const { return _M_t.rend(); }
  bool empty() const { return _M_t.empty(); }
  size_type size() const { return _M_t.size(); }
  size_type max_size() const { return _M_t.max_size(); }
  void swap(set<_Key,_Compare,_Alloc>& __x) { _M_t.swap(__x._M_t); }

  // insert/erase
  pair<iterator,bool> insert(const value_type& __x) { 
    pair<typename _Rep_type::iterator, bool> __p = _M_t.insert_unique(__x); 
    return pair<iterator, bool>(__p.first, __p.second);
  }
  iterator insert(iterator __position, const value_type& __x) {
    typedef typename _Rep_type::iterator _Rep_iterator;
    return _M_t.insert_unique((_Rep_iterator&)__position, __x);
  }
#ifdef __STL_MEMBER_TEMPLATES
  template <class _InputIterator>
  void insert(_InputIterator __first, _InputIterator __last) {
    _M_t.insert_unique(__first, __last);
  }
#else
  void insert(const_iterator __first, const_iterator __last) {
    _M_t.insert_unique(__first, __last);
  }
  void insert(const value_type* __first, const value_type* __last) {
    _M_t.insert_unique(__first, __last);
  }
#endif /* __STL_MEMBER_TEMPLATES */
  void erase(iterator __position) { 
    typedef typename _Rep_type::iterator _Rep_iterator;
    _M_t.erase((_Rep_iterator&)__position); 
  }
  size_type erase(const key_type& __x) { 
    return _M_t.erase(__x); 
  }
  void erase(iterator __first, iterator __last) { 
    typedef typename _Rep_type::iterator _Rep_iterator;
    _M_t.erase((_Rep_iterator&)__first, (_Rep_iterator&)__last); 
  }
  void clear() { _M_t.clear(); }

  // set operations:

  iterator find(const key_type& __x) const { return _M_t.find(__x); }
  size_type count(const key_type& __x) const {
    return _M_t.find(__x) == _M_t.end() ? 0 : 1;
  }
  iterator lower_bound(const key_type& __x) const {
    return _M_t.lower_bound(__x);
  }
  iterator upper_bound(const key_type& __x) const {
    return _M_t.upper_bound(__x); 
  }
  pair<iterator,iterator> equal_range(const key_type& __x) const {
    return _M_t.equal_range(__x);
  }

#ifdef __STL_TEMPLATE_FRIENDS
  template <class _K1, class _C1, class _A1>
  friend bool operator== (const set<_K1,_C1,_A1>&, const set<_K1,_C1,_A1>&);
  template <class _K1, class _C1, class _A1>
  friend bool operator< (const set<_K1,_C1,_A1>&, const set<_K1,_C1,_A1>&);
#else /* __STL_TEMPLATE_FRIENDS */
  friend bool __STD_QUALIFIER
  operator== __STL_NULL_TMPL_ARGS (const set&, const set&);
  friend bool __STD_QUALIFIER
  operator<  __STL_NULL_TMPL_ARGS (const set&, const set&);
#endif /* __STL_TEMPLATE_FRIENDS */
};

set的使用案例

#include <iostream>
#include <set>
using namespace std;

int main()
{
	int i;
	int ia[5] = { 0,1,2,3,4 };
	set<int> iset(ia,ia+5);
	std::cout << "size=" << iset.size() << std::endl;
	std::cout << "3 count" << iset.count(3) << std::endl << std::endl;

	iset.insert(3);
	std::cout << "size=" << iset.size() << std::endl;
	std::cout << "3 count" << iset.count(3) << std::endl << std::endl;

	iset.insert(5);
	std::cout << "size=" << iset.size() << std::endl;
	std::cout << "3 count" << iset.count(3) << std::endl << std::endl;

	iset.erase(1);
	std::cout << "size=" << iset.size() << std::endl;
	std::cout << "3 count" << iset.count(3) << std::endl;
	std::cout << "1 count" << iset.count(1) << std::endl << std::endl;

	set<int>::iterator ite1 = iset.begin();
	set<int>::iterator ite2 = iset.end();
	for (; ite1 != ite2; ite1++)
		std::cout << *ite1<<" ";
	std::cout << std::endl << std::endl;

	//使用STL算法来搜寻元素(循环搜索的),但是没有set的内置find函数高效
	ite1 = find(iset.begin(), iset.end(), 3);
	if (ite1 != iset.end())
		std::cout << "3 found" << std::endl;
	else
		std::cout << "3 not found" << std::endl << std::endl;

	//使用set的内置find函数,比STL算法高效
	ite1 = iset.find(1);
	if (ite1 != iset.end())
		std::cout << "1 found" << std::endl;
	else
		std::cout << "1 not found" << std::endl << std::endl;

	//*ite1 = 9;  错误,不能通过set的迭代器来改变元素的值
	return 0;
}

二、map

map的特性

  • 所有元素都会根据元素的键值自动被排序

map中的pair结构

  • map的所有元素类型都是pair,同时拥有实值(value)和键值(key)
  • pair的第一个元素视为键值,第二个元素视为实值
  • map不允许两个元素拥有相同的键值
  • 下面是stl_pair.h中pair的定义:
//代码摘录与stl_pair.h
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) {}

#ifdef __STL_MEMBER_TEMPLATES
  template <class _U1, class _U2>
  pair(const pair<_U1, _U2>& __p) : first(__p.first), second(__p.second) {}
#endif
};

map的迭代器

  • 不可以根据map的迭代器改变节点的键值,但是可以通过map的迭代器改变节点的实值
  • 因此,map iterators既不是一种constant iterators,也不是一种mutable iterators

map拥有与list的相同的某些性质

  • 当客户端对它进行元素新增(insert)操作或删除(erase)操作时,操作之前的所有迭代器在操作完成之后依然有效(当然,被删除的那个元素的迭代器无效)

map的底层结构

  • 由于RB-tree是一种平衡二叉搜索树,自动排序的效果很不错,所以标准的STL map是以RB-tree为底层机制
  • 又由于map所开放的各种操作接口,RB-tree也都提供了,所以几乎所有的map操作行为,都只是转调用RB-tree的操作行为而已
  • RB-tree参阅:https://blog.csdn.net/qq_41453285/article/details/103645839
  • 下面是map的结构:

map源码

  • 下面是map的源代码摘录
//代码摘录与stl_map.h
template <class _Key, class _Tp, class _Compare, class _Alloc>
class map {
public:

// requirements:

  __STL_CLASS_REQUIRES(_Tp, _Assignable);
  __STL_CLASS_BINARY_FUNCTION_CHECK(_Compare, bool, _Key, _Key);

// typedefs:

  typedef _Key                  key_type;  //键值类型
  typedef _Tp                   data_type; //数据(实值)类型
  typedef _Tp                   mapped_type;
  typedef pair<const _Key, _Tp> value_type; //元素类型(键值/实值)
  typedef _Compare              key_compare; //键值比较函数
    
  //以下定义一个functor,作用就是调用“元素比较函数”
  class value_compare
    : public binary_function<value_type, value_type, bool> {
  friend class map<_Key,_Tp,_Compare,_Alloc>;
  protected :
    _Compare comp;
    value_compare(_Compare __c) : comp(__c) {}
  public:
    bool operator()(const value_type& __x, const value_type& __y) const {
      return comp(__x.first, __y.first);
    }
  };

private:
  //以下定义表述类型。以map元素类型(一个pair)的第一类型,作为RB-tree节点的键值类型
  typedef _Rb_tree<key_type, value_type, 
                   _Select1st<value_type>, key_compare, _Alloc> _Rep_type;
  _Rep_type _M_t;  // 以红黑树实现map
public:
  typedef typename _Rep_type::pointer pointer;
  typedef typename _Rep_type::const_pointer const_pointer;
  typedef typename _Rep_type::reference reference;
  typedef typename _Rep_type::const_reference const_reference;
  typedef typename _Rep_type::iterator iterator;
  //注意上面一行,map不像set,map使用的是RB-tree的iterator
  typedef typename _Rep_type::const_iterator const_iterator;
  typedef typename _Rep_type::reverse_iterator reverse_iterator;
  typedef typename _Rep_type::const_reverse_iterator const_reverse_iterator;
  typedef typename _Rep_type::size_type size_type;
  typedef typename _Rep_type::difference_type difference_type;
  typedef typename _Rep_type::allocator_type allocator_type;

  //注意,map一定使用底层RB-tree的insert_unique()而非insert_equal()
  //multimap才使用insert_equal()
  // allocation/deallocation

  map() : _M_t(_Compare(), allocator_type()) {}
  explicit map(const _Compare& __comp,
               const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) {}

#ifdef __STL_MEMBER_TEMPLATES
  template <class _InputIterator>
  map(_InputIterator __first, _InputIterator __last)
    : _M_t(_Compare(), allocator_type())
    { _M_t.insert_unique(__first, __last); }

  template <class _InputIterator>
  map(_InputIterator __first, _InputIterator __last, const _Compare& __comp,
      const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) { _M_t.insert_unique(__first, __last); }
#else
  map(const value_type* __first, const value_type* __last)
    : _M_t(_Compare(), allocator_type())
    { _M_t.insert_unique(__first, __last); }

  map(const value_type* __first,
      const value_type* __last, const _Compare& __comp,
      const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) { _M_t.insert_unique(__first, __last); }

  map(const_iterator __first, const_iterator __last)
    : _M_t(_Compare(), allocator_type()) 
    { _M_t.insert_unique(__first, __last); }

  map(const_iterator __first, const_iterator __last, const _Compare& __comp,
      const allocator_type& __a = allocator_type())
    : _M_t(__comp, __a) { _M_t.insert_unique(__first, __last); }

#endif /* __STL_MEMBER_TEMPLATES */

  map(const map<_Key,_Tp,_Compare,_Alloc>& __x) : _M_t(__x._M_t) {}
  map<_Key,_Tp,_Compare,_Alloc>&
  operator=(const map<_Key, _Tp, _Compare, _Alloc>& __x)
  {
    _M_t = __x._M_t;
    return *this; 
  }

  //以下所有mao操作,RB-tree都已提供,mao只要调用即可
  // accessors:

  key_compare key_comp() const { return _M_t.key_comp(); }
  value_compare value_comp() const { return value_compare(_M_t.key_comp()); }
  allocator_type get_allocator() const { return _M_t.get_allocator(); }

  iterator begin() { return _M_t.begin(); }
  const_iterator begin() const { return _M_t.begin(); }
  iterator end() { return _M_t.end(); }
  const_iterator end() const { return _M_t.end(); }
  reverse_iterator rbegin() { return _M_t.rbegin(); }
  const_reverse_iterator rbegin() const { return _M_t.rbegin(); }
  reverse_iterator rend() { return _M_t.rend(); }
  const_reverse_iterator rend() const { return _M_t.rend(); }
  bool empty() const { return _M_t.empty(); }
  size_type size() const { return _M_t.size(); }
  size_type max_size() const { return _M_t.max_size(); }
  _Tp& operator[](const key_type& __k) {
    iterator __i = lower_bound(__k);
    // __i->first is greater than or equivalent to __k.
    if (__i == end() || key_comp()(__k, (*__i).first))
      __i = insert(__i, value_type(__k, _Tp()));
    return (*__i).second;
  }
  void swap(map<_Key,_Tp,_Compare,_Alloc>& __x) { _M_t.swap(__x._M_t); }

  // insert/erase

  pair<iterator,bool> insert(const value_type& __x) 
    { return _M_t.insert_unique(__x); }
  iterator insert(iterator position, const value_type& __x)
    { return _M_t.insert_unique(position, __x); }
#ifdef __STL_MEMBER_TEMPLATES
  template <class _InputIterator>
  void insert(_InputIterator __first, _InputIterator __last) {
    _M_t.insert_unique(__first, __last);
  }
#else
  void insert(const value_type* __first, const value_type* __last) {
    _M_t.insert_unique(__first, __last);
  }
  void insert(const_iterator __first, const_iterator __last) {
    _M_t.insert_unique(__first, __last);
  }
#endif /* __STL_MEMBER_TEMPLATES */

  void erase(iterator __position) { _M_t.erase(__position); }
  size_type erase(const key_type& __x) { return _M_t.erase(__x); }
  void erase(iterator __first, iterator __last)
    { _M_t.erase(__first, __last); }
  void clear() { _M_t.clear(); }

  // map operations:

  iterator find(const key_type& __x) { return _M_t.find(__x); }
  const_iterator find(const key_type& __x) const { return _M_t.find(__x); }
  size_type count(const key_type& __x) const {
    return _M_t.find(__x) == _M_t.end() ? 0 : 1; 
  }
  iterator lower_bound(const key_type& __x) {return _M_t.lower_bound(__x); }
  const_iterator lower_bound(const key_type& __x) const {
    return _M_t.lower_bound(__x); 
  }
  iterator upper_bound(const key_type& __x) {return _M_t.upper_bound(__x); }
  const_iterator upper_bound(const key_type& __x) const {
    return _M_t.upper_bound(__x); 
  }
  
  pair<iterator,iterator> equal_range(const key_type& __x) {
    return _M_t.equal_range(__x);
  }
  pair<const_iterator,const_iterator> equal_range(const key_type& __x) const {
    return _M_t.equal_range(__x);
  }

#ifdef __STL_TEMPLATE_FRIENDS 
  template <class _K1, class _T1, class _C1, class _A1>
  friend bool operator== (const map<_K1, _T1, _C1, _A1>&,
                          const map<_K1, _T1, _C1, _A1>&);
  template <class _K1, class _T1, class _C1, class _A1>
  friend bool operator< (const map<_K1, _T1, _C1, _A1>&,
                         const map<_K1, _T1, _C1, _A1>&);
#else /* __STL_TEMPLATE_FRIENDS */
  friend bool __STD_QUALIFIER
  operator== __STL_NULL_TMPL_ARGS (const map&, const map&);
  friend bool __STD_QUALIFIER
  operator< __STL_NULL_TMPL_ARGS (const map&, const map&);
#endif /* __STL_TEMPLATE_FRIENDS */
};
  • insert函数:
    • 返回pair类型。pair参数1位返回的元素,第2个参数为bool,表示是否插入成功。插入成功的话pair参数1才保存返回的节点元素
    • 底层交给RB-tree的insert_unique去执行
pair<iterator,bool> insert(const value_type& __x) 
    { return _M_t.insert_unique(__x); }
  • 下标运算符([]):
    • 左值运用:内容可被修改
    • 右值运用:内容不可被修改
map<std::string, int> simap;
simap[std::string("dongshao")] = 1;         //左值运用
int number = simap[std::string("dongshao")];//右值运用
  • 下标运算符的定义如下

map的使用案例

#include <iostream>
#include <string>
#include <map>
#include <utility>
using namespace std;

int main()
{
	map<std::string, int> simap;
	simap[std::string("jjhou")] = 1;
	simap[std::string("jerry")] = 2;
	simap[std::string("jason")] = 3;
	simap[std::string("jimmy")] = 4;

	std::pair<std::string, int> value(std::string("david"), 5);
	simap.insert(value);

	map<std::string, int>::iterator simap_iter = simap.begin();
	for (; simap_iter != simap.end(); simap_iter++)
		std::cout << simap_iter->first << ": " << simap_iter->second << std::endl;
	std::cout << std::endl;

	int number = simap[std::string("jjhou")];
	std::cout << number << std::endl << std::endl;


	map<std::string, int>::iterator iter;
	iter = simap.find(std::string("mchen"));
	if (iter != simap.end())
		std::cout << "mchen found" << std::endl;
	else
		std::cout << "mchen not found" << std::endl;
	iter = simap.find(std::string("jerry"));
	if (iter != simap.end())
		std::cout << "jerry found" << std::endl;
	else
		std::cout << "jerry not found" << std::endl;
	std::cout << std::endl;

	iter->second = 9;
	int number2 = simap[std::string("jerry")];
	std::cout << number2 << std::endl;
	return 0;
}

发布了1463 篇原创文章 · 获赞 996 · 访问量 35万+

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/104249771
今日推荐