搜索树

200 阅读42分钟

以下代码若有 bug, 可以看看 gitee/bst
数据比较多时可能出现 bug, 懒得改文章了...

二叉搜索树

定义

每一个元素有一个唯一的关键字, 左子树关键字小于根节点的关键字, 右子树关键字大于根节点的关键字

image.png

有重复值的二叉搜索树

左子树关键字小于等于根, 右子树关键字大于等于根

索引二叉搜索树

每个节点存在一个“索引”, 这个值为左子树的个数(leftSize)

image.png

这样将某个节点作为根节点, 其对应的搜索树按顺序放入顺序表, 其 leftSize 就是其索引

image.png

上图以节点 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;
}

时间复杂度:

O(h)O(h)
插入
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++;
}
删除
  1. 如果要删除的是叶子节点, 将其父节点相关子节点置为 NULL, 并 delete 该节点即可

image.png

  1. 存在一个子树, 若要删除的是根节点, 则其子节点作为新的根节点, 如果不是根节点, 则令其父节点对应的子节点指向要删除的节点的子节点, 然后释放该节点

image.png

// 只有一个子树, 或者没有子树
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;
}
  1. 如果存在两个子树, 则用 s 新建一个节点 q, 其中 s 为左子树中最大元素或右子树中最小元素, 并在树中删除 s

image.png

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;
}

时间复杂度:

O(h)O(h)
完整代码
#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

image.png

比如我要找 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++模板实现

最坏情况下高度为 O(logn)O(logn) 的树称为“平衡树”, AVL 树是平衡树的一种

空二叉树是 AVL 树

非空二叉树是 AVL 树当且仅当其左右子树高度差不超过 1, 且其左右子树也是 AVL 树

image.png

上图中 (a) 和 (b) 是 AVL 树, 但 (c) 不是, (a) 不是 AVL 搜索树, 因为它不是二叉搜索树

高度

一颗高度为 hAVL 树, 其最少的节点数为 NhN_h, 最坏情况下, 其一颗子树高度为 h1h-1, 另一颗为 h2h-2, 则结点数存在关系:

Nh=Nh1+Nh2+1(N0=0,N1=1)N_h = N_{h-1}+N_{h-2}+1(N_0=0,N_1=1)

Fh+2=Nh+1F_{h+2}=N_h+1, 则

Fh=Fh1+Fh2(F0=0,F1=1)F_h=F_{h-1}+F_{h-2}(F_0=0,F_1=1)

由斐波那契数列(推导过程)解得

Fh+2=Nh+1=15[1+52]h+215[152]h+2F_{h+2}=N_h+1=\frac{1}{\sqrt5}\left[\frac{1+\sqrt5}{2}\right]^{h+2}-\frac{1}{\sqrt5}\left[\frac{1-\sqrt5}{2}\right]^{h+2}

h 足够大时, 可以忽略 15[152]h+2-\frac{1}{\sqrt5}\left[\frac{1-\sqrt5}{2}\right]^{h+2}

因此

h=log2[5(Nh+1)]log2(1+52)21.44log2(Nh+1)=O(log2n)h=\frac{log_2[\sqrt5(N_h+1)]}{log_2\left(\frac{1+\sqrt5}{2}\right)}-2 ≈1.44log_2(N_h+1)=O(log_2n)

image.png

平衡因子

h1h_1 为左子树高度, h2h_2 为右子树高度

bf=h1h2bf=h_1-h_2

可能取值为 -1, 0, 1

image.png

失衡调节

左旋

旋转后树高和插入前一致

image.png

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;
}
右旋

image.png

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;
}
先左旋后右旋

image.png

template<class T>
AvlTreeNode<T>* AvlTree<T>::leftRightRotation(AvlTreeNode<T>* node) {
    // 先让失衡子树根节点的左子树左旋
    node->left = leftRotation(node->left);
    // 再让失衡子树右旋
    return rightRotation(node);
}
先右旋后左旋

image.png

注意此时 bf=-2 但不能左旋

image.png

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;
}

删除

image.png

删除结点平衡后其对应子树高度不变或者减小1 高度减一的一种情况:

image.png

高度不变的一种情况:

image.png

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;
}

平均复杂度的计算

image.png

完整代码
#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树

平衡的多路搜索树

image.png

相比 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

image.png

一棵高度为 hm 阶 B 树, d=⌈m/2⌉ , 则

2dh11nmh12d^{h-1}-1 \le n \le m^h-1
logm(n+1)hlogd(n+12)+1log_m(n+1) \le h \le log_d\left(\frac{n+1}{2}\right)+1

查找

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 查找不会超过树的深度

插入

上溢分裂

image.png

插入父节点后父节点同样可能出现上溢

插入时子树引用需要在最右插入一个 null

image.png

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;
}

删除

非叶节点删除

image.png

旋转

针对叶节点

image.png

合并

当兄弟节点不能借出时, 合并也不会导致上溢

image.png

合并的时候若是根节点, 则将合并后的节点作为新的根节点

image.png

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;
}

红黑树

定义

树根和外部节点均为 黑色 , 红节点的孩子必为黑色, 树根到外部节点路径上黑色节点数目 相等

image.png

avl 树要求高度差不超过 1, 要求过于严格, 插入操作可能会频繁调整二叉树, 因此引入红黑树

性质

红黑树的黑高度(从树根到叶节点的黑节点数)称为红黑树的

设阶为 r, 则红黑树的高度

h2rh \le 2r

红黑树的节点数

因为树高至少为 r, 也就是全是黑节点, 这时是一个满二叉树

n2r1n\ge 2^r-1

红黑树的高度与节点数

log2(n+1)h2log2(n+1)log_2(n+1)\le h \le 2log_2(n+1)

提升变换

一颗红黑树是一个普通的 avl 树, 将所有红节点提升到与其父节点同层, 就变成了一颗 4 阶 B 树

image.png

image.png

插入

默认插入红色, 因为如果插入黑色, 就需要调整一次红黑树, 而插入红色, 除非出现双红, 就不需要调整

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

叔节点为黑色(不存在也是黑色)

黑色方块可以是外部节点, 也可以是子树

image.png

其他情况类似

image.png

由上图可知, 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

插入节点存在叔节点, 且为红色

image.png

这种情况比较简单, 仅需 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;
}

删除

简单删除

即如何在一棵二叉搜索树中删除一个节点, 前面提到过, 但使用的是 左子树最大元素 替换被删元素, 这里使用 右子树最小元素 替换被删元素

单分支结构, 使用其子树代替其父节点

image.png

双分支结构, 获取其右子树最小值, 交换两个节点数据, 再作为单分支删除

image.png

这里有个细节, 如果右子树最小值不是被删节点的右节点, 那么其右孩子应作为其父节点的左节点, 反之, 应作为被删节点的右节点, 因此:

((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) 将一棵红黑树当作普通二叉搜索树进行节点删除, 实际被删除的节点是右子树最小值所在节点(因此能够改变红黑树性质的就是右子树最小值节点的颜色), 这个节点一定是单分支(或无分支)的

注意当某个节点一个子树为空时, 其另一棵子树不能存在黑节点, 因为这不符合红黑树不同路径上黑节点数目相等的规则(也就是说, 另一颗子树除了外部节点, 至多还能存在一个节点, 并且是红的)

情况一

被删节点本身是红节点, 删掉不会影响路径上黑节点个数

image.png

情况二

被删节点为黑色, 其存在一个孩子(一定是红的), 使用该子节点顶替黑节点

image.png

情况三

当不属于上述两种情况时, 也就是所谓的“双黑”, 删掉节点就会改变路径上黑节点数, 因此需要进行修复

image.png

如何判断出现双黑节点呢?

调用 remove 后节点 p 的左右子树黑高度一致, 说明删除的是一个红节点(第一种情况), 高度不一致, 但是替换节点是红色的(第二种情况), 其他情况均属于双黑

// 未出现双黑...
// hot 左右子树高度一致
if (BlackHeightUpdated(hot)) return true;
// 替换节点 r 为红节点
if (!isBlack(r)) { 
    r->color = Color::BLACK;
    r->height++;
    return true; 
}
双黑修复-1

被删节点兄弟为黑, 至少有一个红孩子

image.png

// 双黑修正-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

被删节点兄弟为黑, 无红孩子, 但其父节点为红

image.png

这时 s 的黑高度减一, p 的黑高度不变, 再互换颜色

双黑修复-3

被删节点兄弟为黑, 无红孩子, 其父节点也为黑

image.png

这时候 sp 的黑高度都要减一, 并且迭代修正 p

双黑修复-4

被删节点兄弟为红色, 父节点一定为黑色

image.png

旋转后变成双黑修复2

旋转操作仍然能调用插入时的左右旋算法

image.png

// 双黑修复-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;
}

附录

渐进时间复杂度

image.png