文章目录
二叉搜索树
概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
- 左子树的值 < 跟 < 右子树的值
查找一个数,最多查找高度次。
操作
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
先序:中 左 右 8 3 1 6 4 7 10 14 13
中序:左 中 右 1 3 4 6 7 8 10 13 14
后序:左 右 中 1 4 7 6 3 13 14 10 8
二叉树的查找
- 从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
- 最多查找高度次,走到到空,还没找到,这个值不存在。
二叉树的插入
- 树为空,则直接新增节点,赋值给root指针。
- 树不空,按二叉搜索树性质查找插入位置,插入新节点。
二叉树的删除
- 要删除的结点无孩子结点
- 删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
- 删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
- 要删除的结点只有左孩子结点
- 删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
- 要删除的结点只有右孩子结点
- 删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
- 要删除的结点有左、右孩子结点
- 在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题–替换法删除
实现
递归
二叉树的结点
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
,_right(nullptr)
,_key(key)
{}
};
二叉搜索树的整体
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
private:
void DestoryTree(Node* root)
{
if (root == nullptr) return;
DestoryTree(root->_left);
DestoryTree(root->_right);
delete root;
}
Node* CopyTree(Node* root)
{
if (root == nullptr) return nullptr;
Node* copyNode = new Node(root->_key);
copyNode->_left = CopyTree(root->_left);
copyNode->_right = CopyTree(root->_right);
return copyNode;
}
public:
BSTree() = default; // 强制编译器自己生成
BSTree(const BSTree<K>& t)
{
_root = CopyTree(t._root);
}
~BSTree()
{
DestoryTree(_root);
_root = nullptr;
}
BSTree<K>& operator=(BSTree<K> t)
{
swap(_root, t,_root);
return *this;
}
void InOrder()
void _InOrder(Node* root);
bool FindR(const K& key);
bool InsertR(const K& key);
bool EraseR(const K& key);
private:
bool _FindR(Node* root, const K& key) ;
bool _InsertR(Node*& root, const K& key);
bool _EraseR(Node*& root, const K& key);
private:
Node* _root = nullptr;
};
中序遍历
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
查找
bool FindR(const K& key)
{
return _FindR(_root, key);
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr) return false;
if (root->_key < key) return _FindR(root->_right, key);
else if (root->_key > key) return _FindR(root->_left, key);
else return true;
}
插入
bool InsertR(const K& key)
{
_InsertR(_root, key);
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr) {
root = new Node(key);
return true;
}
if (root->_key < key) return _InsertR(root->_right, key);
else if (root->_key > key) return _InsertR(root->_left, key);
else return false;
}
删除
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr) return false;
if (root->_key < key) return _EraseR(root->_right, key);
else if (root->_key > key) return _EraseR(root->_left, key);
else {
Node* del = root;
if (root->_left == nullptr) root = root->_right;
else if (root->_right == nullptr) root = root->_left;
else {
Node* minRight = root->_right;
while (minRight->_left) minRight = minRight->_left;
swap(root->_key, minRight->_key);
return Erase(root->_right, key);
}
delete del;
return true;
}
}
非递归
二叉树的结点
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
,_right(nullptr)
,_key(key)
{}
};
二叉树搜索树的整体
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
private:
void DestoryTree(Node* root)
{
if (root == nullptr) return;
DestoryTree(root->_left);
DestoryTree(root->_right);
delete root;
}
Node* CopyTree(Node* root)
{
if (root == nullptr) return nullptr;
Node* copyNode = new Node(root->_key);
copyNode->_left = CopyTree(root->_left);
copyNode->_right = CopyTree(root->_right);
return copyNode;
}
public:
BSTree() = default; // 强制编译器自己生成
BSTree(const BSTree<K>& t)
{
_root = CopyTree(t._root);
}
~BSTree()
{
DestoryTree(_root);
_root = nullptr;
}
BSTree<K>& operator=(BSTree<K> t)
{
swap(_root, t,_root);
return *this;
}
bool insert(const K& key) ;
void InOrder() ;
void _InOrder(Node* root);
bool Find(const K& key);
bool Erase(const K& key);
private:
Node* _root = nullptr;
};
查找
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
if (cur->_key < key) cur = cur->_right;
else if (cur->_key > key) cur = cur->_left;
else return true;
return false;
}
插入
bool insert(const K& key)
{
if (_root == nullptr) {
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
parent = cur;
if (cur->_key < key) cur = cur->_right;
else if (cur->_key > key) cur = cur->_left;
else return false;
}
cur = new Node(key);
if (parent->_key < key) parent->_right = cur;
if (parent->_key > key) parent->_left = cur;
return true;
}
删除
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
parent = cur;
if (cur->_key < key) cur = cur->_right;
else if (cur->_key > key) cur = cur->_left;
else {
// 找到值所对应的结点
// 结点的左子树为空
if (cur->_left == nullptr) {
if (cur == _root) _root = cur->_right; // 如果当前结点是跟结点话, 跟结点就等于当前结点的右结点
else
if (cur == parent->_left) parent->_left = cur->_right; // 如果当前结点是父亲结点的左结点,该结点的右结点为父的左节点
else parent->_right = cur->_right;
delete cur;
// 结点的右子树为空
} else if (cur->_right == nullptr) {
if (cur == _root) _root = cur->_left;
else
if (cur == parent->_left) parent->_left = cur->_left;
else parent->_right = cur->_left;
delete cur;
} else {
Node* minRight = cur->_right;
Node* minRightParent = _root;
while (minRight->_left != nullptr) {
minRightParent = minRight;
minRight = minRight->_left;
}
cur->_key = minRight->_key;
if (minRightParent->_left == minRight) minRightParent->_left = minRight->_right;
else minRightParent->_right = minRight->_right;
delete minRight;
}
return true;
}
}
// 结点不存在 删除失败
return false;
}
应用
K
模型:K
模型即只有key
作为关键码,结构中只需要存储Key
即可,关键码即为需要搜索到的值。
* 给一个单词word,判断该单词是否拼写正确- 以词库中所有单词集合中的每个单词作为
key
,构建一棵二叉搜索树。 - 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
- 以词库中所有单词集合中的每个单词作为
KV
模型:每一个关键码key
,都有与之对应的值Value
,即<Key, Value>
的键值对。- 英汉词典
- 通过英文可以快速找到与其对应的中文,英文单词与其对应的中文
<word, chinese>
就构成一种键值对
- 通过英文可以快速找到与其对应的中文,英文单词与其对应的中文
- 统计单词次数
- 单词与其出现次数就是
<word, count>
就构成一种键值对
- 单词与其出现次数就是
- 高铁刷身份证进站
- 复杂链表的复制
- 英汉词典
KV
模型的二叉树
template<class K, class V>
struct BSTreeNode
{
BSTreeNode<K, V>* _left;
BSTreeNode<K, V>* _right;
const K _key;
V _value;
BSTreeNode(const K& key, const V& value)
:_left(nullptr)
,_right(nullptr)
,_key(key)
,_value(value)
{}
};
template<class K, class V>
class BSTree
{
typedef BSTreeNode<K, V> Node;
public:
Node* FindR(const K& key)
{
return _FindR(_root, key);
}
bool InsertR(const K& key, const V& value)
{
_InsertR(_root, key, value);
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
Node* _FindR(Node* root, const K& key)
{
if (root == nullptr) return nullptr;
if (root->_key < key) return _FindR(root->_right, key);
else if (root->_key > key) return _FindR(root->_left, key);
else return root;
}
bool _InsertR(Node*& root, const K& key, const V& value)
{
if (root == nullptr) {
root = new Node(key, value);
return true;
}
if (root->_key < key) return _InsertR(root->_right, key, value);
else if (root->_key > key) return _InsertR(root->_left, key, value);
else return false;
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr) return false;
if (root->_key < key) return _EraseR(root->_right, key);
else if (root->_key > key) return _EraseR(root->_left, key);
else {
Node* del = root;
if (root->_left == nullptr) root = root->_right;
else if (root->_right == nullptr) root = root->_left;
else {
Node* minRight = root->_right;
while (minRight->_left) minRight = minRight->_left;
swap(root->_key, minRight->_key);
return Erase(root->_right, key);
}
delete del;
return true;
}
}
private:
Node* _root = nullptr;
};
练习
- 根据二叉树创建字符串
- 二叉树的层序遍历
- 二叉树的层序遍历 II
- 二叉树的最近公共祖先
- 二叉搜索树与双向链表
- 从前序与中序遍历序列构造二叉树
- 从中序与后序遍历序列构造二叉树
- 二叉树的前序遍历
- 二叉树的中序遍历
- 二叉树的后序遍历
题目链接 | 难度 |
---|---|
根据二叉树创建字符串 | 简单 |
二叉树的层序遍历 | 中等 |
二叉树的层序遍历 II | 中等 |
二叉树的最近公共祖先 | 中等 |
二叉搜索树与双向链表 | 中等 |
从前序与中序遍历序列构造二叉树 | 中等 |
从中序与后序遍历序列构造二叉树 | 中等 |
二叉树的前序遍历 | 简单 |
二叉树的中序遍历 | 简单 |
二叉树的后序遍历 | 简单 |
AVL 树
AVL 树的概念
一棵AVL树:
- 空树
- 具有以下性质的二叉搜索树
- 它的左右子树都是AVL树
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(右减左)
最后两层缺一些结点
AVL 树的实现
子树的高度变了,就要继续往上更新,子树的高度不变,则更新完成
子树的高度不变,则更新完成
子树违反平衡规则,则停止更新,旋转子树
AVL树结点的
template<class K, class V>
struct AVLTreeNode
{
pair<K, V> _kv;
AVLTreeNode<K, V>* _left; // 左孩子
AVLTreeNode<K, V>* _right; // 有孩子
AVLTreeNode<K, V>* _parent;// 父亲
int _bf; // 平衡因子
AVLTreeNode(const pair<K, V>& kv)
:_kv(kv)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_bf(0)
{}
};
AVL树的整体
template<class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node; // 重命名AVL树的一个结点
public:
bool Insert(const pair<K, V>& kv); // 插入数据
void printTree(); // 打印树
bool IsBalanceTree(); // 判断树是否是AVL树
int Height(); // 得到高度
private:
void RotateL(Node* parent); // 左旋
void RotateR(Node* parent); // 右旋
void RotateLR(Node* parent); // 先左旋 后右旋
void RotateRL(Node* parent); // 先右旋 后左旋
string getSpace(int num);
void printInOrder(Node* head, int height, string to, int len);
int _Height(Node* root);
bool _IsBalanceTree(Node* root);
private:
Node* _root = nullptr;
};
AVL树的插入
在这里,平衡因子的计算规则是:
- 右子树的高度减去左子树的高度的代数值。
- 如果插在父亲的右边,则父亲的平衡因子加1。
- 如果加在父亲的左边,则平衡因子减1
当插入一个数据时,需要更新所有祖先的平衡因子。如果跟新平衡因子之后
- 父亲的平衡因子等于0,则更新平衡因子结束
- 平衡因子为0,表示此次跟新,对该树的高度没有影响
- 父亲的平衡因子为正负1,需要继续向上跟新
- 平衡因子的绝对值为1,表示此次跟新,该树的高度增加了1
- 父亲的平衡因子为正负2,需要对树进行翻转
- 平衡因子的绝对值为2,表示此次更新,打破了AVL的规则
插入数据时可能会导致的不同情况及处理策略:
- 新结点插入较高左树的左侧时 — 右旋
在这里插入图片描述
-
新结点插入较高左树的右侧时 – 左右旋
-
新结点插入较高右侧的右侧时 – 左旋
- 新结点插入较高右树的左侧时 – 右左旋
bool Insert(const pair<K, V>& kv) {
if (_root == nullptr) {
_root = new Node(kv);
_root->_bf = 0;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
parent = cur;
if (cur->_kv.first < kv.first) cur = cur->_right;
else if (cur->_kv.first > kv.first) cur = cur->_left;
else return false;
}
cur = new Node(kv);
if (parent->_kv.first < kv.first) parent->_right = cur;
else parent->_left = cur;
cur->_parent = parent;
while (parent) {
if (cur == parent->_right) parent->_bf++;
else parent->_bf--;
if (parent->_bf == 0) {
break;
} else if (parent->_bf == 1 || parent->_bf == -1) {
cur = cur->_parent;
parent = parent->_parent;
} else if (parent->_bf == 2 || parent->_bf == -2) {
if (parent->_bf == 2 && cur->_bf == 1) RotateL(parent);
else if (parent->_bf == -2 && cur->_bf == -1) RotateR(parent);
else if (parent->_bf == -2 && cur->_bf == 1) RotateLR(parent);
else if (parent->_bf == 2 && cur->_bf == -1) RotateRL(parent);
else assert(false);
break;
} else assert(false);
}
return true;
}
void RotateL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* ppNode = parent->_parent;
parent->_right = subRL;
if (subRL) subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root) {
_root = subR;
_root->_parent = nullptr;
} else {
if (parent == ppNode->_left) ppNode->_left = subR;
else ppNode->_right = subR;
subR->_parent = ppNode;
}
parent->_bf = subR->_bf = 0;
}
void RotateR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* ppNode = parent->_parent;
parent->_left = subLR;
if (subLR) subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root) {
_root = subL;
_root->_parent = nullptr;
} else {
if (parent == ppNode->_left) ppNode->_left = subL;
else ppNode->_right = subL;
subL->_parent = ppNode;
}
parent->_bf = subL->_bf = 0;
}
void RotateLR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 0) {
parent->_bf = subL->_bf = subLR->_bf = 0;
} else if (bf == 1) {
parent->_bf = subLR->_bf = 0;
subL->_bf = -1;
} else if (bf == -1) {
subL->_bf = subLR->_bf = 0;
parent->_bf = 1;
} else {
assert(false);
}
}
void RotateRL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
if (bf == 0) {
subRL->_bf = parent->_bf = subR->_bf = 0;
} else if (bf == 1) {
subRL->_bf = subR->_bf = 0;
parent->_bf = -1;
} else if (bf == -1) {
subRL->_bf = parent->_bf = 0;
subR->_bf = 1;
} else {
assert(false);
}
}
AVL树的删除
注:以后补充
AVL树的打印
void printTree() {
cout << "Binary Tree:" << endl;
printInOrder(_root, 0, "H", 17);
cout << endl;
}
string getSpace(int num) {
string space = " ";
string buf = "";
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf;
}
void printInOrder(Node* head, int height, string to, int len) {
if (head == nullptr) return;
printInOrder(head->_right, height + 1, "v", len); // 递归遍历右子树
string val = "";
val += to;
val += to_string((head->_kv).first);
val += to;
int lenM = val.size();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
cout << getSpace(height * len) + val << endl;
printInOrder(head->_left, height + 1, "^", len); // 递归遍历左子树
}
AVL 树的验证
bool IsBalanceTree() {
_IsBalanceTree(_root);
}
int _Height(Node* root) {
if (root == nullptr) return 0;
int lh = _Height(root->_left);
int rh = _Height(root->_right);
return lh > rh ? lh + 1 : rh + 1;
}
bool _IsBalanceTree(Node* root) {
if (nullptr == root) return true;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
int diff = rightHeight - leftHeight;
if (abs(diff) >= 2) {
cout << root->_kv.first << "节点平衡因子异常" << endl;
return false;
}
if (diff != root->_bf) {
cout << root->_kv.first << "节点平衡因子不符合实际" << endl;
return false;
}
return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
}
红黑树
红黑树的概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
红黑树的性质
- 每个结点不是红色就是黑色
- 根节点是黑色的
- 如果一个节点是红色的,则它的两个孩子结点是黑色的
- 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点
- 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
- 红黑树的最长路径结点的个数不会超过最短路径结点个数的二倍
红黑树的实现
红黑树的结点
enum Colour //枚举红黑树的颜色
{
RED,
BLACK,
};
// 红黑树的结点
template<class K, class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left; // 左孩子
RBTreeNode<K, V>* _right; // 右孩子
RBTreeNode<K, V>* _parent; // 父亲
pair<K, V> _kv;
Colour _col; // 树的颜色
RBTreeNode(const pair<K, V>& kv)
:_kv(kv)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_col(RED)
{}
};
红黑树的整体
template<class K, class V>
class RBTree
{
typedef RBTreeNode<K, V> Node;
public:
bool Insert(const pair<K, V>& kv);
void printTree();
bool IsValidRBTree();
private:
void RotateL(Node* parent);
void RotateR(Node* parent);
string getSpace(int num);
void printInOrder(Node* head, int height, string to, int len);
bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount);
private:
Node* _root = nullptr;
};
红黑树的插入
每次新加入一个结点,把这个结点设置为红色
- 如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;
- 但当新插入节点的双亲节点颜色为红色时,就违反了性质三不能有连在一起的红色节点,此时需要对红黑树分情况来讨论
约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点。
不同的情况及其调整的策略
-
cur为红,p为红,g为黑,u存在且为红
解决方式:
将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
如果g为跟结点,则需要把g变为黑色
-
cur为红,p为红,g为黑,u不存在/u存在且为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转
p为g的右孩子,cur为p的右孩子,则进行左单旋转-
u不存在的时候
进行右单旋
同时将p变为黑色,将cur和g变为红色
-
u存在的时候
这种情况一定是由上一种情况变化而来的
比如:
左图经过调整之后可以变为右图
-
-
cur为红,p为红,g为黑,u不存在/u存在且为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转,然后再右单旋
p为g的右孩子,cur为p的左孩子,则针对p做右单旋转,然后再左单旋
bool Insert(const pair<K, V>& kv) {
if (_root == nullptr) {
_root = new Node(kv);
_root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
parent = cur;
if (cur->_kv.first < kv.first) cur = cur->_right;
else if (cur->_kv.first > kv.first) cur = cur->_left;
else return false;
}
cur = new Node(kv);
cur->_col = RED;
if (parent->_kv.first < kv.first) parent->_right = cur;
else parent->_left = cur;
cur->_parent = parent;
while (parent && parent->_col == RED) {
Node* grandfather = parent->_parent;
if (parent == grandfather->_left) {
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED) {
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
} else {
if (cur == parent->_left) {
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
} else {
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
} else {
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED) {
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
} else {
if (cur == parent->_right) {
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
} else {
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return true;
}
void RotateL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* ppNode = parent->_parent;
parent->_right = subRL;
if (subRL) subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root) {
_root = subR;
_root->_parent = nullptr;
} else {
if (parent == ppNode->_left) ppNode->_left = subR;
else ppNode->_right = subR;
subR->_parent = ppNode;
}
}
void RotateR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* ppNode = parent->_parent;
parent->_left = subLR;
if (subLR) subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root) {
_root = subL;
_root->_parent = nullptr;
} else {
if (parent == ppNode->_left) ppNode->_left = subL;
else ppNode->_right = subL;
subL->_parent = ppNode;
}
}
判断是否为红黑树
bool IsValidRBTree() {
Node* pRoot = _root;
if (nullptr == pRoot) return true;
if (BLACK != pRoot->_col) {
cout << "违反红黑树性质二:根节点必须为黑色" << endl;
return false;
}
size_t blackCount = 0;
Node* Cur = pRoot;
// 统计最左侧的黑树的个数 求出每条路径黑色结点的数量
while (Cur) {
if (BLACK == Cur->_col) blackCount++;
Cur = Cur->_left;
}
size_t k = 0;
return _IsValidRBTree(pRoot, k, blackCount);
}
bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount) {
if (nullptr == pRoot) {
if (k != blackCount) {
cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
return false;
}
return true;
}
if (BLACK == pRoot->_col) k++;
if (pRoot->_parent && RED == pRoot->_parent->_col && RED == pRoot->_col) {
cout << "违反性质三:没有连在一起的红色节点" << endl;
return false;
}
return _IsValidRBTree(pRoot->_left, k, blackCount) && _IsValidRBTree(pRoot->_right, k, blackCount);
}
树的打印
void printTree() {
cout << "Binary Tree:" << endl;
printInOrder(_root, 0, "H", 17);
cout << endl;
}
string getSpace(int num) {
string space = " ";
string buf = "";
for (int i = 0; i < num; i++) {
buf.append(space);
}
return buf;
}
void printInOrder(Node* head, int height, string to, int len) {
if (head == nullptr) return;
printInOrder(head->_right, height + 1, "v", len); // 递归遍历右子树
string val = "";
val += to;
val += to_string((head->_kv).first);
val += to;
int lenM = val.size();
int lenL = (len - lenM) / 2;
int lenR = len - lenM - lenL;
val = getSpace(lenL) + val + getSpace(lenR);
cout << getSpace(height * len) + val << endl;
printInOrder(head->_left, height + 1, "^", len); // 递归遍历左子树
}
红黑树模拟实现STL中的map与set
对红黑树做一些变化
做的变化有:
- 要使用红黑树模拟实现map和set,而map接受两个模板参数,set接受一个模板参数, 所以,set在调用红黑树时
RBTree<k, k>
map 在调用红黑树时可以RBTree<k, pair<k, v>>
- 要进行插入值的时候,需要当前插入的值和目标值进行比较大小,所以需要一个返回结点处值的仿函数
- 需要一个迭代器,进行处理map和set
对红黑树做一些变化,变化之后的代码:
enum Colour
{
RED,
BLACK,
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Colour _col;
RBTreeNode(const T& data)
:_data(data)
,_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_col(RED)
{}
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
__RBTreeIterator(Node* node)
:_node(node)
{ }
Ref operator*() {
return _node->_data;
}
Ptr operator->() {
return &_node->_data;
}
Self& operator++() {
if (_node->_right == nullptr) {
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur) {
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
} else {
Node* subLeft = _node->_right;
while (subLeft->_left) {
subLeft = subLeft->_left;
}
_node = subLeft;
}
return *this;
}
Self operator++(int) {
Self tmp(*this);
++(*this);
return tmp;
}
Self& operator--() {
if (_node->_left == nullptr) {
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left) {
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
} else {
Node* subRight = _node->_left;
while (subRight->_right) {
subRight = subRight->_right;
}
_node = subRight;
}
return *this;
}
Self operator--(int) {
Self tmp(*this);
--(*this);
return tmp;
}
bool operator!=(const Self& s) const {
return _node != s._node;
}
bool operator==(const Self& s) const {
return _node == s._node;
}
};
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __RBTreeIterator<T, T&, T*> iterator;
typedef __RBTreeIterator<T, const T&, const T*> const_iterator;
iterator Begin() {
Node* subLeft = _root;
while (subLeft && subLeft->_left) {
subLeft = subLeft->_left;
}
return iterator(subLeft);
}
iterator End() {
return iterator(nullptr);
}
const_iterator Begin() const {
Node* subLeft = _root;
while (subLeft && subLeft->_left) {
subLeft = subLeft->_left;
}
return const_iterator(subLeft);
}
const_iterator End() const {
return const_iterator(nullptr);
}
iterator Find(const K& key) {
Node* cur = _root;
KeyOfT kot;
while (cur) {
if (kot(cur->_data) < key) {
cur = cur->_right;
} else if (kot(cur->_data) > key) {
cur = cur->_left;
} else {
return iterator(cur);
}
}
return End();
}
pair<iterator, bool> Insert(const T& data) {
if (_root == nullptr) {
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
KeyOfT kot;
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
parent = cur;
if (kot(cur->_data) < kot(data)) cur = cur->_right;
else if (kot(cur->_data) > kot(data)) cur = cur->_left;
else return make_pair(iterator(cur), false);
}
cur = new Node(data);
Node* newNode = cur;
cur->_col = RED;
if (kot(parent->_data) < kot(data)) parent->_right = cur;
else parent->_left = cur;
cur->_parent = parent;
while (parent && parent->_col == RED) {
Node* grandfather = parent->_parent;
if (parent == grandfather->_left) {
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED) {
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
} else {
if (cur == parent->_left) {
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
} else {
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
} else {
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED) {
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
} else {
if (cur == parent->_right) {
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
} else {
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return trmake_pair(iterator(newNode), true);
}
bool IsValidRBTree() {
Node* pRoot = _root;
if (nullptr == pRoot) return true;
if (BLACK != pRoot->_col) {
cout << "违反红黑树性质二:根节点必须为黑色" << endl;
return false;
}
size_t blackCount = 0;
Node* Cur = pRoot;
// 统计最左侧的黑树的个数 求出每条路径黑色结点的数量
while (Cur) {
if (BLACK == Cur->_col) blackCount++;
Cur = Cur->_left;
}
size_t k = 0;
return _IsValidRBTree(pRoot, k, blackCount);
}
void RotateL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
Node* ppNode = parent->_parent;
parent->_right = subRL;
if (subRL) subRL->_parent = parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root) {
_root = subR;
_root->_parent = nullptr;
} else {
if (parent == ppNode->_left) ppNode->_left = subR;
else ppNode->_right = subR;
subR->_parent = ppNode;
}
}
void RotateR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
Node* ppNode = parent->_parent;
parent->_left = subLR;
if (subLR) subLR->_parent = parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root) {
_root = subL;
_root->_parent = nullptr;
} else {
if (parent == ppNode->_left) ppNode->_left = subL;
else ppNode->_right = subL;
subL->_parent = ppNode;
}
}
bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount) {
if (nullptr == pRoot) {
if (k != blackCount) {
cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
return false;
}
return true;
}
if (BLACK == pRoot->_col) k++;
if (pRoot->_parent && RED == pRoot->_parent->_col && RED == pRoot->_col) {
cout << "违反性质三:没有连在一起的红色节点" << endl;
return false;
}
return _IsValidRBTree(pRoot->_left, k, blackCount) && _IsValidRBTree(pRoot->_right, k, blackCount);
}
private:
Node* _root = nullptr;
};
使用红黑树实现set
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& key) {
return key;
}
};
public:
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const {
return _t.Begin();
}
iterator end() const {
return _t.End();
}
iterator Find(const K& key) {
return _t.Find(key);
}
pair<iterator, bool> insert(const K& key) {
pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
return pair<iterator, bool>(iterator(ret.first._node), ret.second);
}
private:
RBTree<K, K, SetKeyOfT> _t;
};
使用红黑树实现map
template<class K, class V>
class map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv) {
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
bool insert(const pair<K, V>& kv) {
return _t.Insert(kv);
}
iterator begin() {
return _t.Begin();
}
iterator end() {
return _t.End();
}
iterator begin() const {
return _t.Begin();
}
iterator end() const {
return _t.End();
}
iterator Find(const K& key) {
return _t.Find(key);
}
V& operator[](const K& key) {
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};