以下代码若有 bug, 可以看看 gitee/bst
数据比较多时可能出现 bug, 懒得改文章了...
二叉搜索树
定义
每一个元素有一个唯一的关键字, 左子树关键字小于根节点的关键字, 右子树关键字大于根节点的关键字
有重复值的二叉搜索树
左子树关键字小于等于根, 右子树关键字大于等于根
索引二叉搜索树
每个节点存在一个“索引”, 这个值为左子树的个数(leftSize)
这样将某个节点作为根节点, 其对应的搜索树按顺序放入顺序表, 其 leftSize 就是其索引
上图以节点 20 作为搜索树, 其索引的 3, 以节点 25 作为搜索树, 其索引是 0
代码实现
搜索
template<class K, class E>
pair<const K, E>* binarySearchTree<K, E>::find(const K& theKey) {
binaryTreeNode<pair<const K, E>>* p = this->root;
while (p != NULL) {
if (theKey < p -> element.first) {
// theKey 比 p 的 key 小, 说明在左子树里
p = p->leftChild;
}
else if (theKey > p->element.first) {
p = p->rightChild;
}
else {
return &p->element;
}
}
// 无匹配对象
return NULL;
}
时间复杂度:
插入
template<class K, class E>
void binarySearchTree<K, E>::insert(const pair<const K, E>& thePair) {
binaryTreeNode<pair<const K, E>>* p = this->root,
* pp = NULL;
// 查找符合条件的节点, 找不到返回一个最接近的
while (p != NULL) {
pp = p;
if (thePair.first < p->element.first) {
p = p->leftChild;
}
else if (thePair.first > p->element.first) {
p = p->rightChild;
}
else {
// 找到了就直接覆盖
p->element.second = thePair.second;
return;
}
}
// 不存在, 创建新节点
binaryTreeNode<pair<const K, E>>* newNode
= new binaryTreeNode<pair<const K, E>>(thePair);
if (this->root != NULL) {
if (thePair.first < pp->element.first) {
// pp 大于 thePair, 将 thePair 插入右子树
pp->leftChild = newNode;
}
else {
pp->rightChild = newNode;
}
}
else {
this->root = newNode;
}
this->treeSize++;
}
删除
- 如果要删除的是叶子节点, 将其父节点相关子节点置为 NULL, 并 delete 该节点即可
- 存在一个子树, 若要删除的是根节点, 则其子节点作为新的根节点, 如果不是根节点, 则令其父节点对应的子节点指向要删除的节点的子节点, 然后释放该节点
// 只有一个子树, 或者没有子树
binaryTreeNode<pair<const K, E>>* c;
if (p->leftChild != NULL) {
c = p->leftChild; // 用 c 接住要删除节点的子树
}
else {
c = p->rightChild; // 如果 p 没有子树, 此时 c=NULL
}
// 删除 p 并将 c 作为父节点 pp 的新子树
if (p == this->root) {
this->root = c;
}
else if (p == pp->leftChild) {
pp->leftChild = c;
}
else {
pp->rightChild = c;
}
- 如果存在两个子树, 则用 s 新建一个节点 q, 其中 s 为左子树中最大元素或右子树中最小元素, 并在树中删除 s
if (p->leftChild != NULL && p->rightChild != NULL) {
binaryTreeNode<pair<const K, E>>* s = p->leftChild,
* ps = p;
// 遍历至左子树的最大子节点处
// 结束时 s 指向左子树的最大元素
// ps 指向 s 的父节点
while (s->rightChild != NULL) {
ps = s;
s = s->rightChild;
}
binaryTreeNode<pair<const K, E>>* q
= new binaryTreeNode<pair<const K, E>>
(s->element, p->leftChild, p->rightChild);
if (pp == NULL) {
// 父节点不存在, 说明删除的是根节点
this->root = q;
}
else if (p == pp->leftChild) {
// p 是 pp 的左节点
// 则用新节点 q 替换 p
pp->leftChild = q;
}
else {
// p 是 pp 的右节点
pp->rightChild = q;
}
// 如果最大元素的父节点就是要删除的那个节点
if (ps == p) {
pp = q;
}
else {
pp = ps;
}
delete p;
p = s;
}
代码末尾将 s 赋给 p, 就是为了后面删除 s, 因为由上图可知, q 本身是带有未删除的 s(节点 35), 因此 s 会作为单子树节点或叶子被删除
下面代码的意义就是将 s 的父节点作为 pp, 这样就方便后面删除 s, 如果最大元素的父节点就是要删除的节点, 因为它要被删除了, 所以只能用新节点作为 pp, 但是如果不是被删除的节点, 因为还在, 所以可以作为 pp
// 如果最大元素的父节点就是要删除的那个节点
if (ps == p) {
pp = q;
}
else {
pp = ps;
}
时间复杂度:
完整代码
#include<iostream>
using namespace std;
// 节点类
template<class T>
struct binaryTreeNode {
T element; // 数据
// 左右子节点
binaryTreeNode<T>* leftChild, * rightChild;
// 构造函数
binaryTreeNode() {
leftChild = rightChild = NULL;
}
binaryTreeNode(const T& theElement):element(theElement) {
leftChild = rightChild = NULL;
}
binaryTreeNode(const T& theElement,
binaryTreeNode* leftChild,
binaryTreeNode* rightChild):element(theElement)
{
this->leftChild = leftChild;
this->rightChild = rightChild;
}
};
// 二叉搜索树
template<class K, class E>
class binarySearchTree {
private:
binaryTreeNode<pair<const K, E>>* root;
int treeSize;
public:
binarySearchTree() {
root = NULL;
treeSize = 0;
}
~binarySearchTree() {
postOrderdelete(root);
root = NULL;
treeSize = 0;
}
void ascend() {
// 搜索树(键)升序输出就是中序遍历
inOrderOutput();
}
pair<const K, E>* find(const K&);
void insert(const pair<const K, E>&);
void erase(const K&);
bool empty() {
return treeSize == 0;
};
int size() {
return treeSize;
};
// 中序遍历输出节点数据
void inOrderOutput() {
inOrder(root);
cout << endl;
}
void inOrder(binaryTreeNode<pair<const K, E>>* t) {
if (t != NULL) {
inOrder(t->leftChild); // 访问左子树
output(t);
inOrder(t->rightChild); // 访问右子树
}
}
// 后续遍历删除节点
void postOrderdelete(binaryTreeNode<pair<const K, E>>* t) {
if (t != NULL) {
postOrderdelete(t->leftChild); // 访问左子树
postOrderdelete(t->rightChild); // 访问右子树
dispose(t);
}
}
private:
static void output(binaryTreeNode<pair<const K, E>>* t) {
cout << "节点数据" << t->element.second << endl;
}
static void dispose(binaryTreeNode<pair<const K, E>>* t) {
delete t;
}
};
template<class K, class E>
pair<const K, E>* binarySearchTree<K, E>::find(const K& theKey) {
binaryTreeNode<pair<const K, E>>* p = this->root;
while (p != NULL) {
if (theKey < p -> element.first) {
// theKey 比 p 的 key 小, 说明在左子树里
p = p->leftChild;
}
else if (theKey > p->element.first) {
p = p->rightChild;
}
else {
return &p->element;
}
}
// 无匹配对象
return NULL;
}
template<class K, class E>
void binarySearchTree<K, E>::insert(const pair<const K, E>& thePair) {
binaryTreeNode<pair<const K, E>>* p = this->root,
* pp = NULL;
// 查找符合条件的节点, 找不到返回一个最接近的
while (p != NULL) {
pp = p;
if (thePair.first < p->element.first) {
p = p->leftChild;
}
else if (thePair.first > p->element.first) {
p = p->rightChild;
}
else {
p->element.second = thePair.second;
return;
}
}
// 不存在, 创建新节点
binaryTreeNode<pair<const K, E>>* newNode
= new binaryTreeNode<pair<const K, E>>(thePair);
if (this->root != NULL) {
if (thePair.first < pp->element.first) {
// pp 大于 thePair, 将 thePair 插入右子树
pp->leftChild = newNode;
}
else {
pp->rightChild = newNode;
}
}
else {
this->root = newNode;
}
this->treeSize++;
}
template<class K, class E>
void binarySearchTree<K, E>::erase(const K& theKey) {
binaryTreeNode<pair<const K, E>>* p = this->root,
* pp = NULL;
// 寻找匹配的 key
// 如果找到, 则 pp 指向匹配节点 p 的父节点
while (p != NULL && p->element.first != theKey) {
pp = p;
if (theKey < p->element.first) {
p = p->leftChild;
}
else {
p = p->rightChild;
}
}
if (p == NULL) {
return; // 不存在匹配项
}
// p 存在两个子树
if (p->leftChild != NULL && p->rightChild != NULL) {
binaryTreeNode<pair<const K, E>>* s = p->leftChild,
* ps = p;
// 遍历至左子树的最大子节点处
// 结束时 s 指向左子树的最大元素
// ps 指向 s 的父节点
while (s->rightChild != NULL) {
ps = s;
s = s->rightChild;
}
binaryTreeNode<pair<const K, E>>* q
= new binaryTreeNode<pair<const K, E>>
(s->element, p->leftChild, p->rightChild);
if (pp == NULL) {
// 父节点不存在, 说明删除的是根节点
this->root = q;
}
else if (p == pp->leftChild) {
// p 是 pp 的左节点
// 则用新节点 q 替换 p
pp->leftChild = q;
}
else {
// p 是 pp 的右节点
pp->rightChild = q;
}
// 如果最大元素的父节点就是要删除的那个节点
if (ps == p) {
pp = q;
}
else {
pp = ps;
}
delete p;
p = s;
}
// 只有一个子树, 或者没有子树
binaryTreeNode<pair<const K, E>>* c;
if (p->leftChild != NULL) {
c = p->leftChild;
}
else {
c = p->rightChild; // 如果 p 没有子树, 此时 c=NULL
}
// 删除 p
if (p == this->root) {
this->root = c;
}
else if (p == pp->leftChild) {
pp->leftChild = c;
}
else {
pp->rightChild = c;
}
this->treeSize--;
delete p;
}
int main() {
binarySearchTree<int, int> b;
pair<int, int> a(10, 20);
b.insert(a);
pair<int, int> c(20, 30);
b.insert(c);
pair<int, int> d(15, 10);
b.insert(d);
b.ascend();
return 0;
}
有重复值
将普通二叉搜素树的插入函数 while 改成
while (p != NULL) {
pp = p;
if (thePair.first <= p->element.first) {
p = p->leftChild;
}
else {
p = p->rightChild;
}
}
索引搜索树
在 binaryTreeNode 的基础上加上 listSzie
template<class T>
struct binaryTreeNode {
T element; // 数据
int leftSize; // 左子树元素个数
// 其他...
// 记得初始化 leftSize 为 0
}
查找
按 index 查找, index 的范围为 1~treeSize
比如我要找 25, 它是第 5 个元素, 因此 index=5, 我们需要让 index - 1, 使其从 0 开始, 然后从根节点出发, 4 > 3, 因此我们要找的元素在根节点的右子树中, 这时我们要将 index - (leftSize+1) = 0 作为新的 index
再比如我们要找的是 15, 它是第 2 个元素, 因此 index = 2, index - 1 = 1, 因为 1 < 3, 因此在左子树中, 但是此时 index 不需要改变
template<class K, class E>
pair<const K, E>* binarySearchTree<K, E>::find_index(int index) {
if (index > treeSize) {
return; // index 超范围了
}
binaryTreeNode<pair<const K, E>>* p = root;
index--; // 让索引从 0 开始
while (p != NULL && index != p->leftSize) {
if (index < p->leftSize) {
// index 小于左子树个数
// 则要找的元素在左子树中
p = p->leftChild;
}
else if (index > p->leftSize) {
// index 大于左子树个数
// 元素在右子树中
index -= (p->leftSize + 1);
p = p->rightChild;
}
}
// 其实直接 return &p->element 也行
// 但编译器会警告
if (p != NULL) {
return &p->element;
}
else {
return NULL;
}
}
插入
在原来 insert 基础上, 从根节点出发, 逐渐修改 leftSize
binaryTreeNode<pair<const K, E>>* q = root;
while (q != NULL) {
if (thePair.first < q->element.first) {
q->leftSize++; // 加入的元素在左子树里就增加
q = q->leftChild;
}
else if(thePair.first > q->element.first) {
q = q->rightChild;
}
else {
break;
}
}
删除
与插入类似, 顺路更改 leftSize
// while() { ... }
// 重新再找一次, 并顺路使 leftSize - 1
p = root;
pp = NULL;
while (p != NULL && p->element.first != theKey)
{
pp = p;
if (theKey < p->element.first) {
p->leftSize--;
p = p->leftChild;
}
else {
p = p->rightChild;
}
}
更新替换节点的 listSzie
// p 存在两个子树
if (p->leftChild != NULL && p->rightChild != NULL) {
// ...
binaryTreeNode<pair<const K, E>>* q
= new binaryTreeNode<pair<const K, E>>
(s->element, p->leftChild, p->rightChild);
q->leftSize = p->leftSize - 1; // 新节点的左子树个数
// -1 是因为新节点是左子树最大值, 要被删除
// ...
}
根据 index 删除类似, 找匹配节点时有所不同
index--;
while (p != NULL && p->leftSize != index) {
pp = p;
if (index < p->leftSize) {
p->leftSize--;
p = p->leftChild;
}
else if (index > p->leftSize) {
index -= (p->leftSize + 1);
p = p->rightChild;
}
}
// p 存在两个子树
// if (p->leftChild != NULL && p->rightChild != NULL) {
完整代码
#include<iostream>
using namespace std;
// 节点类
template<class T>
struct binaryTreeNode {
T element; // 数据
int leftSize; // 左子树元素个数
// 左右子节点
binaryTreeNode<T>* leftChild, * rightChild;
// 构造函数
binaryTreeNode() {
leftChild = rightChild = NULL;
leftSize = 0;
}
binaryTreeNode(const T& theElement):element(theElement) {
leftChild = rightChild = NULL;
leftSize = 0;
}
binaryTreeNode(const T& theElement,
binaryTreeNode* leftChild,
binaryTreeNode* rightChild):element(theElement)
{
this->leftChild = leftChild;
this->rightChild = rightChild;
leftSize = 0;
}
};
// 二叉搜索树
template<class K, class E>
class binarySearchTree {
// private:
public:
binaryTreeNode<pair<const K, E>>* root;
int treeSize;
binarySearchTree() {
root = NULL;
treeSize = 0;
}
~binarySearchTree() {
postOrderdelete(root);
root = NULL;
treeSize = 0;
}
void ascend() {
// 搜索树(键)升序输出就是中序遍历
inOrderOutput();
}
pair<const K, E>* find(const K&);
pair<const K, E>* find_index(int);
void insert(const pair<const K, E>&);
void erase(const K&);
void erase_index(int);
bool empty() {
return treeSize == 0;
};
int size() {
return treeSize;
};
// 中序遍历输出节点数据
void inOrderOutput() {
inOrder(root);
cout << endl;
}
void inOrder(binaryTreeNode<pair<const K, E>>* t) {
if (t != NULL) {
inOrder(t->leftChild); // 访问左子树
output(t);
inOrder(t->rightChild); // 访问右子树
}
}
// 后续遍历删除节点
void postOrderdelete(binaryTreeNode<pair<const K, E>>* t) {
if (t != NULL) {
postOrderdelete(t->leftChild); // 访问左子树
postOrderdelete(t->rightChild); // 访问右子树
dispose(t);
}
}
private:
static void output(binaryTreeNode<pair<const K, E>>* t) {
cout << "节点数据" << t->element.second << endl;
}
static void dispose(binaryTreeNode<pair<const K, E>>* t) {
delete t;
}
};
template<class K, class E>
pair<const K, E>* binarySearchTree<K, E>::find(const K& theKey) {
binaryTreeNode<pair<const K, E>>* p = this->root;
while (p != NULL) {
if (theKey < p -> element.first) {
// theKey 比 p 的 key 小, 说明在左子树里
p = p->leftChild;
}
else if (theKey > p->element.first) {
p = p->rightChild;
}
else {
return &p->element;
}
}
// 无匹配对象
return NULL;
}
// 根据 index 查找
template<class K, class E>
pair<const K, E>* binarySearchTree<K, E>::find_index(int index) {
if (index > treeSize) {
return NULL; // index 超范围了
}
binaryTreeNode<pair<const K, E>>* p = root;
index--; // 让索引从 0 开始
while (p != NULL && index != p->leftSize) {
if (index < p->leftSize) {
// index 小于左子树个数
// 则要找的元素在左子树中
p = p->leftChild;
}
else if (index > p->leftSize) {
// index 大于左子树个数
// 元素在右子树中
index -= (p->leftSize + 1);
p = p->rightChild;
}
}
if (p != NULL) {
return &p->element;
}
else {
return NULL;
}
}
template<class K, class E>
void binarySearchTree<K, E>::insert(const pair<const K, E>& thePair) {
binaryTreeNode<pair<const K, E>>* p = root,
* pp = NULL;
// 查找符合条件的节点, 找不到返回一个最接近的
while (p != NULL) {
pp = p;
if (thePair.first <= p->element.first) {
p = p->leftChild;
}
else if (thePair.first > p->element.first) {
p = p->rightChild;
}
else {
p->element.second = thePair.second;
return;
}
}
// 不存在, 创建新节点
binaryTreeNode<pair<const K, E>>* newNode
= new binaryTreeNode<pair<const K, E>>(thePair);
if (root != NULL) {
if (thePair.first < pp->element.first) {
// pp 大于 thePair, 将 thePair 插入右子树
pp->leftChild = newNode;
}
else {
pp->rightChild = newNode;
}
}
else {
root = newNode;
}
treeSize++;
// 修改路径上的 leftSize
binaryTreeNode<pair<const K, E>>* q = root;
while (q != NULL) {
if (thePair.first < q->element.first) {
q->leftSize++;
q = q->leftChild;
}
else if(thePair.first > q->element.first) {
q = q->rightChild;
}
else {
break;
}
}
}
template<class K, class E>
void binarySearchTree<K, E>::erase(const K& theKey) {
binaryTreeNode<pair<const K, E>>* p = this->root,
* pp = NULL;
// 寻找匹配的 key
// 如果找到, 则 pp 指向匹配节点 p 的父节点
while (p != NULL && p->element.first != theKey) {
pp = p;
if (theKey < p->element.first) {
p = p->leftChild;
}
else {
p = p->rightChild;
}
}
if (p == NULL) {
return; // 不存在匹配项
}
// 重新再找一次, 并顺路使 leftSize - 1
p = root;
pp = NULL;
while (p != NULL && p->element.first != theKey)
{
pp = p;
if (theKey < p->element.first) {
p->leftSize--;
p = p->leftChild;
}
else {
p = p->rightChild;
}
}
// p 存在两个子树
if (p->leftChild != NULL && p->rightChild != NULL) {
binaryTreeNode<pair<const K, E>>* s = p->leftChild,
* ps = p;
// 遍历至左子树的最大子节点处
// 结束时 s 指向左子树的最大元素
// ps 指向 s 的父节点
while (s->rightChild != NULL) {
ps = s;
s = s->rightChild;
}
binaryTreeNode<pair<const K, E>>* q
= new binaryTreeNode<pair<const K, E>>
(s->element, p->leftChild, p->rightChild);
q->leftSize = p->leftSize - 1; // 新节点的左子树个数
if (pp == NULL) {
// 父节点不存在, 说明删除的是根节点
root = q;
}
else if (p == pp->leftChild) {
// p 是 pp 的左节点
// 则用新节点 q 替换 p
pp->leftChild = q;
}
else {
// p 是 pp 的右节点
pp->rightChild = q;
}
// 如果最大元素的父节点就是要删除的那个节点
if (ps == p) {
pp = q;
}
else {
pp = ps;
}
delete p;
p = s;
}
// 只有一个子树, 或者没有子树
binaryTreeNode<pair<const K, E>>* c;
if (p->leftChild != NULL) {
c = p->leftChild;
}
else {
c = p->rightChild; // 如果 p 没有子树, 此时 c=NULL
}
// 删除 p
if (p == root) {
root = c;
}
else if (p == pp->leftChild) {
pp->leftChild = c;
}
else {
pp->rightChild = c;
}
treeSize--;
delete p;
}
template<class K, class E>
void binarySearchTree<K, E>::erase_index(int index) {
if (index > treeSize) return;
binaryTreeNode<pair<const K, E>>* p = root,
* pp = NULL;
index--;
while (p != NULL && p->leftSize != index) {
pp = p;
if (index < p->leftSize) {
p->leftSize--;
p = p->leftChild;
}
else if (index > p->leftSize) {
index -= (p->leftSize + 1);
p = p->rightChild;
}
}
// p 存在两个子树
if (p != NULL && p->leftChild != NULL && p->rightChild != NULL) {
binaryTreeNode<pair<const K, E>>* s = p->leftChild,
* ps = p;
// 遍历至左子树的最大子节点处
// 结束时 s 指向左子树的最大元素
// ps 指向 s 的父节点
while (s->rightChild != NULL) {
ps = s;
s = s->rightChild;
}
binaryTreeNode<pair<const K, E>>* q
= new binaryTreeNode<pair<const K, E>>
(s->element, p->leftChild, p->rightChild);
q->leftSize = p->leftSize - 1;
if (pp == NULL) {
// 父节点不存在, 说明删除的是根节点
this->root = q;
}
else if (p == pp->leftChild) {
// p 是 pp 的左节点
// 则用新节点 q 替换 p
pp->leftChild = q;
}
else {
// p 是 pp 的右节点
pp->rightChild = q;
}
// 如果最大元素的父节点就是要删除的那个节点
if (ps == p) {
pp = q;
}
else {
pp = ps;
}
delete p;
p = s;
}
// 只有一个子树, 或者没有子树
if (p == NULL) return;
binaryTreeNode<pair<const K, E>>* c;
if (p->leftChild != NULL) {
c = p->leftChild;
}
else {
c = p->rightChild; // 如果 p 没有子树, 此时 c=NULL
}
// 删除 p
if (p == this->root) {
this->root = c;
}
else if (p == pp->leftChild) {
pp->leftChild = c;
}
else {
pp->rightChild = c;
}
this->treeSize--;
delete p;
}
int main() {
binarySearchTree<int, int> b;
pair<int, int> a(20, 20);
b.insert(a);
pair<int, int> c(15, 15);
b.insert(c);
pair<int, int> d(12, 12);
b.insert(d);
pair<int, int> e(18, 18);
b.insert(e);
pair<int, int> f(25, 25);
b.insert(f);
b.erase_index(4);
pair<int, int> g(30, 30);
b.insert(g);
b.ascend();
cout << b.root->leftSize << endl;
for (int i = 1; i <= 5; i++) {
pair<const int, int>* ff = b.find_index(i);
if (ff != NULL) {
cout << ff->first << " " << endl;
}
}
return 0;
}
AVL 树
代码转载至 AVL树详解及C++模板实现
最坏情况下高度为 的树称为“平衡树”, AVL 树是平衡树的一种
空二叉树是 AVL 树
非空二叉树是 AVL 树当且仅当其左右子树高度差不超过 1, 且其左右子树也是 AVL 树
上图中 (a) 和 (b) 是 AVL 树, 但 (c) 不是, (a) 不是 AVL 搜索树, 因为它不是二叉搜索树
高度
一颗高度为 h 的 AVL 树, 其最少的节点数为 , 最坏情况下, 其一颗子树高度为 , 另一颗为 , 则结点数存在关系:
令 , 则
由斐波那契数列(推导过程)解得
当 h 足够大时, 可以忽略
因此
平衡因子
令 为左子树高度, 为右子树高度
可能取值为 -1, 0, 1
失衡调节
左旋
旋转后树高和插入前一致
template<class T>
AvlTreeNode<T>* AvlTree<T>::leftRotation(AvlTreeNode<T>* node) {
// 失衡子树根节点(图中4)的右孩子(图中5)
AvlTreeNode<T>* child = node->right;
// 如果右孩子有左子树
// 将其作为失衡子树根节点的右孩子
node->right = child->left;
// 将 4 作为 5 的左孩子
child->left = node;
// 更新节点高度
int h1 = height(node->right),
h2 = height(node->left);
node->height = h1 > h2 ? h1 + 1 : h2 + 1;
h1 = height(child->right);
h2 = height(child->left);
child->height = h1 > h2 ? h1 + 1 : h2 + 1;
// 返回平衡子树的根节点(即图中 5)
return child;
}
右旋
template<class T>
AvlTreeNode<T>* AvlTree<T>::rightRotation(AvlTreeNode<T>* node) {
// 失衡子树根节点(图中2)的左孩子(图中1)
AvlTreeNode<T>* child = node->left;
// 如果左孩子有右子树
// 将其作为失衡子树根节点的左孩子
node->left = child->right;
// 将 2 作为 1 的右孩子
child->right = node;
int h1 = height(node->right),
h2 = height(node->left);
node->height = h1 > h2 ? h1 + 1 : h2 + 1;
h1 = height(child->right);
h2 = height(child->left);
child->height = h1 > h2 ? h1 + 1 : h2 + 1;
// 返回平衡子树的根节点(即图中 1)
return child;
}
先左旋后右旋
template<class T>
AvlTreeNode<T>* AvlTree<T>::leftRightRotation(AvlTreeNode<T>* node) {
// 先让失衡子树根节点的左子树左旋
node->left = leftRotation(node->left);
// 再让失衡子树右旋
return rightRotation(node);
}
先右旋后左旋
注意此时 bf=-2 但不能左旋
template<class T>
AvlTreeNode<T>* AvlTree<T>::rightLeftRotation(AvlTreeNode<T>* node) {
// 先让失衡子树根节点的右子树右旋
node->right = rightRotation(node->right);
// 再让失衡子树左旋
return leftRotation(node);
}
插入
template<class T>
AvlTreeNode<T>* AvlTree<T>::insert(AvlTreeNode<T>*& node, T key) {
if (node == nullptr) {
node = new AvlTreeNode<T>(key);
}
else if (key > node->key) {
// 插入值较大, 插入到右子树
node->right = insert(node->right, key);
// 插入后失衡
if (height(node->right) - height(node->left) == 2) { // 右子树更高
if (key > node->right->key) {
// 插入值大于右子树根, 进行左旋
node = leftRotation(pnode);
}
else if (key < node->right->key) {
// 否则先右旋, 再左旋
node = rightLeftRotation(pnode);
}
}
}
else if (key < node->key) { // 插入值小于当前节点, 插入到左子树上
node->left = insert(node->right, key);
if (height(node->left) - height(pnode->right) == 2) {
if (key < node->left->key) {
node = rightRotation(node);
}
else if (key > node->left->key) {
node = leftRightRotation(node);
}
}
}
int h1 = height(node->left),
h2 = height(node->right);
node->height = h1 > h2 ? h1 + 1 : h2 + 1;
return node;
}
删除
删除结点平衡后其对应子树高度不变或者减小1 高度减一的一种情况:
高度不变的一种情况:
template<class T>
AvlTreeNode<T>* AvlTree<T>::erase(AvlTreeNode<T>*& node, T key) {
if (node != nullptr) {
if (key == node->key) { // 删除节点等于当前节点
if (node->left != nullptr && node->right != nullptr) { // 左右子树不为空
// 左子树比右子树高
if (height(node->left) > height(node->right)) {
// 用左子树最大节点来代替被删节点
AvlTreeNode<T>* p = maximum(node->left);
node->key = p->key;
// 递归删除最大节点
node->left = erase(node->left, p->key);
}
else {
// 左子树和右子树高度相等, 或者右子树高
// 用右子树最小值代替被删节点
AvlTreeNode<T>* p = minimum(node->right);
node->key = p->key;
node->right = remove(node->right, p->key);
}
}
else {
// 有一颗子树为空, 说明子树只有一个节点了
// 或者左右子树均为空
AvlTreeNode<T>* temp = node;
// 如果左子树不为空
if (node->left != nullptr) {
// 左节点代替被删节点
node = node->left;
}
else if (node->right != nullptr) {
node = node->right;
}
else {
// 没有子树
node = nullptr;
}
delete temp;
return node;
}
}
else if (key > node->key) { // 被删节点在右子树
node->right = remove(node->right, key);
// 右子树删除节点后失衡
if (height(node->left) - height(node->right) == 2) {
if (height(node->left->right) > height(node->left->left)) {
// 左子树的右子树更高, 先左旋后右旋
node = leftRightRotation(node);
}
else {
// 左子树的左子树更高, 右旋
node = rightRotation(node);
}
}
}
else if (key < node->key) { // 被删节点在左子树
node->left = remove(node->left, key);
if (height(node->right) - height(node->left) == 2) {
if (height(node->right->left) > height(node->right->right)) {
node = rightLeftRotation(node);
}
else {
node = leftRotation(node);
}
}
}
}
return node;
}
查找
递归实现
template<class T>
AvlTreeNode<T>* AvlTree<T>::searchByRecurse(AvlTreeNode<T>* node, T key) const {
if (node != nullptr) {
if (key == node->key) {
return node;
}
else if (key > node->key) {
return search_recurse(node->right, key);
}
else {
return search_recurse(node->left, key);
}
}
return nullptr;
}
平均复杂度的计算
完整代码
#include<iostream>
using namespace std;
// avl 树节点
template<class T>
class AvlTreeNode {
public:
AvlTreeNode(T value, AvlTreeNode<T>* l, AvlTreeNode<T>* r)
:key(value), left(l), right(r), height(0) {};
AvlTreeNode(T value) : key(value) {
left = nullptr;
right = nullptr;
height = 0;
};
T key; // 节点的值
int height; // 节点的高度
AvlTreeNode<T>* left;
AvlTreeNode<T>* right;
};
// avl 树
template<class T>
class AvlTree {
public:
AvlTree() { root = nullptr; };
~AvlTree() {
destory(root);
};
void preOrder() {
preOrder(root);
cout << endl;
}
void inOrder() {
inOrder(root);
cout << endl;
}
void postOrder() {
postOrder(root);
cout << endl;
}
void insert(T key) {
insert(root, key);
};
void erase(T key) {
erase(root, key);
};
AvlTreeNode<T>* searchByRecurse(T key) {
return searchByRecurse(root, key);
};
AvlTreeNode<T>* searchByIterator(T key) {
return searchByIterator(root, key);
};
T minimum() {
AvlTreeNode<T>* res = minimum(root);
if (res != nullptr) {
return res->key;
}
};
T maximum() {
AvlTreeNode<T>* res = maximum(root);
if (res != nullptr) {
return res->key;
}
};
// avl 树某节点的高度
int height(AvlTreeNode<T>* node) {
if (node != nullptr) {
return node->height;
}
return 0;
};
// avl 树高度
int height() {
return height(root);
}
private:
AvlTreeNode<T>* root;
void destory(AvlTreeNode<T>*& node);
// 前序遍历
void preOrder(AvlTreeNode<T>* node) const {
if (node != nullptr) {
cout << node->key << " ";
preOrder(node->left);
preOrder(node->right);
}
};
// 中序遍历
void inOrder(AvlTreeNode<T>* node) const {
if (node != nullptr) {
inOrder(node->left);
cout << node->key << " ";
inOrder(node->right);
}
};
// 后序遍历
void postOrder(AvlTreeNode<T>* node) const {
if (node != nullptr) {
postOrder(node->left);
postOrder(node->right);
cout << node->key << " ";
}
};
AvlTreeNode<T>* insert(AvlTreeNode<T>*& node, T key);
AvlTreeNode<T>* erase(AvlTreeNode<T>*& node, T key);
AvlTreeNode<T>* minimum(AvlTreeNode<T>* node) const;
AvlTreeNode<T>* maximum(AvlTreeNode<T>* node) const;
AvlTreeNode<T>* searchByRecurse(AvlTreeNode<T>* node, T key) const;
AvlTreeNode<T>* searchByIterator(AvlTreeNode<T>* node, T key) const;
// 将节点 node 进行旋转
AvlTreeNode<T>* leftRotation(AvlTreeNode<T>* node);
AvlTreeNode<T>* rightRotation(AvlTreeNode<T>* node);
AvlTreeNode<T>* leftRightRotation(AvlTreeNode<T>* node);
AvlTreeNode<T>* rightLeftRotation(AvlTreeNode<T>* node);
};
// 查找元素(递归实现)
template<class T>
AvlTreeNode<T>* AvlTree<T>::searchByRecurse(AvlTreeNode<T>* node, T key) const {
if (node != nullptr) {
if (key == node->key) {
return node;
}
else if (key > node->key) {
return search_recurse(node->right, key);
}
else {
return search_recurse(node->left, key);
}
}
return nullptr;
}
template<class T>
AvlTreeNode<T>* AvlTree<T>::searchByIterator(AvlTreeNode<T>* node, T key) const {
while (node != nullptr) {
if (node->key == key) {
return node;
}
else if (key > node->key) {
node = node->right;
}
else {
node = node->left;
}
}
return nullptr;
}
// 左旋
template<class T>
AvlTreeNode<T>* AvlTree<T>::leftRotation(AvlTreeNode<T>* node) {
AvlTreeNode<T>* child = node->right;
node->right = child->left;
child->left = node;
int h1 = height(node->right),
h2 = height(node->left);
node->height = h1 > h2 ? h1 + 1 : h2 + 1;
h1 = height(child->right);
h2 = height(child->left);
child->height = h1 > h2 ? h1 + 1 : h2 + 1;
return child;
}
// 右旋
template<class T>
AvlTreeNode<T>* AvlTree<T>::rightRotation(AvlTreeNode<T>* node) {
AvlTreeNode<T>* child = node->left;
node->left = child->right;
child->right = node;
int h1 = height(node->right),
h2 = height(node->left);
node->height = h1 > h2 ? h1 + 1 : h2 + 1;
h1 = height(child->right);
h2 = height(child->left);
child->height = h1 > h2 ? h1 + 1 : h2 + 1;
return child;
}
// 先左旋后右旋
template<class T>
AvlTreeNode<T>* AvlTree<T>::leftRightRotation(AvlTreeNode<T>* node) {
node->left = leftRotation(node->left);
return rightRotation(node);
}
// 先右旋后左旋
template<class T>
AvlTreeNode<T>* AvlTree<T>::rightLeftRotation(AvlTreeNode<T>* node) {
node->right = rightRotation(node->right);
return leftRotation(node);
}
template<class T>
void AvlTree<T>::destory(AvlTreeNode<T>*& node) {
if (node != nullptr) {
destory(node->left);
destory(node->right);
delete node;
node = nullptr;
}
}
// 相等的值不会重复插入
template<class T>
AvlTreeNode<T>* AvlTree<T>::insert(AvlTreeNode<T>*& node, T key) {
if (node == nullptr) {
node = new AvlTreeNode<T>(key);
}
else if (key > node->key) {
// 插入值较大, 插入到右子树
// insert 会返回平衡后的子树根节点
node->right = insert(node->right, key);
// 插入后失衡
if (height(node->right) - height(node->left) == 2) { // 右子树更高
if (key > node->right->key) {
// 插入值大于右子树根, 进行左旋
node = leftRotation(node);
}
else if (key < node->right->key) {
// 否则先右旋, 再左旋
node = rightLeftRotation(node);
}
}
}
else if (key < node->key) { // 插入值小于当前节点, 插入到左子树上
node->left = insert(node->right, key);
if (height(node->left) - height(node->right) == 2) {
if (key < node->left->key) {
node = rightRotation(node);
}
else if (key > node->left->key) {
node = leftRightRotation(node);
}
}
}
int h1 = height(node->left),
h2 = height(node->right);
node->height = h1 > h2 ? h1 + 1 : h2 + 1;
return node;
}
template<class T>
AvlTreeNode<T>* AvlTree<T>::erase(AvlTreeNode<T>*& node, T key) {
if (node != nullptr) {
if (key == node->key) { // 删除节点等于当前节点
if (node->left != nullptr && node->right != nullptr) { // 左右子树不为空
// 左子树比右子树高
if (height(node->left) > height(node->right)) {
// 用左子树最大节点来代替被删节点
AvlTreeNode<T>* p = maximum(node->left);
node->key = p->key;
// 递归删除最大节点
node->left = erase(node->left, p->key);
}
else {
// 左子树和右子树高度相等, 或者右子树高
// 用右子树最小值代替被删节点
AvlTreeNode<T>* p = minimum(node->right);
node->key = p->key;
node->right = erase(node->right, p->key);
}
}
else {
// 有一颗子树为空, 说明子树只有一个节点了
// 或者左右子树均为空
AvlTreeNode<T>* temp = node;
// 如果左子树不为空
if (node->left != nullptr) {
// 左节点代替被删节点
node = node->left;
}
else if (node->right != nullptr) {
node = node->right;
}
else {
// 没有子树
node = nullptr;
}
delete temp;
return node;
}
}
else if (key > node->key) { // 被删节点在右子树
node->right = erase(node->right, key);
// 右子树删除节点后失衡
if (height(node->left) - height(node->right) == 2) {
if (height(node->left->right) > height(node->left->left)) {
// 左子树的右子树更高, 先左旋后右旋
node = leftRightRotation(node);
}
else {
// 左子树的左子树更高, 右旋
node = rightRotation(node);
}
}
}
else if (key < node->key) { // 被删节点在左子树
node->left = erase(node->left, key);
if (height(node->right) - height(node->left) == 2) {
if (height(node->right->left) > height(node->right->right)) {
node = rightLeftRotation(node);
}
else {
node = leftRotation(node);
}
}
}
}
return node;
}
// 最小节点
template<class T>
AvlTreeNode<T>* AvlTree<T>::minimum(AvlTreeNode<T>* node) const {
if (node != nullptr) {
while (node->left != nullptr) {
node = node->left;
}
}
return node;
}
// 获取最大节点
template<class T>
AvlTreeNode<T>* AvlTree<T>::maximum(AvlTreeNode<T>* node) const {
if (node != nullptr) {
// 最大节点一定在右子树
while (node->right != nullptr) {
node = node->right;
}
}
return node;
}
int main() {
AvlTree<int> a;
for (int i = 0; i < 10; i++) {
a.insert(i);
}
cout << "树高:" << a.height() << endl;
cout << "中序遍历:" << endl;
a.inOrder();
cout << "删除元素 10" << endl;
a.erase(10);
AvlTreeNode<int>* b = a.searchByIterator(10);
if (b != nullptr) {
cout << b->key << endl;
}
else {
cout << "无此元素" << endl;
}
return 0;
}
另一种非递归写法
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
// avl 树结点
struct AVLNode {
int key;
int height;
AVLNode* left;
AVLNode* right;
AVLNode* parent;
AVLNode(int k, AVLNode* p) : key(k), parent(p), left(nullptr), right(nullptr), height(1) {};
bool isRoot() const {
return parent == nullptr;
}; // 结点是否是根节点
bool isLeft() const {
return !isRoot() && parent->left == this;
}; // 是否是左孩子
bool isRight() const {
return !isRoot() && parent->right == this;
}; // 是否是右孩子
};
// avl 树
class AVLTree {
AVLNode* root;
AVLNode* hot; // 保存被查元素的父节点
int size; // 结点数
AVLNode* leftRotate(AVLNode*); // 左旋
AVLNode* rightRotate(AVLNode*); // 右旋
AVLNode* leftRightRotate(AVLNode*); // 先左旋后右旋
AVLNode* rightLeftRotate(AVLNode*); // 先右旋后左旋
bool isBalence(AVLNode* node) const {
int delta = bf(node);
if (delta > -2 && delta < 2) return true;
else return false;
}; // 结点(非null)是否平衡
int height(AVLNode* node) const {
if (node) return node->height;
else return 0; // node 为外部结点(即null)时
}; // 结点的高度
void balence(AVLNode* node); // 结点重新平衡
void updateHeight(AVLNode* node) {
int h1 = height(node->left),
h2 = height(node->right);
node->height = h1 > h2 ? h1 + 1 : h2 + 1;
}; // 更新结点高度
int bf(AVLNode* node) const {
return height(node->left) - height(node->right);
}; // 返回结点的平衡因子
AVLNode* remove(AVLNode* x);
public:
AVLTree() :root(nullptr), hot(nullptr), size(0) {};
AVLNode* insert(int key); // 插入元素
AVLNode* search(int key); // 搜索元素
void levelOrder() const; // 层次遍历
void inOrder() const; // 中序遍历
bool isComplete() const; // 判断是否是完全二叉树
bool erase(int key); // 删除结点
};
AVLNode* AVLTree::leftRotate(AVLNode* node) {
AVLNode* parent = node->parent,
* child = node->right;
// 孩子的左子树成为结点的右子树
node->right = child->left;
// 结点成为孩子的左子树
child->left = node;
// 修改结点的父亲
node->parent = child;
child->parent = parent;
if (node->right) node->right->parent = node;
updateHeight(node);
updateHeight(child);
return child;
}
AVLNode* AVLTree::rightRotate(AVLNode* node) {
AVLNode* parent = node->parent,
* child = node->left;
// 孩子的右子树成为结点的左子树
node->left = child->right;
// 结点成为孩子的右子树
child->right = node;
// 修改结点的父亲
node->parent = child;
child->parent = parent;
if (node->left) node->left->parent = node;
updateHeight(node);
updateHeight(child);
return child;
}
AVLNode* AVLTree::leftRightRotate(AVLNode* node) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
AVLNode* AVLTree::rightLeftRotate(AVLNode* node) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
void AVLTree::balence(AVLNode* node) {
if (node) { // 仅 node 非空时需要平衡
if (isBalence(node)) {
updateHeight(node); // node 平衡, 则仅需更新高度
balence(node->parent); // 不断向上重新平衡
}
else {
// node 失衡, 进行调整
// 先判断 node 是根, 左孩子还是右孩子
bool left = false, right = false;
if (node->isLeft()) left = true;
else if (node->isRight()) right = true;
AVLNode* n, *p = node->parent;
if (bf(node) == 2) { // 平衡因子为 2
if (height(node->left->left) >= height(node->left->right)) {
// node 左孩子的左子树更高, 进行右旋
n = rightRotate(node);
}
else {
// 先左旋后右旋
n = leftRightRotate(node);
}
}
else {
if (height(node->right->left) <= height(node->right->right)) {
// node 右孩子的右子树更高, 进行左旋
n = leftRotate(node);
}
else {
// 先右旋后左旋
n = rightLeftRotate(node);
}
}
if (left) {
p->left = n;
}
else if (right) {
p->right = n;
}
else {
root = n;
}
balence(n->parent); // 不断向上重新平衡
}
}
}
AVLNode* AVLTree::remove(AVLNode* x) {
AVLNode* succ = nullptr, * w = x;
if (x->left == nullptr) {
// x 左子树为空, 使用右子树替换 x
// 如果此时右子树也为空, 依旧可以替换 x
if (x->isLeft()) {
x->parent->left = succ = x->right;
}
else if (x->isRight()) {
x->parent->right = succ = x->right;
}
else {
root = succ = x->right;
}
}
else if (x->right == nullptr) {
if (x->isLeft()) {
x->parent->left = succ = x->left;
}
else if (x->isRight()) {
x->parent->right = succ = x->left;
}
else {
root = succ = x->left;
}
}
else {
// 双分支结构
w = x->right;
// 遍历至右子树最小值节点
while (w->left != nullptr) {
w = w->left;
}
// w 是右子树最小值
// 交换 w 和 x 的数据
int temp = x->key;
x->key = w->key;
w->key = temp;
AVLNode* u = w->parent;
// 实际被删节点的子树交给实际被删节点的父节点
((u == x) ? u->right : u->left) = succ = w->right;
}
hot = w->parent; // hot 指向实际被删节点的父亲
if (succ) succ->parent = hot; // 将被删节点的代替者过继给 hot
delete w; // 删除最终节点
return succ; // 返回代替者
}
bool AVLTree::erase(int key) {
AVLNode* x = search(key);
if (!x) return false; // 元素不存在, 删除失败
remove(x);
size--;
balence(hot);
return true;
}
AVLNode* AVLTree::insert(int key) {
AVLNode* x = search(key);
if (x) return x; // 元素存在, 直接返回该结点
x = new AVLNode(key, hot);
size++;
if (x->isRoot()) root = x; // x 是根节点则绑定根节点
else {
if (key > hot->key) hot->right = x;
else hot->left = x;
balence(hot); // 父节点重新平衡
}
return x;
}
AVLNode* AVLTree::search(int key) {
AVLNode* p = root;
hot = nullptr;
while (p) {
if (key == p->key) return p; // 匹配, 返回结点
hot = p;
if (key > p->key) p = p->right; // 元素在右子树中
else p = p->left; // 元素在左子树中
}
// 遍历到外部结点, 返回 null
return nullptr;
}
void AVLTree::levelOrder() const {
queue<AVLNode*> q;
AVLNode* t = root;
while (t) {
cout << t->key;
if (t->left) q.push(t->left);
if (t->right) q.push(t->right);
if (q.empty()) break; // 对空则退出循环
cout << " "; // 实现行尾无空格
t = q.front();
q.pop();
}
cout << endl;
}
void AVLTree::inOrder() const {
stack<AVLNode*> s;
AVLNode* t = root;
while (t || !s.empty()) {
while (t) {
s.push(t);
t = t->left;
}
t = s.top();
s.pop();
cout << t->key << " ";
t = t->right;
}
}
bool AVLTree::isComplete() const {
queue<AVLNode*> q;
AVLNode* t = root;
while (t) {
// 不管左右子树是否为空, 都加入队列
q.push(t->left);
q.push(t->right);
t = q.front();
q.pop();
// 遇到空结点就退出
if (!t) break;
}
// 判断队列中剩余元素是否有非空结点
while (!q.empty()) {
t = q.front();
q.pop();
// 如果存在非空元素, 则非完全二叉树
if (t) return false;
}
return true;
}
int main() {
int num;
cin >> num;
int* data = new int[num];
for (int i = 0; i < num; i++) {
cin >> data[i];
}
AVLTree at;
for (int i = 0; i < num; i++) {
at.insert(data[i]);
}
at.levelOrder();
// 是否是完全二叉树
if (at.isComplete()) cout << "Yes";
else cout << "No";
cout << endl;
at.erase(35);
at.erase(37);
at.levelOrder();
delete[] data;
return 0;
}
B树
平衡的多路搜索树
相比 AVL 树好处在于每次读入多个节点, 能够提高 I/O 访问速度(即减少频繁访问外存的次数)
超级节点数取决于磁盘数据块数, 比如需要读取 2^30 bits 数据, AVL 每次访问 2 个节点, 需要 30 次 I/O 操作, 如果采用 256 路(即数据块为 2^8 bits), 仅需 <4 次操作
定义
m 阶 B 树, 即 m 路平衡搜索树, 其叶子节点的深度统一
对于 m 阶 B 树, 其分支不得超过 m , 不得少于 ⌈m/2⌉ (树根可以不少于 2 个分支), 关键码不得超过 m-1 个
一棵高度为 h 的 m 阶 B 树, d=⌈m/2⌉ , 则
查找
template<class T>
BTNode<T>* BTree<T>::search(const T& e) {
BTNode<T>* v = root;
hot = nullptr;
while (v) {
int r = v->search(e);
if (r >= 0 && e == v->key[r]) return v; // 找到元素
// hot 保存 e 的父节点(当 e 在树中)
// 或者 e 所应该在的节点(当 e 不在树中)
// 即 v->child[r] == null, hot 指向叶节点
hot = v;
v = v->child[r + 1];
}
return nullptr;
}
while 查找不会超过树的深度
插入
上溢分裂
插入父节点后父节点同样可能出现上溢
插入时子树引用需要在最右插入一个 null
template<class T>
bool BTree<T>::insert(const T& e) {
BTNode<T>* v = search(e);
if (v) return false; // 节点重复, 插入失败
int r = hot->search(e);
hot->key.insert(hot->key.begin() + (r + 1), e);
// 每插入一个节点, child 就要多一个 null
hot->child.insert(hot->child.begin() + (r + 2), nullptr);
size++;
solveOverFlow(hot); // 上溢分裂
return true;
}
删除
非叶节点删除
旋转
针对叶节点
合并
当兄弟节点不能借出时, 合并也不会导致上溢
合并的时候若是根节点, 则将合并后的节点作为新的根节点
template<class T>
bool BTree<T>::erase(const T& e) {
BTNode<T>* v = search(e); // 查找被删元素
if (!v) return false;
int r = v->search(e); // 这个位置肯定是精确的
if (v->child[0]) {
// v 非叶节点
BTNode<T>* u = v->child[r + 1];
while (u->child[0]) {
u = u->child[0];
}
// 用右子树最大值替换被删节点
v->key[r] = u->key[0];
v = u;
r = 0;
}
v->key.erase(v->key.begin() + r);
// 删哪个都可以, 叶节点的 child 都是 nullptr
v->child.erase(v->child.begin() + r);
size--;
solveUnderFlow(v); // 下溢合并/旋转
return true;
}
完整代码
#include<iostream>
#include<vector>
using namespace std;
// B 树节点
template<class T>
struct BTNode {
BTNode<T>* parent;
vector<T> key; // 关键码
vector<BTNode<T>*> child;
BTNode() { parent = nullptr; child.push_back(nullptr); };
BTNode(T e, BTNode<T>* left = nullptr, BTNode<T>* right = nullptr) {
parent = nullptr;
key.push_back(e);
child.push_back(left);
child.push_back(right);
if (left) left->parent = this;
if (right) right->parent = this;
};
int search(const T& e) const;
};
// 在关键码向量中顺序查找元素
template<class T>
int BTNode<T>::search(const T& e) const {
for (int i = 0; i < key.size(); i++) {
// 匹配就返回其索引
// 不匹配返回最后一个小于 e 的索引
if (e == key[i]) return i;
else if (e < key[i]) return i - 1;
}
// e 比所有关键码都大
// 返回最后一个值的索引
return key.size() - 1;
}
// B 树
template<class T>
class BTree {
int size; // 关键码数
int order; // 阶
BTNode<T>* root; // 根节点
BTNode<T>* hot; // search() 查找最接近 e 的节点
void solveOverFlow(BTNode<T>*); // 插入后上溢分裂
void solveUnderFlow(BTNode<T>*); // 删除后下溢合并
void output(BTNode<T>* node) { // 升序遍历
if (node) {
int i = 0;
for (; i < node->key.size(); i++) {
output(node->child[i]);
cout << node->key[i] << " ";
}
output(node->child[i]);
}
}
void inOrder(BTNode<T>* node) { // 中序遍历
if (node) {
inOrder(node->child[0]);
cout << "[";
int i = 0;
for (i = 0; i < node->key.size() - 1; i++) {
cout << node->key[i] << " ";
}
cout << node->key[i] << "] ";
for (int j = 1; j < node->child.size(); j++) {
inOrder(node->child[j]);
}
}
}
public:
BTree(int o) : order(o), size(0) {
root = new BTNode<T>();
hot = nullptr;
}
BTNode<T>* search(const T& e); // 查找
bool insert(const T& e); // 插入
bool erase(const T& e); // 删除
void output() { output(root); };
void inOrder() { inOrder(root); };
};
template<class T>
void BTree<T>::solveOverFlow(BTNode<T>* node) {
// 发生上溢
static int num = 0;
if (node->child.size() > order) {
cout << "发生上溢: " << ++num << "次 ----> ";
for (int i = 0; i < node->key.size(); i++) {
cout << node->key[i] << " ";
}
cout << endl;
int mid = node->key.size() / 2;
// 分裂出右子树
BTNode<T>* right = new BTNode<T>();
int len = node->key.size() - mid - 1; // 右子树 key 的个数
for (int i = 0; i < len; i++) {
right->key.insert(right->key.begin() + i, node->key[mid + 1]);
node->key.erase(node->key.begin() + (mid + 1)); // 插入右子树的同时删掉这个元素
right->child.insert(right->child.begin() + i, node->child[mid + 1]);
node->child.erase(node->child.begin() + (mid + 1));
}
// child 比 key 多一个(注意这里不是插入, 而是替换, new 的时候已经有一个子节点)
right->child[len] = node->child[mid + 1];
node->child.erase(node->child.begin() + (mid + 1));
// 统一右子树的父节点
if (right->child[0]) {
// right 非叶节点其子节点才有父节点
for (int j = 0; j < right->child.size(); j++) {
right->child[j]->parent = right;
}
}
BTNode<T>* p = node->parent;
if (!p) {
// 如果当前节点是根节点
// 新建一个新节点作为新根节点
root = p = new BTNode<T>();
p->child[0] = node;
node->parent = p;
}
int r = p->search(node->key[mid]);
p->key.insert(p->key.begin() + (r + 1), node->key[mid]);
// 不要忘了删除 mid 元素
node->key.erase(node->key.begin() + mid);
p->child.insert(p->child.begin() + (r + 2), right);
// 关联右子树
right->parent = p;
// 迭代上溢检测父节点
solveOverFlow(p);
}
}
template<class T>
void BTree<T>::solveUnderFlow(BTNode<T>* node) {
static int num = 0;
if ((order + 1) / 2 > node->child.size()) {
cout << "发生下溢: " << ++num << "次 ---> ";
for (int i = 0; i < node->key.size(); i++) {
cout << node->key[i] << " ";
}
cout << endl;
BTNode<T>* p = node->parent;
if (!p) { // 若 node 是根节点
if (!node->key.size() && node->child[0]) {
// 并且节点数为空, 但是其存在非空孩子
// root 指向其非空孩子
root = node->child[0];
root->parent = nullptr;
delete node;
}
return;
}
// node 是 p 的第 r 个孩子
int r = 0;
while (p->child[r] != node) {
r++;
}
// 旋转
if (r > 0) { // node 非第一个孩子
BTNode<T>* ls = p->child[r - 1]; // 先看左兄弟
if ((order + 1) / 2 < ls->child.size()) { // 左兄弟少一个不会下溢
// 向父节点借一个
node->key.insert(node->key.begin(), p->key[r - 1]);
// 兄弟节点最大值给父节点
p->key[r - 1] = ls->key.back();
ls->key.pop_back();
// 兄弟最后一个孩子过继给 node
node->child.insert(node->child.begin(), ls->child.back());
ls->child.pop_back(); // 不要忘了删除左兄弟最后一个孩子
// 如果孩子不为 null, 还要修改其父亲
if (node->child[0]) node->child[0]->parent = node;
return;
}
}
if (r < p->child.size() - 1) {
BTNode<T>* rs = p->child[r + 1]; // 看看右兄弟
if ((order + 1) / 2 < rs->child.size()) {
// 往 node 的最后位置插入父节点值
node->key.push_back(p->key[r]);
// 右兄弟将第一个值给父节点
p->key[r] = rs->key[0];
// 删除右兄弟第一个节点
rs->key.erase(rs->key.begin());
// 将右兄弟的第一个孩子过继给 node
node->child.push_back(rs->child[0]);
rs->child.erase(rs->child.begin()); // 不要忘了把右兄弟第一个孩子删除
if (node->child.back()) node->child.back()->parent = node;
return;
}
}
// 合并
if (r > 0) {
BTNode<T>* ls = p->child[r - 1];
// 左兄弟加入粘合剂
ls->key.push_back(p->key[r - 1]);
// 将作为粘合剂的父节点的关键码从父节点中移除
p->key.erase(p->key.begin() + (r - 1));
// 将 node 从 p.child 中移除
p->child.erase(p->child.begin() + r);
// 因为 child 总是比 key 多一个, 为配合 while 写出来一个
ls->child.push_back(node->child[0]);
node->child.erase(node->child.begin());
if (ls->child.back()) {
ls->child.back()->parent = ls;
}
// 将 node 剩余孩子逐步过继给左兄弟
while (!node->key.empty()) {
ls->key.push_back(node->key[0]);
node->key.erase(node->key.begin());
ls->child.push_back(node->child[0]);
node->child.erase(node->child.begin());
// 如果孩子不为 null, 其父亲改成左兄弟
if (ls->child.back()) {
ls->child.back()->parent = ls;
}
}
delete node;
}
else {
BTNode<T>* rs = p->child[r + 1];
node->key.push_back(p->key[r]);
p->key.erase(p->key.begin() + r);
// 将右兄弟从父节点中删除
p->child.erase(p->child.begin() + (r + 1));
// 将右兄弟的孩子过继给 node
node->child.push_back(rs->child[0]);
rs->child.erase(rs->child.begin());
if (node->child.back()) node->child.back()->parent = node;
while (!rs->key.empty()) {
node->key.push_back(rs->key[0]);
rs->key.erase(rs->key.begin());
node->child.push_back(rs->child[0]);
rs->child.erase(rs->child.begin());
if (node->child.back()) node->child.back()->parent = node;
}
delete rs;
}
// p 删掉一个节点后可能出现下溢
solveUnderFlow(p);
}
}
template<class T>
BTNode<T>* BTree<T>::search(const T& e) {
BTNode<T>* v = root;
hot = nullptr;
while (v) {
int r = v->search(e);
if (r >= 0 && e == v->key[r]) return v; // 找到元素
// hot 保存 e 的父节点(当 e 在树中)
// 或者 e 所应该在的节点(当 e 不在树中)
// 即 v->child[r] == null, hot 指向叶节点
hot = v;
v = v->child[r + 1];
}
return nullptr;
}
template<class T>
bool BTree<T>::insert(const T& e) {
BTNode<T>* v = search(e);
if (v) return false; // 节点重复, 插入失败
int r = hot->search(e);
hot->key.insert(hot->key.begin() + (r + 1), e);
hot->child.insert(hot->child.begin() + (r + 2), nullptr);
size++;
solveOverFlow(hot); // 上溢分裂
return true;
}
template<class T>
bool BTree<T>::erase(const T& e) {
BTNode<T>* v = search(e); // 查找被删元素
if (!v) return false;
int r = v->search(e); // 这个位置肯定是精确的
if (v->child[0]) {
// v 非叶节点
BTNode<T>* u = v->child[r + 1];
while (u->child[0]) {
u = u->child[0];
}
v->key[r] = u->key[0];
v = u;
r = 0;
}
v->key.erase(v->key.begin() + r);
// 删哪个都可以, 叶节点的 child 都是 nullptr
v->child.erase(v->child.begin() + r);
size--;
solveUnderFlow(v); // 下溢合并
return true;
}
int main() {
int data[12] = { 53,36,19,41,51,77,89,64,75,79,84,97 };
BTree<int> bt(3);
for (int i = 0; i < 12; i++) {
bt.insert(data[i]);
}
bt.inOrder();
cout << "\n插入 45\n";
bt.insert(45);
bt.inOrder();
cout << "\n删除 45\n";
bt.erase(45);
bt.inOrder();
cout << "\n删除 41\n";
bt.erase(41);
bt.inOrder();
return 0;
}
红黑树
定义
树根和外部节点均为 黑色 , 红节点的孩子必为黑色, 树根到外部节点路径上黑色节点数目 相等
avl 树要求高度差不超过 1, 要求过于严格, 插入操作可能会频繁调整二叉树, 因此引入红黑树
性质
红黑树的黑高度(从树根到叶节点的黑节点数)称为红黑树的 阶
设阶为 r, 则红黑树的高度
红黑树的节点数
因为树高至少为
r, 也就是全是黑节点, 这时是一个满二叉树
红黑树的高度与节点数
提升变换
一颗红黑树是一个普通的 avl 树, 将所有红节点提升到与其父节点同层, 就变成了一颗 4 阶 B 树
插入
默认插入红色, 因为如果插入黑色, 就需要调整一次红黑树, 而插入红色, 除非出现双红, 就不需要调整
template<class T>
BinNode<T>* RedBlack<T>::insert(const T& e) {
BinNode<T>* x = search(e);
if (x) return x; // 如果节点存在, 返回该节点
// 只会插入到叶子, 因此左右子树均为 nullptr
x = new BinNode<T>(e, hot); // 默认红节点
if (!x->isRoot()) {
// hot 关联子树
// 只有 x 非根节点才需要
if (x->data > hot->data) {
hot->right = x;
}
else {
hot->left = x;
}
}
else {
// x 是根节点, 需要绑定 root
root = x;
}
size++;
solveDoubleRed(x); // 双红修正
return x;
}
双红修正-1
叔节点为黑色(不存在也是黑色)
黑色方块可以是外部节点, 也可以是子树
其他情况类似
由上图可知, x 和 p 同侧时, p 变色, x 不变, 异侧时 x 变色, p 不变, g 总是变色
或者说旋转后孩子都是红, 父节点是黑
这种情况变红(G)的黑高度要减一
// 双红修正-1
// 只有四种情况
BinNode<T>* gg = g->parent, // 祖父节点(可能为 null)
* root_ = nullptr;
// 先判断 gg 是左孩子还是右孩子, 或者是根
bool left = g->isLeftChild();
bool right = g->isRightChild();
if (x->isLeftChild() && p->isLeftChild()) {
// x 和 p 都是左孩子, 进行右旋
p->height++; // 此时 p 会变成黑节点, 黑高度增加
p->color = Color::BLACK;
root_ = rightRotation(g); // 这会返回修正子树的根节点
}
else if (x->isRightChild() && p->isLeftChild()) {
// p 是左孩子, x 是右孩子, 先左旋后右旋
x->height++;
x->color = Color::BLACK;
root_ = leftRightRotation(g);
}
else if (x->isRightChild() && p->isRightChild()) {
// x 和 p 都是右孩子, 进行左旋
p->height++;
p->color = Color::BLACK;
root_ = leftRotation(g);
}
else {
// x 是左孩子, p 是右孩子, 先右旋后左旋
x->height++;
x->color = Color::BLACK;
root_ = rightLeftRotation(g);
}
// g 一定会变红
g->height--;
g->color = Color::RED;
// 重新绑定祖父的孩子
if (left) {
gg->left = root_;
}
else if (right) {
gg->right = root_;
}
else {
// g 是根节点
root = root_;
}
root_->parent = gg;
双红修正-2
插入节点存在叔节点, 且为红色
这种情况比较简单, 仅需 x 的祖先, 叔父的颜色 取反 即可(祖先为根就不能取反变红)
这种变红(G)的情况不需要更新黑节点高度
// 双红修正-2
p->color = Color::BLACK;
p->height++;
u->color = Color::BLACK;
u->height++;
if (!g->isRoot()) g->color = Color::RED; // g 若非根, 则转红
solveDoubleRed(g);
查找
与普通搜索树查找算法一致
template<class T>
BinNode<T>* RedBlack<T>::search(const T& e) {
BinNode<T>* p = root;
hot = nullptr;
while (p != nullptr) {
if (e == p->data) {
return p;
}
hot = p; // hot 指向 p 的父节点
if (e < p->data) {
p = p->left;
}
else if (e > p->data) {
p = p->right;
}
}
// 无匹配对象
return nullptr;
}
删除
简单删除
即如何在一棵二叉搜索树中删除一个节点, 前面提到过, 但使用的是 左子树 中 最大元素 替换被删元素, 这里使用 右子树 中 最小元素 替换被删元素
单分支结构, 使用其子树代替其父节点
双分支结构, 获取其右子树最小值, 交换两个节点数据, 再作为单分支删除
这里有个细节, 如果右子树最小值不是被删节点的右节点, 那么其右孩子应作为其父节点的左节点, 反之, 应作为被删节点的右节点, 因此:
((u == x) ? u->right : u->left) = succ = w->right;
具体代码
template<class T>
BinNode<T>* RedBlack<T>::remove(BinNode<T>* x) {
BinNode<T>* succ = nullptr;
BinNode<T>* w = x;
if (x->left == nullptr) {
// x 左子树为空, 使用右子树替换 x
// 如果此时右子树也为空, 依旧可以替换 x
if (x->isLeftChild()) {
x->parent->left = succ = x->right;
}
else if (x->isRightChild()) {
x->parent->right = succ = x->right;
}
else {
root = succ = x->right;
}
}
else if (x->right == nullptr) {
if (x->isLeftChild()) {
x->parent->left = succ = x->left;
}
else if (x->isRightChild()) {
x->parent->right = succ = x->left;
}
else {
root = succ = x->left;
}
}
else {
// 双分支结构
w = x->right;
// 遍历至右子树最小值节点
while (w->left != nullptr) {
w = w->left;
}
// w 是右子树最小值
// 交换 w 和 x 的数据
T temp = x->data;
x->data = w->data;
w->data = temp;
BinNode<T>* u = w->parent;
// 实际被删节点的子树交给实际被删节点的父节点
((u == x) ? u->right : u->left) = succ = w->right;
}
hot = w->parent; // hot 指向实际被删节点的父亲
if (succ) succ->parent = hot; // 将被删节点的代替者过继给 hot
delete w; // 删除最终节点
return succ; // 返回代替者
}
我们调用 remove(x) 将一棵红黑树当作普通二叉搜索树进行节点删除, 实际被删除的节点是右子树最小值所在节点(因此能够改变红黑树性质的就是右子树最小值节点的颜色), 这个节点一定是单分支(或无分支)的
注意当某个节点一个子树为空时, 其另一棵子树不能存在黑节点, 因为这不符合红黑树不同路径上黑节点数目相等的规则(也就是说, 另一颗子树除了外部节点, 至多还能存在一个节点, 并且是红的)
情况一
被删节点本身是红节点, 删掉不会影响路径上黑节点个数
情况二
被删节点为黑色, 其存在一个孩子(一定是红的), 使用该子节点顶替黑节点
情况三
当不属于上述两种情况时, 也就是所谓的“双黑”, 删掉节点就会改变路径上黑节点数, 因此需要进行修复
如何判断出现双黑节点呢?
调用
remove后节点p的左右子树黑高度一致, 说明删除的是一个红节点(第一种情况), 高度不一致, 但是替换节点是红色的(第二种情况), 其他情况均属于双黑
// 未出现双黑...
// hot 左右子树高度一致
if (BlackHeightUpdated(hot)) return true;
// 替换节点 r 为红节点
if (!isBlack(r)) {
r->color = Color::BLACK;
r->height++;
return true;
}
双黑修复-1
被删节点兄弟为黑, 至少有一个红孩子
// 双黑修正-1
Color color = p->color; // 备份父节点颜色
bool left = p->isLeftChild();
bool right = p->isRightChild();
if (!isBlack(s->left)) {
// 兄弟左孩子为红
if (s->isLeftChild()) {
// 兄弟为左孩子, 进行右旋
t = rightRotation(p);
}
else {
// 兄弟为右孩子, 先右旋后左旋
t = rightLeftRotation(p);
}
}
else {
// 兄弟右孩子为红
if (s->isLeftChild()) {
// 兄弟为左孩子, 先左旋后右旋
t = leftRightRotation(p);
}
else {
// 兄弟为右孩子, 进行左旋
t = leftRotation(p);
}
}
if (left) {
g->left = t;
}
else if (right) {
g->right = t;
}
else {
// p 原来是根节点, 旋转后还需要把根节点换成新的
root = t;
}
t->parent = g;
// 孩子染黑
t->left->color = Color::BLACK;
updateHeight(t->left);
t->right->color = Color::BLACK;
updateHeight(t->right);
// 恢复颜色
t->color = color;
updateHeight(t);
双黑修复-2
被删节点兄弟为黑, 无红孩子, 但其父节点为红
这时 s 的黑高度减一, p 的黑高度不变, 再互换颜色
双黑修复-3
被删节点兄弟为黑, 无红孩子, 其父节点也为黑
这时候 s 和 p 的黑高度都要减一, 并且迭代修正 p
双黑修复-4
被删节点兄弟为红色, 父节点一定为黑色
旋转后变成双黑修复2
旋转操作仍然能调用插入时的左右旋算法
// 双黑修复-4
// s 一定会存在父节点
s->color = Color::BLACK;
p->color = Color::RED;
bool left = p->isLeftChild();
bool right = p->isRightChild();
if (s->isLeftChild()) {
// 兄弟节点是左孩子, 进行右旋
t = rightRotation(p);
}
else {
// 兄弟节点是右孩子, 进行左旋
t = leftRotation(p);
}
// p 是根节点就不需要关联 g 的孩子
if (left) {
g->left = t;
}
else if (right) {
g->right = t;
} else {
root = t;
}
// 修改旋转后各自的父节点
s->parent = g;
solveDoubleBlack(x);
完整代码
#include<iostream>
#include<vector>
using namespace std;
enum class Color { RED, BLACK }; // 节点颜色
// 节点类
template<class T>
struct BinNode {
T data;
BinNode<T>* parent;
BinNode<T>* left;
BinNode<T>* right;
int height; // 黑高度
Color color;
// 极造函数
BinNode() : parent(nullptr), left(nullptr), right(nullptr), height(0), color(Color::RED) {};
BinNode(T e, BinNode<T>* p = nullptr, BinNode<T>* l = nullptr, BinNode<T>* r = nullptr,
int h = 0, Color c = Color::RED) :data(e), parent(p), left(l), right(r), height(h), color(c) {};
bool isRoot() { return parent == nullptr; }; // 是否是根节点
bool isLeftChild() { // 是否是左孩子
// 首先如果是根节点, 就不是什么左孩子
// 其次不是其父节点的右孩子
return !isRoot() && this == parent->left;
};
bool isRightChild() {
return !isRoot() && this == parent->right;
}
BinNode<T>* uncle() {
// 获取叔节点
if (isRoot()) { return nullptr; } // 根节点不会有叔节点
else if (parent->isLeftChild()) {
// 如果其父节点是其祖先的左孩子
// 返回其祖先的右孩子
return parent->parent->right;
}
else if (parent->isRightChild()) {
return parent->parent->left;
}
else {
// 父节点是根节点, 没有叔节点
return nullptr;
}
}
};
// 红黑树
template <class T>
class RedBlack {
public:
BinNode<T>* root;
BinNode<T>* hot;
int size; // 节点数
void solveDoubleRed(BinNode<T>* x); // 双红修正
void solveDoubleBlack(BinNode<T>* x); // 双黑修正
int updateHeight(BinNode<T>* x); // 更新黑节点高度
BinNode<T>* leftRotation(BinNode<T>* node); // 左旋
BinNode<T>* rightRotation(BinNode<T>* node); // 右旋
BinNode<T>* rightLeftRotation(BinNode<T>* node); // 先右旋后左旋
BinNode<T>* leftRightRotation(BinNode<T>* node); // 先左旋后右旋
int height(BinNode<T>* node) { // 某个节点的高度
if (node != nullptr) {
return node->height;
}
return 0;
};
int height() {
return height(root);
}
BinNode<T>* remove(BinNode<T>* x);
bool BlackHeightUpdated(BinNode<T>* x);
void inOrder(BinNode<T>* node) { // 中序遍历
if (node != nullptr) {
inOrder(node->left);
cout << node->data << "("
<< (node->color == Color::BLACK ? "黑" : "红")
<< "," << node->height
<< ") ";
inOrder(node->right);
}
};
void preOrder(BinNode<T>* node) { // 前序遍历
if (node != nullptr) {
cout << node->data << "("
<< (node->color == Color::BLACK ? "B" : "R")
<< ") ";
preOrder(node->left);
preOrder(node->right);
}
}
public:
RedBlack() :size(0) {
hot = root = nullptr;
};
BinNode<T>* insert(const T& e);
bool erase(const T& e);
BinNode<T>* search(const T& e);
// 判断某个节点是否是黑色节点
bool isBlack(const BinNode<T>* x) const {
// 外部节点(nullptr)也是黑色节点
if (x == nullptr || x->color == Color::BLACK) {
return true;
}
else {
return false;
}
};
void inOrder() {
if (root) inOrder(root);
else cout << "Null";
};
void preOrder() {
if (root) preOrder(root);
else cout << "Null";
}
BinNode<T>* Max() const;
BinNode<T>* Min() const;
};
// 查找最大值节点
template<class T>
BinNode<T>* RedBlack<T>::Max() const {
BinNode<T>* p = root, *pp = nullptr;
while (p) {
pp = p;
p = p->right;
}
return pp;
}
// 查找最小值节点
template<class T>
BinNode<T>* RedBlack<T>::Min() const {
BinNode<T>* p = root, *pp = nullptr;
while(p) {
pp = p;
p = p->left;
}
return pp;
}
// 左旋
template<class T>
BinNode<T>* RedBlack<T>::leftRotation(BinNode<T>* node) {
BinNode<T>* child = node->right;
node->right = child->left;
if (node->right) {
node->right->parent = node;
}
child->left = node;
node->parent = child;
return child;
}
// 右旋
template<class T>
BinNode<T>* RedBlack<T>::rightRotation(BinNode<T>* node) {
BinNode<T>* child = node->left;
node->left = child->right;
if (node->left) {
// 节点不为空, 还要重新关联其父节点
node->left->parent = node;
}
child->right = node;
node->parent = child;
return child;
}
// 先左旋后右旋
template<class T>
BinNode<T>* RedBlack<T>::leftRightRotation(BinNode<T>* node) {
node->left = leftRotation(node->left);
return rightRotation(node);
}
// 先右旋后左旋
template<class T>
BinNode<T>* RedBlack<T>::rightLeftRotation(BinNode<T>* node) {
node->right = rightRotation(node->right);
return leftRotation(node);
}
// 双红修正
template<class T>
void RedBlack<T>::solveDoubleRed(BinNode<T>* x) {
if(x->isRoot()) { // 递归至根, 树高增加
root->color = Color::BLACK; // 双红修正到根时(此时根为红), 但根只能为黑
root->height++;
return;
}
BinNode<T>* p = x->parent;
if (isBlack(p)) return; // 若 p 为黑色节点, 说明不是双红了, 可以退出
// p 为红色, 说明 p 不可能是根, g 不可能是空
BinNode<T>* g = p->parent;
BinNode<T>* u = x->uncle(); // 获取 x 的叔节点, 可能为 null
if (isBlack(u)) {
// x 的叔节点是黑色, 考虑“双红修正-1”
// 只有下面四种情况
BinNode<T>* gg = g->parent, // 祖父节点(可能为 null)
* root_ = nullptr;
// 先判断 gg 是左孩子还是右孩子, 或者是根
bool left = g->isLeftChild();
bool right = g->isRightChild();
if (x->isLeftChild() && p->isLeftChild()) {
// x 和 p 都是左孩子, 进行右旋
p->height++; // 此时 p 会变成黑节点, 黑高度增加
p->color = Color::BLACK;
root_ = rightRotation(g); // 这会返回修正子树的根节点
}
else if (x->isRightChild() && p->isLeftChild()) {
// p 是左孩子, x 是右孩子, 先左旋后右旋
x->height++;
x->color = Color::BLACK;
root_ = leftRightRotation(g);
}
else if (x->isRightChild() && p->isRightChild()) {
// x 和 p 都是右孩子, 进行左旋
p->height++;
p->color = Color::BLACK;
root_ = leftRotation(g);
}
else {
// x 是左孩子, p 是右孩子, 先右旋后左旋
x->height++;
x->color = Color::BLACK;
root_ = rightLeftRotation(g);
}
// g 一定会变红
g->height--;
g->color = Color::RED;
if (left) {
gg->left = root_;
}
else if (right) {
gg->right = root_;
}
else {
// g 是根节点
root = root_;
}
root_->parent = gg;
}
else {
// 叔节点是红色, 考虑“双红修正-2”
p->color = Color::BLACK;
p->height++;
u->color = Color::BLACK;
u->height++;
if (!g->isRoot()) g->color = Color::RED; // g 若非根, 则转红
solveDoubleRed(g);
}
}
// 双黑修正
template<class T>
void RedBlack<T>::solveDoubleBlack(BinNode<T>* x) {
BinNode<T>* p = x ? x->parent : hot;
if (!p) return; // 父节点不存在, 不需要修正
// x 可能为空, 不能使用 x.isLeftChild()
BinNode<T>* s = (x == p->left) ? p->right : p->left; // x 的兄弟
BinNode<T>* t = nullptr, /*临时节点*/ *g = p->parent; // 祖父节点
if (isBlack(s)) { // 兄弟为黑色节点
if (!isBlack(s->left) || !isBlack(s->right)) {
// 兄弟的红孩子存在, 进行“双黑修正-1”
Color color = p->color; // 备份父节点颜色
bool left = p->isLeftChild();
bool right = p->isRightChild();
if (!isBlack(s->left)) {
// 兄弟左孩子为红
if (s->isLeftChild()) {
// 兄弟为左孩子, 进行右旋
t = rightRotation(p);
}
else {
// 兄弟为右孩子, 先右旋后左旋
t = rightLeftRotation(p);
}
}
else {
// 兄弟右孩子为红
if (s->isLeftChild()) {
// 兄弟为左孩子, 先左旋后右旋
t = leftRightRotation(p);
}
else {
// 兄弟为右孩子, 进行左旋
t = leftRotation(p);
}
}
if (left) {
g->left = t;
}
else if (right) {
g->right = t;
}
else {
// p 原来是根节点, 旋转后还需要把根节点换成新的
root = t;
}
t->parent = g;
// 孩子染黑
t->left->color = Color::BLACK;
updateHeight(t->left);
t->right->color = Color::BLACK;
updateHeight(t->right);
// 恢复颜色
t->color = color;
updateHeight(t);
}
else {
// 兄弟的红孩子不存在
s->color = Color::RED;
s->height--;
if (!isBlack(p)) {
// 父节点为红色, 进行“双黑修正-2”
p->color = Color::BLACK;
}
else {
// 父节点为黑色, 进行“双黑修正-3”
p->height--;
solveDoubleBlack(p);
}
}
}
else {
// 兄弟为红色节点, 即“双黑修复-4”
// s 一定会存在父节点
s->color = Color::BLACK;
s->height++;
p->color = Color::RED;
p->height--;
bool left = p->isLeftChild();
bool right = p->isRightChild();
if (s->isLeftChild()) {
// 兄弟节点是左孩子, 进行右旋
t = rightRotation(p);
}
else {
// 兄弟节点是右孩子, 进行左旋
t = leftRotation(p);
}
// p 是根节点就不需要关联 g 的孩子
if (left) {
g->left = t;
}
else if (right) {
g->right = t;
} else {
root = t;
}
// 修改旋转后各自的父节点
s->parent = g;
solveDoubleBlack(x);
}
}
// 更新黑节点高度
template<class T>
int RedBlack<T>::updateHeight(BinNode<T>* x) {
int h1 = height(x->left), h2 = height(x->right);
x->height = h1 > h2 ? h1 : h2;
return isBlack(x) ? x->height++ : x->height;
}
// 高度更新条件
template<class T>
bool RedBlack<T>::BlackHeightUpdated(BinNode<T>* x) {
// 左右子树黑高度相等, 且当前节点黑高度等于子树黑高度(当为黑节点时+1)
return height(x->left) == height(x->right) &&
x->height == (isBlack(x) ? height(x->left) + 1 : height(x->left));
}
// 插入
template<class T>
BinNode<T>* RedBlack<T>::insert(const T& e) {
BinNode<T>* x = search(e);
if (x) return x; // 如果节点存在, 返回该节点
// 只会插入到叶子, 因此左右子树均为 nullptr
x = new BinNode<T>(e, hot); // 默认红节点
if (!x->isRoot()) {
// hot 关联子树
// 只有 x 非根节点才需要
if (x->data > hot->data) {
hot->right = x;
}
else {
hot->left = x;
}
}
else {
// x 是根节点, 需要绑定 root
root = x;
}
size++;
solveDoubleRed(x); // 双红修正
return x;
}
// 查询
template<class T>
BinNode<T>* RedBlack<T>::search(const T& e) {
BinNode<T>* p = root;
hot = nullptr;
while (p != nullptr) {
if (e == p->data) {
return p;
}
hot = p; // hot 指向 p 的父节点
if (e < p->data) {
p = p->left;
}
else if (e > p->data) {
p = p->right;
}
}
// 无匹配对象
return nullptr;
}
// 删除
template<class T>
BinNode<T>* RedBlack<T>::remove(BinNode<T>* x) {
BinNode<T>* succ = nullptr;
BinNode<T>* w = x;
if (x->left == nullptr) {
// x 左子树为空, 使用右子树替换 x
// 如果此时右子树也为空, 依旧可以替换 x
if (x->isLeftChild()) {
x->parent->left = succ = x->right;
}
else if (x->isRightChild()) {
x->parent->right = succ = x->right;
}
else {
root = succ = x->right;
}
}
else if (x->right == nullptr) {
if (x->isLeftChild()) {
x->parent->left = succ = x->left;
}
else if (x->isRightChild()) {
x->parent->right = succ = x->left;
}
else {
root = succ = x->left;
}
}
else {
// 双分支结构
w = x->right;
// 遍历至右子树最小值节点
while (w->left != nullptr) {
w = w->left;
}
// w 是右子树最小值
// 交换 w 和 x 的数据
T temp = x->data;
x->data = w->data;
w->data = temp;
BinNode<T>* u = w->parent;
// 实际被删节点的子树交给实际被删节点的父节点
((u == x) ? u->right : u->left) = succ = w->right;
}
hot = w->parent; // hot 指向实际被删节点的父亲
if (succ) succ->parent = hot; // 将被删节点的代替者过继给 hot
delete w; // 删除最终节点
return succ; // 返回代替者
}
template<class T>
bool RedBlack<T>::erase(const T& e) {
BinNode<T>* x = search(e);
if (!x) return false; // 目标不存在
BinNode<T>* r = remove(x);
// 节点都删完了, 啥都不用修复, 直接退出
if (--size <= 0) return true;
// 至少存在一个根节点...
if (!hot) { // 被删节点为根节点
root->color = Color::BLACK;
root->height++;
return true;
}
// 未出现双黑...
if (BlackHeightUpdated(hot)) return true;
// 替换节点为红色
if (!isBlack(r)) {
r->color = Color::BLACK;
r->height++;
return true;
}
solveDoubleBlack(r);
return true;
}
int main() {
int M, d;
// 输入元素个数
cin >> M;
// 获取插入元素
vector<int> data;
for (int i = 0; i < M; i++) {
cin >> d;
data.push_back(d);
}
// 获取删除元素
cin >> M;
vector<int> edata;
for (int i = 0; i < M; i++) {
cin >> d;
edata.push_back(d);
}
// 创建红黑树并插入元素
RedBlack<int> rb;
for (int i = 0; i < data.size(); i++) {
rb.insert(data[i]);
}
// 前序遍历
rb.preOrder();
cout << endl;
// 获取最小值和最大值
BinNode<int>* min = rb.Min();
BinNode<int>* max = rb.Max();
if (min) cout << min->data << " ";
if (max) cout << max->data << endl;
// 删除元素
for (int i = 0; i < edata.size(); i++) {
rb.erase(edata[i]);
}
rb.preOrder();
return 0;
}