最近在看《stl源码剖析》,看到了红黑树的一章,就想根据书上的代码自己动手实现一下。现在只实现到树的构建与插入功能;节点删除和修改功能还未实现。写完之后发现自己用的Ubuntu16.04的g++5.4.0上与书上的g++版本相差太大,比如其中的空间分配器的使用已经完全不同。我只得照着g++5.4.0的源码再修改已经写好的代码,所以代码中有着很多c++11标准的语法与书上的老标准的语法穿插的情况。现在把写好的代码放上来,也算是一个记录。删除和修改功能以后有空在写吧。。。
代码如下:
/*
* RB_tree.h
*
* Created on: Jul 11, 2018
* Author: clh01s@163.com
*/
#include <iostream>
#include <memory>
//#include <bits/stl_tree.h>
#include <bits/stl_algobase.h>
#include <bits/allocator.h>
#include <bits/stl_function.h>
#include <bits/cpp_type_traits.h>
//#include <bits/exception_defines.h>
#include <ext/aligned_buffer.h>
#include <ext/alloc_traits.h>
#include <utility>
//#include <map>
using namespace std;
typedef bool __rb_tree_color_type;
const __rb_tree_color_type __rb_tree_red = false;//红色为false
const __rb_tree_color_type __rb_tree_black = true;//黑色为true
struct __rb_tree_node_base
{
typedef __rb_tree_color_type color_type;
typedef __rb_tree_node_base* base_ptr;
color_type color; //节点颜色
base_ptr parent; //RB树的很多操作都需要知道父节点
base_ptr left; //指向左节点
base_ptr right; //指向右节点
static base_ptr minimum(base_ptr x)
{
while(x->left != 0)
x = x->left;
return x;
}
static base_ptr maximum(base_ptr x)
{
while(x->right != 0)
x = x->right;
return x;
}
};
template <class Value>
struct __rb_tree_node : public __rb_tree_node_base
{
typedef __rb_tree_node<Value>* link_type;
Value value_field;//节点值
__gnu_cxx::__aligned_membuf<Value> _M_storage;
Value* _M_valptr()
{
return _M_storage._M_ptr();
}
};
//右旋函数
static void local_Rb_tree_rotate_left(__rb_tree_node_base* const x,
__rb_tree_node_base*& root)
{
__rb_tree_node_base* y = x->right;//令y为旋转点的右节点
x->right = y->left;
if(y->left != 0)
{
y->left->parent = x;//x设置为y
}
y->parent = x->parent;
//令y完全顶替x的地位(必须将x的关系完全接收过来)
if(x == root)//x为根节点
{
root = y;
}
else if(x == x->parent->left)//为父节点的左节点
{
x->parent->left = y;
}
else//x为父节点的右节点
{
x->parent->right = y;
}
//y交换完毕之后再交换x
y->left = x;
//将y设置为父节点
x->parent = y;
}
//左旋函数
static void local_Rb_tree_rotate_right(__rb_tree_node_base* const x,
__rb_tree_node_base*& root)
{
__rb_tree_node_base* y = x->left;//令y为旋转点的左节点
x->left = y->right;
if(y->right != 0)
{
y->right->parent = x;//x设置为y
}
y->parent = x->parent;
//令y完全顶替x的地位(必须将x的关系完全接收过来)
if(x == root)//x为根节点
{
root = y;
}
else if(x == x->parent->right)//x为父节点的右节点
{
x->parent->right = y;
}
else//x为父节点的左节点
{
x->parent->left = y;
}
//y交换完毕之后再交换x
y->right = x;
//将y设置为父节点
x->parent = y;
}
//RB-tree正规迭代器
template<typename _Tp>
struct __rb_tree_iterator
{
typedef _Tp value_type;
typedef _Tp& reference;
typedef _Tp* pointer;
typedef __rb_tree_iterator<_Tp> self;
typedef __rb_tree_node_base::base_ptr base_ptr;
typedef __rb_tree_node<_Tp>* link_type;
__rb_tree_iterator():node(){}
__rb_tree_iterator(base_ptr x):node(x)
{}
//这里是实现找到只比当前节点值大比其他节点小的值
//这是一个数学意义上的++(找到只比自身大的那一个值),而不是在树的意义上的下一个节点
__rb_tree_node_base* increment()
{
if(node->right != 0) //如果有右子节点
{
node = node->right; //就向右走
while(node->left != 0) //然后就一直往左子树走到底
node = node->left; //就是答案
}
else //没有右子节点
{
base_ptr y = node->parent; //找出父节点
while(node == y->right) //如果现行节点本身是个右子节点
{
node = y; //就一直上溯直到不为右子节点为止
y = y->parent;
}
if(node->right != y) //若此时的右子节点不等于此时的父节点
node = y; //此时的父节点即为解答
//否则此时的node为解答
}
return node;
}
//这里是实现找到只比当前节点值小比的值
//这是一个数学意义上的--(找到只比自身小的那一个值),而不是在树的意义上的下一个节点
__rb_tree_node_base* decrement()
{
if(node->color == __rb_tree_red && //如果是红节点
node->parent->parent == node) //且父节点等于自己
{
node = node->right; //右节点即为解答
//以上情况发生与node为header时
//注意,header之右子节点即mostright,指向整棵树的max节点
}
else if(node->left != 0) //如果有左子节点
{
base_ptr y = node->left; //令y指向左子节点
while(y->right != 0) //当y有右子节点时
y = y->right;//一直往右子节点走到底
node = y;//最后即为答案
}
else //即非根节点,亦无左子节点
{
base_ptr y = node->parent; //找出父节点
while(node == y->left) //当现行节点是左子节点
{
node = y; //一直交替往上走,直到现行节点
y = y->parent; //不为左子节点
}
node = y; //此时父节点就是答案mx
}
return node;
}
reference operator*() const {return *static_cast<link_type>(node)->_M_valptr();}
#ifdef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const {retrun &(operator*() );}
#endif /* __SGI_STL_NO_ARROW_OPERATOR*/
self& operator++(){increment(); return *this;}
self operator++(int) _GLIBCXX_NOEXCEPT
{
self tmp = *this;
increment();
return tmp;
}
self& operator--(){decrement(); return *this;}
self operator--(int) _GLIBCXX_NOEXCEPT
{
self tmp = *this;
decrement();
return tmp;
}
bool operator==(const self& x)
{
return node == x.node;
}
bool operator!=(const self& x)
{
return node != x.node;
}
base_ptr node;
};
//template<typename Val>
//inline bool
//operator==(const __rb_tree_iterator<Val>& x,__rb_tree_iterator<Val>& y) _GLIBCXX_NOEXCEPT
//{
// return x.node == y.node;
//}
//
//template<typename Val>
//inline bool
//operator!=(const __rb_tree_iterator<Val>& x,__rb_tree_iterator<Val>& y) _GLIBCXX_NOEXCEPT
//{
// return x.node != y.node;
//}
void _Rb_Tree_insert_and_rebalance(const bool insert_left,
__rb_tree_node_base* x,
__rb_tree_node_base* p,
__rb_tree_node_base& header)
{
__rb_tree_node_base*& root = header.parent;//保存根节点
//初始化新节点
x->parent = p;
x->left = 0;
x->right = 0;
x->color = __rb_tree_red;//新节点必定为红
//插入
//构建父节点的新子节点,并且维护根节点、最左节点、最右节点
//如果插入点在左边
if(insert_left)
{
//将父节点的左边置为新的节点
p->left = x;//而且当父节点p与头节点header相同时就表示leftmost() = x
//这里表示插入节点的父节点与根节点相同也就是说新插入的节点为该树的第一个节点
if(p == &header)
{
header.parent = x;//所以将header的父节点置为x
header.right = x;//右节点也为x
}
//如果头节点的左节点与父节点p相同表示header.left为之前的最左节点
else if(p == header.left)
{
//也就是说之前左节点为父节点p自己,那么插入新的左节点之后更新左节点
header.left = x;
}
}
else
{
//插入点为右边
p->right = x;
//如果父节点与头结点的右节点相同表示之前没有右节点
if(p == header.right)
{
//将头结点的右节点更新为新的右节点
header.right = x;
}
}
//平衡树
while(x != root && x->parent->color == __rb_tree_red)
{
//获得插入节点的爷爷节点
__rb_tree_node_base* const xpp = x->parent->parent;
//判断插入节点的父节点是否为爷爷节点的左节点
if(x->parent == xpp->left)
{
//获得伯父节点
__rb_tree_node_base* const y = xpp->right;
//如果伯父节点存在且为红
if(y && y->color == __rb_tree_red)
{
//插入新节点后父节点将改为黑
//根据规则4(任意至叶子节点的路径,黑色节点数必须相同)
//将父节点改为黑
x->parent->color = __rb_tree_black;
//伯父节点也改为黑
y->color = __rb_tree_black;
//将爷爷节点改为红
xpp->color = __rb_tree_red;
x = xpp;//准备继续往上层检查
}
else //无伯父节点或伯父节点为黑
{
//如果新节点为父节点的右节点
if(x == x->parent->right)
{
//以新节点的父节点做左旋操作
x = x->parent;
local_Rb_tree_rotate_left(x,root);
}
x->parent->color = __rb_tree_black;//改变颜色
x->parent->parent->color = __rb_tree_red;
//以祖父节点为右旋点做右旋操作
local_Rb_tree_rotate_right(xpp, root);
}
}
//该else的流程与if的流程相同但旋转方向相反
else//父节点为爷爷节点的右节点
{
//获得伯父节点
__rb_tree_node_base* const y = xpp->left;
//如果伯父节点存在且为红
if(y && y->color == __rb_tree_red)
{
//插入新节点后父节点将改为黑
//根据规则4(任意至叶子节点的路径,黑色节点数必须相同)
//将父节点改为黑
x->parent->color = __rb_tree_black;
//伯父节点也改为黑
y->color = __rb_tree_black;
//更改祖父节点为红
xpp->color = __rb_tree_red;
x = xpp;//准备继续往上检查
}
else //无伯父节点或伯父节点为黑
{
if(x == x->parent->left)//如果新节点为父节点的左节点
{
x = x->parent;
//以父节点为旋转点做右旋操作
local_Rb_tree_rotate_right(x, root);
}
x->parent->color = __rb_tree_black;//改变颜色
xpp->color = __rb_tree_red;
//再以爷爷节点为右旋点进行左旋操作
local_Rb_tree_rotate_left(xpp, root);
}
}
}
root->color = __rb_tree_black;//根节点永远为黑
}
//stl源码分析中的版本较老,在新版本中(我使用的5.4.0)已经改为使用allocator作为分配器
template <typename Key, typename Value, typename _KeyOfValue, typename Compare,
typename Alloc = allocator<Value> >
class RB_Tree
{
protected:
typedef void* void_pointer;
typedef __rb_tree_node_base* base_ptr;
typedef __rb_tree_node<Value> rb_tree_node;
typedef __rb_tree_color_type color_type;
typedef rb_tree_node* link_type;
private:
struct _Reuse_or_alloc_node
{
_Reuse_or_alloc_node(RB_Tree& t)
:_M_root(t._M_root()), _M_nodes(t._M_rightmost()), _M_t(t)
{
if(_M_root)
{
_M_root->parent = 0;
if(_M_nodes->left)
{
_M_nodes = _M_nodes->left;
}
}
else
{
_M_nodes = 0;
}
}
~_Reuse_or_alloc_node()
{_M_t._M_erase(static_cast<link_type>(_M_root));}
private:
base_ptr
_M_extract()
{
if(!_M_nodes)
{
return _M_nodes;
}
base_ptr node = _M_nodes;
_M_nodes = _M_nodes->parent;
if(_M_nodes)
{
if(_M_nodes->right == node)
{
_M_nodes->right = 0;
if(_M_nodes->left)
{
_M_nodes = _M_nodes->left;
while(_M_nodes->right)
{
_M_nodes = _M_nodes->left;
}
if(_M_nodes->left)
{
_M_nodes = _M_nodes->left;
}
}
}
else
{
_M_nodes = _M_nodes->left;
}
}
else
{
_M_root = 0;
}
return node;
}
base_ptr _M_root;
base_ptr _M_nodes;
RB_Tree& _M_t;
};
struct _Alloc_node
{
_Alloc_node(RB_Tree& t)
:_M_t(t){}
template<typename Arg>
link_type operator()(Arg&& arg) const
{
return _M_t.create_node(_GLIBCXX_FORWARD(Arg, arg));
}
private:
RB_Tree& _M_t;
};
private:
typedef typename __gnu_cxx::__alloc_traits<Alloc>::template
rebind<__rb_tree_node<Value> >::other Node_allocator;
typedef __gnu_cxx::__alloc_traits<Node_allocator> Alloc_traits;
public:
typedef Key key_type;
typedef Value value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef Alloc allocator_type;
Node_allocator&
_M_get_Node_allocator() _GLIBCXX_NOEXCEPT
{ return *static_cast<Node_allocator*>(&this->_M_impl); }
const Node_allocator&
_M_get_Node_allocator() const _GLIBCXX_NOEXCEPT
{ return *static_cast<const Node_allocator*>(&this->_M_impl); }
allocator_type
get_allocator() const _GLIBCXX_NOEXCEPT
{ return allocator_type(_M_get_Node_allocator()); }
protected:
link_type get_node()
{return Alloc_traits::allocate(_M_get_Node_allocator(), 1);}
void put_node(link_type p)
{Alloc_traits::deallocate(_M_get_Node_allocator(), p, 1);}
//构造节点
template<typename... Args>
void _M_construct_node(link_type node, Args&&... args)
{
try
{
::new(node) __rb_tree_node<Value>;
Alloc_traits::construct(_M_get_Node_allocator(),
node->_M_valptr(), std::forward<Args>(args)...);
}
catch(...)
{
node->~__rb_tree_node<Value>();
put_node(node);
__throw_exception_again;
}
}
template<typename... Args>
link_type
create_node(Args&&... args)
{
link_type tmp = get_node();
_M_construct_node(tmp, std::forward<Args>(args)...);
return tmp;
}
//销毁节点
void _M_destory_node(link_type __p) noexcept
{
Alloc_traits::destroy(_M_get_Node_allocator(), __p->_M_valptr());
__p->~__rb_tree_node<Value>();
}
template<typename _NodeGen>
link_type
_M_clone_node(link_type __x, _NodeGen& __node_gen)
{
link_type __tmp = __node_gen(*__x->_M_valptr());
__tmp->color = __x->color;
__tmp->left = 0;
__tmp->right = 0;
}
//销毁节点(这里使用5.4.0中的_M_drop_node代替destory_node)
void _M_drop_node(link_type __p) _GLIBCXX_NOEXCEPT
{
_M_destory_node(__p);//析构内容
put_node(__p);//释放内存
}
protected:
template<typename _Key_compare,
bool /* _Is_pod_comparator */ = __is_pod(_Key_compare)>
struct Rb_tree_impl : public Node_allocator
{
_Key_compare _M_key_compare;
__rb_tree_node_base _M_header;
size_type _M_node_count; // Keeps track of size of tree.
Rb_tree_impl()
: Node_allocator(), _M_key_compare(), _M_header(),
_M_node_count(0)
{ _M_initialize(); }
Rb_tree_impl(const _Key_compare& __comp, const Node_allocator& __a)
: Node_allocator(__a), _M_key_compare(__comp), _M_header(),
_M_node_count(0)
{ _M_initialize(); }
#if __cplusplus >= 201103L
Rb_tree_impl(const _Key_compare& __comp, Node_allocator&& __a)
: Node_allocator(std::move(__a)), _M_key_compare(__comp),
_M_header(), _M_node_count(0)
{ _M_initialize(); }
#endif
void
_M_reset()
{
this->_M_header.parent = 0;
this->_M_header.left = &this->_M_header;
this->_M_header.right = &this->_M_header;
this->_M_node_count = 0;
}
private:
void
_M_initialize()
{
this->_M_header.color = __rb_tree_red;
this->_M_header.parent = 0;
this->_M_header.left = &this->_M_header;
this->_M_header.right = &this->_M_header;
}
};
Rb_tree_impl<Compare> _M_impl;
protected:
//以下三个函数方便取得header的成员
base_ptr& _M_root()
{return this->_M_impl._M_header.parent;}
base_ptr& _M_leftmost()
{return this->_M_impl._M_header.left;}
base_ptr& _M_rightmost()
{return this->_M_impl._M_header.right;}
link_type _M_begin()
{return static_cast<link_type>(this->_M_impl._M_header.parent);}
link_type _M_end()
{return static_cast<link_type>(&this->_M_impl._M_header);}
static const_reference
_S_value(link_type __x)
{return *__x->_M_valptr();}
static const_reference
_S_value(base_ptr x)
{return *static_cast<link_type>(x)->_M_valptr();}
static const Key&
_S_key(link_type __x)
{return _KeyOfValue()(_S_value(__x));}
static const Key&
_S_key(base_ptr x)
{return _KeyOfValue()(_S_value(x));}
static link_type
_S_left(base_ptr __x)
{return static_cast<link_type>(__x->left);}
static link_type
_S_right(base_ptr __x)
{return static_cast<link_type>(__x->right);}
static base_ptr
_S_minimum(base_ptr __x)
{return __rb_tree_node_base::minimum(__x);}
static base_ptr
_S_maxmum(base_ptr __x)
{return __rb_tree_node_base::maximum(__x);}
public:
typedef __rb_tree_iterator<value_type> iterator;
private:
pair<base_ptr, base_ptr>
_M_get_insert_unique_pos(const key_type& k)
{
typedef pair<base_ptr, base_ptr> Res;
link_type x = _M_begin();
link_type y = _M_end();
bool comp = true;
//往下寻找合适的插入点
while(0 != x)
{
y = x;
//遇大则往左,遇小于或等于往右
comp = _M_impl._M_key_compare(k, _S_key(x));
x = comp ? _S_left(x) : _S_right(x);
}
iterator j = iterator(y);//令迭代器j指向插入节点父节点y
if(comp)//如果comp为真则表示大插入左侧
{
//如果插入的节点的父节点为最左节点
if(begin() == j)
{
//返回插入需要的pair
return Res(x,y);
}
else//插入节点的父节点不为最左节点则调整j
{
--j;
}
}
//如果新的节点不与既有节点键值重复返回插入需要的pair
if(_M_impl._M_key_compare(_S_key(j.node),k))
{
return Res(x, y);
}
//将插入需要的pair的second改为改为0表示不该插入然后返回
return Res(j.node, 0);
}
pair<base_ptr, base_ptr>
_M_get_insert_equal_pos(const key_type& k)
{
typedef pair<base_ptr, base_ptr> Res;
link_type x = _M_begin();
link_type y = _M_end();
while(0 != x)//寻找适当的插入点
{
y = x;
//遇大则往左,遇小于或等于往右
x = _M_impl._M_key_compare(k, _S_key(x)) ?
_S_left(x) : _S_right(x);
}
return Res(x,y);
}
//插入节点参数1为值插入点,参数2为插入点父节点,参数3为新值,参数4为新值的内存空间
template<typename _Arg, typename _NodeGen>
iterator _M_insert_(base_ptr x, base_ptr p, _Arg&& v, _NodeGen& node_gen)
{
//是否是插入左边
bool insert_left = (x != 0 || p == _M_end()
|| _M_impl._M_key_compare(_KeyOfValue()(v),_S_key(p)));
//产生一个新的节点
link_type z = node_gen(_GLIBCXX_FORWARD(_Arg, v));
//插入并平衡树
//参数1为插入左右的标示,参数2为新的插入节点,参数3为插入节点的父节点,参数4为根节点
_Rb_Tree_insert_and_rebalance(insert_left, z, p
, this->_M_impl._M_header);
//将节点计数++
++_M_impl._M_node_count;
return iterator(z);
}
template<typename _NodeGen>
link_type _M_copy(link_type x, link_type p , _NodeGen& an);
link_type _M_copy(link_type x, link_type p)
{
_Alloc_node an(*this);
return _M_copy(x, p, an);
}
void _M_erase(link_type x)
{
//删除下属整颗树
while(0 != x)
{
//删除且不重新平衡
_M_erase(_S_right(x));
link_type y = _S_left(x);
_M_drop_node(x);
x = y;
}
}
public:
RB_Tree(){}
RB_Tree(const Compare& comp, const allocator_type& a = allocator_type())
: _M_impl(comp, Node_allocator(a)){}
~RB_Tree() _GLIBCXX_NOEXCEPT
{
_M_erase(_M_begin());
}
Compare key_comp() const
{
return _M_impl._M_key_compare;
}
iterator begin() _GLIBCXX_NOEXCEPT
{
return iterator(this->_M_impl._M_header.left);
}
iterator end() _GLIBCXX_NOEXCEPT
{
return iterator(&this->_M_impl._M_header);
}
bool empty() const _GLIBCXX_NOEXCEPT
{
return _M_impl._M_node_count == 0;
}
size_type size() const _GLIBCXX_NOEXCEPT
{
return _M_impl._M_node_count;
}
size_type max_size() const _GLIBCXX_NOEXCEPT
{
return Alloc_traits::max_size(_M_get_Node_allocator());
}
template<typename Arg>
pair<iterator, bool>
_M_insert_unique(Arg&& v)
{
typedef pair<iterator, bool> _Res;
pair<base_ptr, base_ptr> __res
=_M_get_insert_unique_pos(_KeyOfValue()(v));
//如果second为真表示没有重复可以插入
if(__res.second)
{
_Alloc_node an(*this);
//插入节点并返回插入的数据true表示没有重复数据false表示有重复
//插入节点参数1为值插入点,参数2为插入点父节点,参数3为新值,参数4为新值的内存空间
return _Res(_M_insert_(__res.first, __res.second,
_GLIBCXX_FORWARD(Arg, v), an), true);
}
return _Res(iterator(static_cast<link_type>(__res.first)), false);
}
template<typename Arg>
iterator _M_insert_equal(Arg&& v)
{
//寻找插入的位置
pair<base_ptr, base_ptr> res
= _M_get_insert_equal_pos(_KeyOfValue()(v));
_Alloc_node an(*this);
//插入节点参数1为值插入点,参数2为插入点父节点,参数3为新值,参数4为新值的内存空间
return _M_insert_(res.first, res.second,
_GLIBCXX_FORWARD(Arg, v), an);
}
};
下面是调用代码:
/*
* test.cpp
*
* Created on: Jul 31, 2018
* Author: clh01s
*/
#include <iostream>
#include "RB_tree.h"
using namespace std;
int main()
{
RB_Tree<int, int, _Identity<int>, std::less<int>, std::allocator<int>> a;
cout<<"插入之前树的大小:"<<a.size()<<endl;
a._M_insert_unique(6);
a._M_insert_unique(5);
a._M_insert_unique(4);
a._M_insert_unique(13);
cout<<"插入之后树的大小:"<<a.size()<<endl;
__rb_tree_iterator<int> rbtite;
for(auto it = a.begin();it != a.end(); ++it)
{
// rbtite = __rb_tree_base_iterator(it);
cout<<*it<<endl;
}
return 0;
}
输出结果:
clh01s@clh01s:~/testcode/数据结构$ g++ test.cpp -std=c++11
clh01s@clh01s:~/testcode/数据结构$ ./a.out
插入之前树的大小:0
插入之后树的大小:4
value = 4
value = 5
value = 6
value = 13
转载请注明原地址:https://blog.csdn.net/clh01s/article/details/83269466