目录
红黑树的介绍
-
大家可以去看我之前的博客模拟实现红黑树,里面详细的介绍了红黑树的主题逻辑,本文着重介绍迭代器和封装
封装版本的红黑树
-
新版本红黑树的完整代码
#pragma once
namespace HQJ
{
enum Color
{
RED,
BLACK
};
//template<class K ,class V>这里不用data是为了封装做准备
template<class T>//
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _color;
RBTreeNode(const T& data)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _data(data)
, _color(RED)
{}
};
template<class T>
struct _iterator
{
typedef RBTreeNode<T> Node;
typedef _iterator<T> self;
Node* _node;
_iterator(Node* node)
:_node(node)
{}
self& operator++()
{
if (_node->_right != nullptr)
{
Node* cur = _node->_right;
while (cur && cur->_left)
{
cur = cur->_left;
}
_node = cur;
}
else
{
Node* cur = _node;
Node* parent = _node->_parent;
while (parent && cur == parent->_right)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
return *this;
}
bool operator!=(const self& node)
{
return _node != node._node;
}
bool operator==(const self& node)
{
return (*this != node);
}
T* operator->()
{
return &(_node->_data);
}
T& operator*()
{
return _node->_data;
}
};
template<class K, class V, class keyOfT>
class RBTree
{
public:
typedef RBTreeNode<V> Node;
typedef _iterator<V> iterator;
iterator begin()
{
Node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return iterator(cur);
}
iterator end()
{
return iterator(nullptr);
}
bool Insert(const V& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_color = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (_kot(cur->_data) < _kot(data))
{
parent = cur;
cur = cur->_right;
}
else if (_kot(cur->_data) > _kot(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(data);
cur->_color = RED;
if (_kot(parent->_data) < _kot(data))
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
while (parent && parent->_color == RED)
{
Node* grandfather = parent->_parent;
if (parent == grandfather->_left)
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_color == RED)
{
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur == parent->_left)
{
RotateR(grandfather);
parent->_color = BLACK;
grandfather->_color = RED;
}
else
{
RotateL(parent);
RotateR(grandfather);
cur->_color = BLACK;
grandfather->_color = RED;
}
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_color == RED)
{
parent->_color = uncle->_color = BLACK;
grandfather->_color = RED;
cur = grandfather;
}
else
{
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_color = BLACK;
grandfather->_color = RED;
}
else
{
RotateR(parent);
RotateL(grandfather);
cur->_color = BLACK;
grandfather->_color = RED;
}
break;
}
}
}
_root->_color = BLACK;
return true;
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
subR->_left = parent;
Node* parentParent = parent->_parent;
parent->_parent = subR;
if (subRL)
subRL->_parent = parent;
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (parentParent->_left == parent)
{
parentParent->_left = subR;
}
else
{
parentParent->_right = subR;
}
subR->_parent = parentParent;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* parentParent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (parentParent->_left == parent)
{
parentParent->_left = subL;
}
else
{
parentParent->_right = subL;
}
subL->_parent = parentParent;
}
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_data.first << " ";
_InOrder(root->_right);
}
private:
// 根节点->当前节点这条路径的黑色节点的数量
bool Check(Node* root, int blacknum, const int refVal)
{
if (root == nullptr)
{
//cout << balcknum << endl;
if (blacknum != refVal)
{
cout << "存在黑色节点数量不相等的路径" << endl;
return false;
}
return true;
}
if (root->_color == RED && root->_parent->_color == RED)
{
cout << "有连续的红色节点" << endl;
return false;
}
if (root->_color == BLACK)
{
++blacknum;
}
return Check(root->_left, blacknum, refVal)
&& Check(root->_right, blacknum, refVal);
}
public:
bool IsBalance()
{
if (_root == nullptr)
return true;
if (_root->_color == RED)
return false;
//参考值
int refVal = 0;
Node* cur = _root;
while (cur)
{
if (cur->_color == BLACK)
{
++refVal;
}
cur = cur->_left;
}
int blacknum = 0;
return Check(_root, blacknum, refVal);
}
private:
Node* _root = nullptr;
keyOfT _kot;
};
}
新增加的部分(迭代器)
-
成员变量
Node* _node;:指向当前迭代器所代表的红黑树节点的指针。
-
构造函数
_iterator(Node* node) : _node(node) {}:接收一个指向红黑树节点的指针,并将其赋值给_node。
-
前置递增运算符 operator++()
这个函数实现了迭代器的前置递增操作,即将迭代器移动到下一个节点。如果当前节点有右子树,则找到右子树中的最左侧节点作为下一个节点。如果当前节点没有右子树,则沿着父节点的链向上遍历,直到找到一个节点,该节点是其父节点的左子节点,或者遍历到根节点(即没有更多的父节点)。更新_node以指向新的节点。
-
不等运算符 operator!=()
比较当前迭代器和另一个迭代器是否指向不同的节点。 如果两个迭代器的_node指针不同,则返回true,否则返回false。
-
相等运算符 operator==()
比较当前迭代器和另一个迭代器是否指向相同的节点。实际上,这里的实现是通过调用operator!=()并返回其反值,可能不是最高效的实现方式,但逻辑上没有问题。
-
解引用运算符 operator->()
允许通过迭代器直接访问节点的数据成员,类似于指针的解引用。 返回一个指向节点数据成员的指针。
-
解引用运算符 operator*()
返回当前节点所存储的数据的引用。通过这个运算符,可以直接修改红黑树节点的数据。
template<class T>
struct _iterator
{
typedef RBTreeNode<T> Node;
typedef _iterator<T> self;
Node* _node;
_iterator(Node* node)
:_node(node)
{}
self& operator++()
{
if (_node->_right != nullptr)
{
Node* cur = _node->_right;
while (cur && cur->_left)
{
cur = cur->_left;
}
_node = cur;
}
else
{
Node* cur = _node;
Node* parent = _node->_parent;
while (parent && cur == parent->_right)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
return *this;
}
bool operator!=(const self& node)
{
return _node != node._node;
}
bool operator==(const self& node)
{
return (*this != node);
}
T* operator->()
{
return &(_node->_data);
}
T& operator*()
{
return _node->_data;
}
};
map的模拟实现
-
模板参数
myMap有两个模板参数:K和V,分别代表键(Key)的类型和值(Value)的类型。
-
成员函数
Insert(const pair<K, V>& data) 这个函数接受一个pair<K, V>类型的参数,并尝试将其插入到红黑树中。它直接调用红黑树的Insert函数来完成插入操作。
内部结构体 MapkeyOfT 这个结构体定义了一个函数对象(也称为仿函数),它接受一个pair<K, V>类型的参数,并返回其键(即pair的first成员)。这个函数对象被用作红黑树的键提取函数,以便红黑树能够正确地根据键来排序和查找节点。
typedef别名 iterator 这里使用typedef为红黑树的迭代器类型定义了一个别名iterator。这个别名使得myMap的用户可以更方便地引用和使用迭代器。
begin() 和 end() 这两个函数分别返回指向红黑树中第一个节点和尾后节点的迭代器。它们允许用户遍历myMap中的所有元素。
-
私有成员
_tree是一个红黑树对象,它使用K作为键类型,pair<K, V>作为值类型,并使用MapkeyOfT作为键提取函数。
-
模拟实现的全部代码
#pragma once
#include"RBTree.h"
namespace HQJ
{
template<class K, class V>
class myMap
{
public:
bool Insert(const pair<K, V>& data)
{
return _tree.Insert(data);
}
struct MapkeyOfT
{
const K& operator()(const pair<K, V>& data)
{
return data.first;
}
};
typedef typename RBTree<K, pair<K, V>, MapkeyOfT>::iterator iterator;
iterator begin()
{
return _tree.begin();
}
iterator end()
{
return _tree.end();
}
private:
RBTree<K, pair<K, V>, MapkeyOfT> _tree;
};
}
set的模拟实现
-
模板参数
mySet有一个模板参数K,代表集合中元素的类型。
-
成员函数
Insert(const K& data) 这个函数接受一个类型为K的参数,并尝试将其插入到红黑树中。它直接调用红黑树的Insert函数来完成插入操作。
内部结构体 SetkeyOfT 这个结构体定义了一个函数对象(也称为仿函数),它接受一个类型为K的参数,并返回该参数本身。这个函数对象被用作红黑树的键提取函数,以便红黑树能够正确地根据键来排序和查找节点。对于集合来说,键和值实际上是相同的,因此这个函数对象只是简单地返回了传入的参数。
typedef别名 iterator 这里使用typedef为红黑树的迭代器类型定义了一个别名iterator。这个别名使得mySet的用户可以更方便地引用和使用迭代器。
begin() 和 end() 这两个函数分别返回指向红黑树中第一个节点和尾后节点的迭代器。它们允许用户遍历mySet中的所有元素。
-
私有成员
_tree是一个红黑树对象,它使用K作为键类型和值类型,并使用SetkeyOfT作为键提取函数。由于集合中键和值是相同的,因此这里使用了相同的类型K作为键和值。
-
模拟实现的全部代码
#pragma once
#include"RBTree.h"
namespace HQJ
{
template<class K>
class mySet
{
public:
bool Insert(const K& data)
{
return _tree.Insert(data);
}
struct SetkeyOfT
{
const K& operator()(const K& data)
{
return data;
}
};
typedef typename RBTree<K, K, SetkeyOfT>::iterator iterator;
iterator begin()
{
return _tree.begin();
}
iterator end()
{
return _tree.end();
}
private:
RBTree<K, K, SetkeyOfT> _tree;
};
}