数据结构关联式容器底层红黑树的模拟实现
Posted zhao111222333444
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构关联式容器底层红黑树的模拟实现相关的知识,希望对你有一定的参考价值。
红黑树的实现
红黑树是一种二叉搜索树,接近平衡。
主要有几个特点:
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
- 每个叶子结点都是黑色的
红黑树节点
#include<iostream>
#include<utility>
using namespace std;
enum COLOR
RED,
BLACK
;
//红黑树节点
//包含3指向,1颜色,1val
//val可以是pair,和k
template<class V>
struct RBNode
RBNode<V>* _parent;
RBNode<V>* _left;
RBNode<V>* _right;
V _val;
COLOR _color;
RBNode(const V& val = V())
:_parent(nullptr)
, _left(nullptr)
, _right(nullptr)
, _val(val)
, _color(RED)
;
迭代器
由于树形结构的底层实现,红黑树的迭代器是封装了node节点的迭代器
//红黑树迭代器
template<class V>
struct RBTreeIterator
typedef RBNode<V> Node;
typedef RBTreeIterator<V> Self;
Node* _node;
RBTreeIterator(Node* node)
:_node(node)
//迭代器一般要实现解引用,->,!=操作符
//解引用需要返回节点的val的引用,可以修改val
V& operator*()
return _node->_val;
//->操作符需要返回节点的val的指针
V* operator->()
return &_node->_val;
//判断迭代器是否相等传参就是迭代器,不是迭代器指针
bool operator!=(const Self& it)
return _node != it._node;
//迭代器的++和--重载
//返回值就是迭代器本身
//红黑树的迭代器是根据中序遍历实现,++就是中序遍历的下一个
Self& operator++()
//如果右节点存在,下一个就是右节点的最左节点
if (_node->_right)
_node = _node->_right;
while (_node->_left)
_node = _node->_left;
//若右节点不存在,需要向上寻找
//当node作为父节点的左子树时,下一个才是parent
//是父节点的右子树,父亲已经先遍历过了
else
Node* parent = _node->_parent;
while (_node == parent->_right)
_node = parent;
parent = parent->_parent;
//避免出现没有右子树,node==parent(此时parent是root),此时结束遍历了
//若node再++,程序还会跑,p更新到了root的左子树,node再一次=parent
//再次进入循环,出现死循环
if (_node->_right != parent)
_node = parent;
return *this;//返回调用++的迭代器*(前置++)
//--和++只有顺序上的不同,逻辑上相同
Self& operator--()
if (_node->_left)
_node = _node->_left;
while (_node->_right)
_node = _node->_right;
else
Node* parent = _node->_parent;
while (parent->_left == _node)
_node = parent;
parent = parent->_parent;
if (_node->_left != parent)
_node = parent;
return *this;
;
//红黑树实现
template<class K,class V,class KeyOfValue>
class RBTree
public:
typedef RBNode<V> Node;
typedef RBTreeIterator<V> iterator;
RBTree()
:_header(new Node)
_header->_left = _header->_right = _header;
//partent默认为nullptr
iterator begin()
return iterator(_header->_left);
iterator end()
return iterator(_header);
iterator rbegin()
return iterator(_header->_right);
红黑树的插入
插入接口非常繁琐,涉及到了各种情况的不同处理,需要旋转操作来保持平衡
//红黑树的插入
//返回值是当前插入位置的迭代器和一个bool
pair<iterator, bool> insert(const V& val)
//若是空树的情况
if (_header->_parent == nullptr)
Node* root = new Node(val);
_header->_parent = root;
root->_parent = _header;
_header->_left = _header->_right = root;
root->_color = BLACK;
return make_pair(iterator(root), true);
//不是空树走二叉搜索树的逻辑
Node* node = _header->_parent;//无法直接拿到root,需要这样取
Node* parent = nullptr;
KeyOfValue kov;
//注意此时就要使用回调函数区分map,set
//map的val是<k,v>键值对,比较的是val.first
//set的val就是k,可以直接比较
while (node)
parent = node;
if (kov(node->_val) == kov(val))
return make_pair(iterator(node), false);
else if (kov(node->_val) > kov(val))
node = node->_left;
else
node = node->_right;
node = new Node(val);
Node* cur = node;//用于返回迭代器
if (kov(parent->_val) > kov(node->_val))
parent->_left = node;
else
parent->_right = node;
node->_parent = parent;//加入指向
//开始进行调整,若出现连续的两个红色就需要调整
//结束条件是node不是根节点,因为根节点是黑色的,node和parent是红色就需要调整
while (node != _header->_parent&&node->_parent->_color == RED)
parent = node->_parent;
Node* gfather = parent->_parent;
//若父节点是祖父节点的左节点
if (gfather->_left == parent)
Node* uncle = gfather->_right;
//若果uncle存在并为红色
if (uncle && uncle->_color == RED)
parent->_color = uncle->_color = BLACK;
gfather->_color = RED;
//此时父节点是黑色,gfather为红色,所以更新到红色
node = gfather;
else
//uncle不存在或者为黑色都需要旋转
//此时node的位置也需要判断是否为双旋
if (node == parent->_right)
RotateL(parent);
swap(node, parent);
RotateR(gfather);
parent->_color = BLACK;
gfather->_color = RED;
break;
//若父节点是祖父节点的右节点
else
Node* uncle = gfather->_left;
//若果uncle存在并为红色
if (uncle && uncle->_color == RED)
parent->_color = uncle->_color = BLACK;
gfather->_color = RED;
//此时父节点是黑色,gfather为红色,所以更新到红色
node = gfather;
else
//uncle不存在或者为黑色都需要旋转
//此时node的位置也需要判断是否为双旋
if (node == parent->_left)
RotateR(parent);
swap(node, parent);
RotateL(gfather);
parent->_color = BLACK;
gfather->_color = RED;
break;
//调整结束,node此时可能刚刚结束旋转,gparent为红,并且不会再进入循环
//需要把根节点改黑色
_header->_parent->_color = BLACK;
//更新_header的指向
_header->_left = leftmost();
_header->_right = rightmost();
return make_pair(iterator(cur), true);
//左旋接口
void RotateL(Node* parent)
Node* subR = parent->_right;
Node* subRL = subR->_left;
subR->_left = parent;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
//判断根,不是根的情况需要祖父节点的指向
if (parent == _header->_parent)
_header->_parent = subR;
subR->_parent = _header;
else
Node* gparent = parent->_parent;
if (gparent->_left == parent)
gparent->_left = subR;
else
gparent->_right = subR;
subR->_parent = gparent;
parent->_parent = subR;
//右旋接口
void RotateR(Node* parent)
Node* subL = parent->_left;
Node* subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
//判断根,不是根的情况需要祖父节点的指向
if (parent == _header->_parent)
_header->_parent = subL;
subL->_parent = _header;
else
Node* gparent = parent->_parent;
if (gparent->_left == parent)
gparent->_left = subL;
else
gparent->_right = subL;
subL->_parent = gparent;
parent->_parent = subL;
Node* leftmost()
Node* node = _header->_parent;
while (node&& node->_left)
node = node->_left;
return node;
Node* rightmost()
Node* node = _header->_parent;
while (node && node->_right)
node = node->_right;
return node;
void inorder()
_inorder(_header->_parent);
cout << endl;
void _inorder(Node* root)
if (root)
_inorder(root->_left);
cout << root->_kv.first << " ";
_inorder(root->_right);
验证
根据红黑树的特点验证树
//红黑树的验证
bool isBalence()
//空树也是红黑树
if (_header->_parent == nullptr)
return true;
Node* root = _header->_parent;
//根节点必须为黑色
if (root->_color == RED)
return false;
//统计一条路径黑色节点的个数
int bcount = 0;
Node* node = root;
while (node)
if (node->_color == BLACK)
++bcount;
node = node->_left;
cout << "Bcount: " << bcount << endl;
int nodebcount = 0;
return _isBalence(root, bcount, nodebcount);
//递归判断每一条路径上的节点数字是否相等
//递归的结束条件:当递归到空指针时,用计数器的节点大小相比
//需要返回上一级是否当前路径的数字相等,bool返回值
//本轮递归需要判断是否为黑色并++,并继续判定左右子树是否为黑色
bool _isBalence(Node* root,int &bcount,int nodecount)
if (root == nullptr)
if (nodecount == bcount)
return true;
else
return false;
if (root->_color == BLACK)
++nodecount;
//判断是否有相邻的红色节点
if (root->_parent && root->_color == RED && root->_parent->_color == RED)
cout << "data: " << root->_kv.first << endl;
return false;
return _isBalence(root->_left, bcount, nodecount) &&
_isBalence(root->_right, bcount, nodecount);
private:
Node* _header;
;
以上是关于数据结构关联式容器底层红黑树的模拟实现的主要内容,如果未能解决你的问题,请参考以下文章
[C/C++]详解STL容器9-基于红黑树模拟实现map和set
[C/C++]详解STL容器9-基于红黑树模拟实现map和set
[C/C++]详解STL容器9-基于红黑树模拟实现map和set