5. Associative Containers(1)

Introduction to red-black tree

In addition AVL-tree, RB-treeis another widely used balanced binary search tree, which is also STLthe underlying implementation of associative containers in China.

insert image description here

Red-black tree properties

RB-treeIt is a binary search tree. Recall that the binary search tree has the following properties:

  • If the left subtree is not empty, the values ​​of all nodes in the left subtree are less than the value of the root node;
  • If the right subtree is not empty, the values ​​of all nodes in the right subtree are greater than or equal to the value of the root node;
  • Any subtree is also a binary search tree;

The search time complexity of binary search tree isO(logn)
insert image description here


RB-treeIn addition to conforming to the basic characteristics of the binary search tree, it also has the following characteristics:

  • Each node is either red or black;
  • The root node is black;
  • If a node is red, its children must be black;
  • Any path from any node to NULLa leaf node must contain the same number of black nodes;
    insert image description here

Red-black tree operations

RB-treeIt should include three operations of node search, insertion and deletion. RB-treeThere are too many situations to consider for insertion and deletion operations, so I won’t introduce them here (I can’t understand it either!). The following mainly introduces the insertion and search operations, and STLsome implementation details in .

find node

RB-treeIt is a binary search tree itself, which satisfies the properties of a binary search tree: the value of all nodes in the left subtree is less than the root node, and the value of all nodes in the right subtree is greater than or equal to the root node. The rules for finding nodes are as follows:

insert image description here

insert node

RB-treeThe situation of node insertion is more complicated, there are seven situations, as shown in the figure below, and the specific operations will not be introduced too much.

insert image description here

RB-treeProvide two insertion operations: insert_unique()and insert_equal(), the former function indicates that the inserted key value keymust be unique in the whole tree, and when inserting the same key value, the insertion operation does not work; the latter indicates that the key value of the inserted node keycan be in the Repeat throughout the tree.

Data structure of red-black tree

The following definition of RB-tree, which defines a dedicated space configurator, configures and releases the memory of a node through two functions, get_nodecopies the value and color of a node, and releases the content and memory of the node.create_nodeclone_nodedestroy_node

template <class Key, class Value, class KeyofValue, class Compare,
          class Alloc = alloc>
class rb_tree
{
    
    
protected:
	typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
public:
	typedef Key key_value;
	typedef Value value_type;
	...
};

The meanings of the above templatefive parameters are as follows:

  • Key: the data type of the key value key;
  • Value: organized by key and data, it can be seen in the map as a pair structure;
  • KeyofValue: How to separate the key from the Value, which is done through the select1st function in the map;
  • Compare: the comparison function of the key value;
  • Alloc: memory configurator

set

setHas the following characteristics:

  • All elements will be automatically sorted according to the key value of the element;
  • Contains only the key value, the key value keyis the real value value;
  • Two elements are not allowed to have the same key value;

setThe data structure is as follows:

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
{
    
    	
public:
	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 t;		// 成员变量
public:
	// set不允许迭代器执行写入操作, 因此iterator定义为RB-tree的const_iterator
	typedef typename rep_type::const_iterator iterator;
	typedef typename rep_type::const_iterator const_iterator;
};

setrb_treeThe bottom layer implements various functions through the called data structure, and the following functions can rb_treebe implemented simply by calling:

iterator begin() const {
    
     return t.begin(); }
iterator end()   const {
    
     return t.end(); }
bool	 empty() const {
    
     return t.empty(); }
size_type size() const {
    
    return t.size();  }
size_type max_size() const {
    
     return t.max_size(); }

insert operation

setThe element's keyrequest must be unique and, therefore, insert()the underlying call rb_tree's insert_unique()implementation. The following three insertion operations are provided in the set:

typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator, bool> insert(const value_type& x) // 向RB-tree中插入一个节点, 自动排序
{
    
    
    pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
    return pair<iterator, bool>(p.first, p.second);
}
typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator, bool> insert(iterator position, const value_type& x) 
{
    
    
    // 指定插入的位置, 自动排序后, 插入的节点位置未知
    typedef typename rep_type::iterator rep_iterator;
	return t.insert_unique((rep_iterator&)position, x);
}
template <class InputIterator>
void insert(InputIterator first, InputInterator last)
{
    
    
    t.insert_unqiue(first, last);
}

For testing demo, it should be noted that insertthe return values ​​of the three functions are different:

#include <iostream>
#include <set>

int main ()
{
    
    
  std::set<int> myset;
  std::set<int>::iterator it;
  std::pair<std::set<int>::iterator,bool> ret;

  // set some initial values:
  for (int i=1; i<=5; ++i) myset.insert(i*10);    // set: 10 20 30 40 50

  ret = myset.insert(20);               // no new element inserted

  if (ret.second==false) it=ret.first;  // "it" now points to element 20
  std::cout << "current iterator value: " << *it << std::endl;

  it = myset.insert (it,25);                 // max efficiency inserting
  std::cout << "current iterator value: " << *it << std::endl;
  it = myset.insert (it,24);                 // max efficiency inserting
  std::cout << "current iterator value: " << *it << std::endl;
  it = myset.insert (it,26);                 // no max efficiency inserting
  std::cout << "current iterator value: " << *it << std::endl;

  int myints[]= {
    
    5,10,15};              // 10 already in set, not inserted
  myset.insert (myints,myints+3);

  std::cout << "myset contains:";
  for (it=myset.begin(); it!=myset.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

delete operation

Similarly, the delete operation also provides three forms, and the bottom layer is implemented by calling rb_treethe erasefunction:

void erase(iterator position)
{
    
    	// 传入迭代器, 删除对应的节点
    typedef typename rep_type::iterator rep_iterator;
    t.erase((rep_iterator&) position);
}
size_type erase(const key_type& x)
{
    
    
    return t.erase(x);
}
void erase(iterator first, iterator last)
{
    
    
    typedef typename rep_type::iterator rep_iterator;
    t.erase((rep_iterator&)first, (rep_iterator&)last)
}
void clear() {
    
     t.clear(); }

find operation

In the face of associative containers, you should use findthe functions provided by it to find elements, which will be more efficient than using STLthe algorithm, because the bottom layer of the algorithm is only sequential search.find()STLfind()

iterator find(const key_type& x) const {
    
     return t.find(x); }
size_type count (const key_type& x) const {
    
     return t.count(x); }

map

mapHas the following characteristics:

  • All elements will be automatically sorted according to the key value key of the element;
  • Node elements are all pairstructures, with both real dataand key values key. pairThe first element in the node is regarded as a key value, and the second element is regarded as a real value;
  • Two elements are not allowed to have the same key value key;

pairThe data structure of sum is as follows map:

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) {
    
    }
};
template < class Key, class T,  // Key为键值, T为data型别
        	class Compare = less<key>,
        	class Alloc = alloc>
class map
{
    
    
public:
	typedef Key key_type;
	typedef T   data_type;
	typedef pair<const Key, T>  vaule_type;
private:
	typedef rb_tree<key_type, value_type,
                	select1st<value_type>, key_compare, Alloc> rep_type;
	// 成员变量
	rep_type t;
public:
	typedef typename rep_type::iterator iterator;
	typedef typename rep_type::const_iterator const_iterator;
};

mapiteratorThe definition in setis different because it allows the user to modify the element's through an iterator data. mapIt is not allowed to modify the key value of the element, but the content of the element can be modified data, because mapthe element datadoes not affect mapthe arrangement rules of the element.
mapThe implementation of the search, insertion and deletion operations in is the setsame as rb_treethe implementation of the call implementation, so I won't introduce it here.

unique operator[]

public:
	typedef Key key_type;
	typedef T   data_type;
	typedef pair<const Key, T>  vaule_type;
	T& operator[] (const key_type& k)
	{
    
    
        return (*((insert(value_type(k, T()))).first).second);
	}

If the key value kis in the container map, return the keycorresponding key value data, if the key value k does not exist mapin the container, use the key value keyto insert a new element, and return the corresponding element data. If the key value k does not exist, the size of datathe container mapwill increase regardless of whether the corresponding key is specified 1.

  • value_type(k, T())

First, make an element based on the key value and the real value. Since the real value is unknown, a temporary object of the same type as the real value is generated instead

  • insert(value_type(k, T()))

Insert elements mapinto

  • ((insert(value_type(k, T()))).first

The insert operation returns an iterator pairwhose first element is the newly inserted elementmap

  • *((insert(value_type(k, T()))).first).second

For an iterator dereference, get a key value and a real value pair, take its second element, which is the real value

multiset

multisetThe characteristics and usage of setare exactly the same as that of , the only difference is that it allows duplicate key values, so its insertion is done by the underlying RB-treemechanism insert_equal()instead insert_unique().

multimap

multimapThe characteristics and usage of mapare exactly the same as that of , the only difference is that it allows duplicate key values, so its insertion is done by the underlying RB-treemechanism insert_equal()instead insert_unique().

Summarize

In this paper, we first introduce RB-treethe characteristics of balanced binary trees, and RB-treeconduct a simple analysis of the operation of and, then introduce the specific content of the implementation based on setand , and finally explain the difference between and and and in use.mapRB-treemultisetmultimapsetmap

Guess you like

Origin blog.csdn.net/hello_dear_you/article/details/128677820