Introduction to red-black tree
In addition AVL-tree
, RB-tree
is another widely used balanced binary search tree, which is also STL
the underlying implementation of associative containers in China.
Red-black tree properties
RB-tree
It 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)
RB-tree
In 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
NULL
a leaf node must contain the same number of black nodes;
Red-black tree operations
RB-tree
It should include three operations of node search, insertion and deletion. RB-tree
There 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 STL
some implementation details in .
find node
RB-tree
It 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 node
RB-tree
The 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.
RB-tree
Provide two insertion operations: insert_unique()
and insert_equal()
, the former function indicates that the inserted key value key
must 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 key
can 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_node
copies the value and color of a node, and releases the content and memory of the node.create_node
clone_node
destroy_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 template
five 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
set
Has 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
key
is the real valuevalue
; - Two elements are not allowed to have the same key value;
set
The 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;
};
set
rb_tree
The bottom layer implements various functions through the called data structure, and the following functions can rb_tree
be 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
set
The element's key
request 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 insert
the 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_tree
the erase
function:
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 find
the functions provided by it to find elements, which will be more efficient than using STL
the algorithm, because the bottom layer of the algorithm is only sequential search.find()
STL
find()
iterator find(const key_type& x) const {
return t.find(x); }
size_type count (const key_type& x) const {
return t.count(x); }
map
map
Has the following characteristics:
- All elements will be automatically sorted according to the key value key of the element;
- Node elements are all
pair
structures, with both realdata
and key valueskey
.pair
The 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
;
pair
The 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;
};
map
iterator
The definition in set
is different because it allows the user to modify the element's through an iterator data
. map
It is not allowed to modify the key value of the element, but the content of the element can be modified data
, because map
the element data
does not affect map
the arrangement rules of the element. map
The implementation of the search, insertion and deletion operations in is the set
same as rb_tree
the 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 k
is in the container map
, return the key
corresponding key value data
, if the key value k does not exist map
in the container, use the key value key
to insert a new element, and return the corresponding element data
. If the key value k does not exist, the size of data
the container map
will 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 map
into
((insert(value_type(k, T()))).first
The insert operation returns an iterator pair
whose 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
multiset
The characteristics and usage of set
are 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-tree
mechanism insert_equal()
instead insert_unique()
.
multimap
multimap
The characteristics and usage of map
are 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-tree
mechanism insert_equal()
instead insert_unique()
.
Summarize
In this paper, we first introduce RB-tree
the characteristics of balanced binary trees, and RB-tree
conduct a simple analysis of the operation of and, then introduce the specific content of the implementation based on set
and , and finally explain the difference between and and and in use.map
RB-tree
multiset
multimap
set
map