高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)

visualgo.net BST AVL

1. 二叉查找树

二叉查找树(Binary Search Tree),又被称为二叉搜索树


高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第1张图片

1. 特点

  1. 任意节点的左子树不空, 则左子树上所有节点的key均小于它的根节点的key
  2. 任意节点的右子树不空, 则右子树上所有节点的key均大于它的根节点的key
  3. 任意节点的左,右子树也分别为二叉查找树
  4. 没有key相等的节点

二叉查找树进行中序遍历,可以得到一个递增的有序序列


高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第2张图片
BST的中序遍历

2. 结构

二叉搜索树通常使用链式存储孩子表示法。

struct Node {
    int key;
    struct Node* left;
    struct Node* right;
}

3. 操作

3.1 插入

  1. 如果二叉查找树为空,则直接插入。
  2. 如果插入节点key小于根结点key,则插入到左子树中;大于根结点key,则插入到右子树中。
  3. 依次类推,直到找到插入位置。

BST默认插入新的节点是叶子节点。

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第3张图片
Node* Insert(Node*& node, int key){
    if(NULL == node) node = new Node(key);
    if (key < node->key) node->left = Insert(node->left, key);
    else if (key > node->key) node->right = Insert(node->right,key);    
    return node;
}

3.2 查找

  1. 查找指定key的节点
    从根结点开始,若二叉树非空,将给定值与根结点的关键字比较,若相等,则查找成功;若不等,则当给定值小于根结点关键字时,在根结点的左子树中查找,否则在根结点的右子树中查找。
    Node* Search(Node* node, int key){
        if(NULL == node) return NULL;
        if (key < node->key) return Search(node->left, key);
        else if (key > node->key) return Search(node->right, key);
        return node;
    }
    
  2. 查找最大/最小key的节点
    // 最大键
    Node* Maximum(Node* node){
        if (NULL == node) return NULL;
        while (NULL != node->right) node = node->right;
        return node;
    }
    
    // 最小键
    Node* Minimum(Node* node){
        if (NULL == node) return NULL;
        while (NULL != node->left) node = node->left;
        return node;
    }
    

3.3 删除

二叉查找树的删除操作是相对复杂一点,它要按 3 种情况来处理:

  1. 被删除结点是叶子结点,直接删除。


    高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第4张图片
  2. 结点只有左子树或只有右子树,则让子树替代;


    高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第5张图片
  3. 结点既有左子树,又有右子树,有两种处理方式
    替代删除,后继代替删除节点,然后删除后继;或者前驱代替删除节点,然后删除前驱。
    合并删除,右子树合并到左子树的最大值的右子树上;或者左子树合并到右子树最小值的左子树上。


    高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第6张图片
    合并删除-增加树高.png
Node* Remove(Node* node, int key){
    if(NULL == node) return NULL;
    if (key < node->key) node->left = Remove(node->left, key);
    else if (key > node->key) node->right = Remove(node->right, key);
    else {
        if(NULL != node->right && NULL != node->left){// 有两个子树
            // 最小值删除
            Node* p = Minimum(node->right);
            node->key = p->key;
            node->right = Remove(node->right,p->key);
        } else {// 叶子节点或者只有一个子树
            Node* res = NULL;
            if(NULL != node->right) res = node->right;
            if(NULL != node->left) res = node->left;
            delete node;
            node = NULL;
            return res;
        }
    }
    return node;
}

优缺点

  1. 优点
No. 操作 时间复杂度
1 插入 O(log n)
2 查找 O(log n)
3 插入 O(log n)
  1. 缺点
    二叉搜索树构造顺序影响操作的时间复杂度。

参考代码

#include 
#include 
using namespace std;

// 节点
struct Node{
    int key;        ///< 键
    Node *left;     ///< 左子节点
    Node *right;    ///< 右子节点
    Node(int key) 
    :key(key),left(NULL),right(NULL){}
};

// 辅助操作
Node* Maximum(Node* node){
    if (NULL == node) return NULL;
    while (NULL != node->right) node = node->right;
    return node;
}
Node* Minimum(Node* node){
    if (NULL == node) return NULL;
    while (NULL != node->left) node = node->left;
    return node;
}

// 核心操作
Node* Insert(Node*& node, int key){
    if(NULL == node) node = new Node(key);
    if (key < node->key) node->left = Insert(node->left, key);
    else if (key > node->key) node->right = Insert(node->right,key);    
    return node;
}

Node* Search(Node* node, int key){
    if(NULL == node) return NULL;
    if (key < node->key) return Search(node->left, key);
    else if (key > node->key) return Search(node->right, key);
    return node;
}
Node* Remove(Node* node, int key){
    if(NULL == node) return NULL;
    if (key < node->key) node->left = Remove(node->left, key);
    else if (key > node->key) node->right = Remove(node->right, key);
    else {
        if(NULL != node->right && NULL != node->left){// 有两个子树
            // 最小值删除
            Node* p = Minimum(node->right);
            node->key = p->key;
            node->right = Remove(node->right,p->key);
        } else {// 叶子节点或者只有一个子树
            Node* res = NULL;
            if(NULL != node->right) res = node->right;
            if(NULL != node->left) res = node->left;
            delete node;
            node = NULL;
            return res;
        }
    }
    return node;
}

/////////////////////////////////////////////////////////////
ostream& operator<<(ostream& os,const Node root) {
    queue q;
    q.push(&root);
    while(!q.empty()){
        const Node* curr = q.front();
        q.pop();
        if (NULL != curr){
            os << curr->key;
            q.push(curr->left);
            q.push(curr->right);
        } else {
            os << '#';
        }
    }
    return os;        
}
void TestInsert(Node*& root){
    Insert(root,1);
    Insert(root,2);
    Insert(root,3);
    Insert(root,4);
    Insert(root,5);
    cout << *root << endl;
}
void TestSearch(Node* root,int key){
    cout <<"Search " << key << ":" << Search(root,key) << endl;
}
void TestRemove(Node*& root,int key){
    root = Remove(root, key);
    cout <<"Remove " << key << ":" ;
    if(NULL != root) cout << *root << endl;
    else cout << "#" << endl;
}
void TestMax(Node* root){
    Node* maxNode = Maximum(root);
    cout << "Max:"<< maxNode->key <<":"<< maxNode <key <<":"<< minNode <

2. AVL树(平衡二叉树)

BST树的缺点不平衡


高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第7张图片
二叉树的平衡.png

平衡二叉树/自平衡二叉查找树(Balanced Binary Tree): 也称为AVL树(名称来自发明人G.M. Adelson-Velsky 和 E.M. Landis的首字母),它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第8张图片

特点

  1. 左右子树深度之差的绝对值不超过1(任意节点的两子树的高度最大差别为1).
  2. 左右子树仍然为平衡二叉树.
  • 平衡因子BF(Balance Factor):左树深度减去右树深度的值。平衡因子BF = 左子树深度-右子树深度。
  • 平衡二叉树每个结点的平衡因子只能是1,0,-1。若其绝对值超过1,则该二叉排序树就是不平衡的。当BF为-1、0、1时,二叉树平衡;反之,不平衡。

树快速查找的关键是高度要低,高度低的关键是平衡。

判断平衡:BF


高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第9张图片
判断平衡二叉树
/* 节点 */
struct Node{
    char key;       // 键值
    Node* right;    // 右节点
    Node* left;     // 左节点
    int height;     // 节点高度
    Node(char key):key(key),right(NULL),left(NULL),height(0){}
    Node(char key,int height):key(key),right(NULL),left(NULL),height(height){}
};

/*
* 平衡因子:左子树树高-右子树树高
*/
int BalanceFactor(const Node* root){
    if(NULL == root) return 0;
    if(NULL == root->left && NULL == root->right) return 0;
    if(NULL == root->left) return -root->right->height;
    if(NULL == root->right) return root->left->height;
    return root->left->height - root->right->height;
}

ostream& operator<<(ostream& os,const Node root) {
    queue q;
    q.push(&root);
    while(!q.empty()){
        const Node* curr = q.front();
        q.pop();
        if (NULL != curr){
            os << curr->key << "[" << BalanceFactor(curr)<<"]";
            q.push(curr->left);
            q.push(curr->right);
        } else {
            os << '#';
        }
    }
    return os;        
}
int main(){
    {
        //     1
        //    /
        //   2
        //  /
        // 3
        Node a('1',3);
        Node b('2',2);
        Node c('3',1);
        a.left = &b;
        b.left = &c;
        cout << a << endl;
    }
    {
        // 1
        //  \
        //   2
        //    \
        //     3
        Node a('1',3);
        Node b('2',2);
        Node c('3',1);
        a.right = &b;
        b.right = &c;
        cout << a << endl;
    }
    {
        //     1
        //    /
        //   2
        //    \
        //     3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        a.left = &b;
        b.right = &c;
        cout << a << endl;
    }
    {
        // 1
        //  \
        //   2
        //  /
        // 3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        a.right = &b;
        b.left = &c;
        cout << a << endl;
    }
}

LeetCode 110. 平衡二叉树

两种旋转(左旋/右旋)、三个节点(新插入节点/不平衡节点/旋转节点)、四种不平衡(LL/RR/RL/LR)。

操作

AVL树的操作基本和二叉查找树一样,这里我们关注的是两个变化很大的操作:插入和删除!

旋转

旋转条件:当最小不平衡子树根节点BF>1,右旋;BF<-1,左旋。


高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第10张图片

旋转步骤:

  1. 获取旋转节点
  2. 旋转节点的子节点替换父节点的旋转节点
  3. 旋转节点父节点做旋转节点子节点
  4. 返回旋转节点
#include 
#include 
using namespace std;

/* 节点 */
struct Node{
    char key;       // 键值
    Node* right;    // 右节点
    Node* left;     // 左节点
    int height;     // 节点高度
    Node(char key):key(key),right(NULL),left(NULL),height(0){}
};

ostream& operator<<(ostream& os,const Node root) {
    queue q;
    q.push(&root);
    while(!q.empty()){
        const Node* curr = q.front();
        q.pop();
        if (NULL != curr){
            os << curr->key;
            q.push(curr->left);
            q.push(curr->right);
        } else {
            os << '#';
        }
    }
    return os;        
}

/*
 * 右旋
 *       Q                  P 
 *      / \                / \ 
 *     P   C  ------->    A   Q 
 *    / \                /   / \ 
 *   A   B              X'  B   C  
 *
 */
Node* RightRotate(Node* root){
    Node* pivot = root->left;  // 获取旋转节点
    root->left = pivot->right; // 旋转节点的子节点替换父节点的旋转节点
    pivot->right = root;       // 旋转节点父节点做旋转节点子节点
    return pivot;              // 返回旋转节点
}

/*
 * 左旋
 *      P                    Q
 *     / \                  / \ 
 *    A   Q     ----->     P   C 
 *       / \              / \   \ 
 *      B   C            A   B   X'  
 */
Node* LeftRotate(Node* root){
    Node* pivot = root->right; // 获取旋转节点
    root->right = pivot->left; // 旋转节点的子节点替换父节点的旋转节点
    pivot->left = root;        // 旋转节点父节点做旋转节点子节点
    return pivot;              // 返回旋转节点 
}

int main(){
    {
        Node a('1');
        Node b('2');
        Node c('3');
        a.left = &b;
        b.left = &c;
        cout << a << endl;
        cout << *RightRotate(&a) << endl;
    }
    {
        Node a('1');
        Node b('2');
        Node c('3');
        a.right = &b;
        b.right = &c;
        cout << a << endl;
        cout << *LeftRotate(&a) << endl;
    }
    {
        Node q('Q');
        Node p('P');
        Node c('C');
        Node a('A');
        Node b('B');
        q.left = &p;
        q.right = &c;
        p.left = &a;
        p.right = &b;
        cout << q << endl;
        Node* r = RightRotate(&q);
        cout << *r << endl;
        Node *l = LeftRotate(r);
        cout << *l << endl;
    }
}

四种不平衡

不平衡的四种情况:
LL:插入一个新节点到不平衡节点的左子树(Left)的左子树(Left),导致不平衡节点的平衡因子由1变为2

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第11张图片

RR:插入一个新节点到不平衡节点的右子树(Right)的右子树(Right),导致不平衡节点的平衡因子由-1变为-2

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第12张图片

LR:插入一个新节点到不平衡节点的左子树(Left)的右子树(Right),导致不平衡节点的平衡因子由1变为2

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第13张图片

RL:插入一个新节点到不平衡节点的右子树(Right)的左子树(Left),导致不平衡节点的平衡因子由-1变为-2

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第14张图片
/*
* 检查是否平衡
*/
void Check(Node* root){
    int nf = BalanceFactor(root);
    if(nf>1){
        int lf = BalanceFactor(root->left);
        if(lf > 0) { // LL
            cout << "LL" << endl;
        } else { // LR
            cout << "LR" << endl;
        }
    }else if(nf < -1){
        int rf = BalanceFactor(root->right);
        if (rf < 0) { // RR
            cout << "RR" << endl;
        } else { // RL
            cout << "RL" << endl;
        }
    }else{// 保持平衡的情况
        cout << "Balance" << endl;
    }
}
int main(){
    {
        //     1
        //    /
        //   2
        //  /
        // 3
        Node a('1',3);
        Node b('2',2);
        Node c('3',1);
        a.left = &b;
        b.left = &c;
        cout << a << endl;
        Check(&a);
    }

    {
        // 1
        //  \
        //   2
        //    \
        //     3
        Node a('1',3);
        Node b('2',2);
        Node c('3',1);
        a.right = &b;
        b.right = &c;
        cout << a << endl;
        Check(&a);
    }

    {
        //     1
        //    /
        //   2
        //    \
        //     3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        a.left = &b;
        b.right = &c;
        cout << a << endl;
        Check(&a);
    }

    {
        // 1
        //  \
        //   2
        //  /
        // 3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        a.right = &b;
        b.left = &c;
        cout << a << endl;
        Check(&a);
    }

    {
        //     1
        //    / \
        //   2   4
        //  / \
        // 3   5
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        cout << a << endl;
        Check(&a);
    }

    {
        //   1
        //  / \
        // 4   2
        //    / \
        //   5   3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 1);
        a.right = &b;
        a.left = &d;
        b.right = &c;
        b.left = &e;
        cout << a << endl;
        Check(&a);
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //  /
        // 6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 2);
        Node d('4', 1);
        Node e('5', 1);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        c.left = &f;
        cout << a << endl;
        Check(&a);
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //    \
        //     6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 2);
        Node d('4', 1);
        Node e('5', 1);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        c.right = &f;
        cout << a << endl;
        Check(&a);
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //      /
        //     6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 2);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        e.left = &f;
        cout << a << endl;
        Check(&a);
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //        \
        //         6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 2);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        e.right = &f;
        cout << a << endl;
        Check(&a);
    }

    {
        //   1
        //  / \
        // 4   2
        //    / \
        //   5   3
        //  /
        // 6
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 1);
        Node f('6', 1);
        a.right = &b;
        a.left = &d;
        b.right = &c;
        b.left = &e;
        e.left = &f;
        cout << a << endl;
        Check(&a);
    }
}

不平衡处理方法

  • 单向右旋平衡处理LL
  • 单向左旋平衡处理RR
  • 双向旋转(先左后右)平衡处理LR
  • 双向旋转(先右后左)平衡处理RL
高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第15张图片
image.png
/*
* 平衡
*/
Node* Balance(Node* root){
    Node *res = root;
    int nf = BalanceFactor(root);
    if(nf>1){
        int lf = BalanceFactor(root->left);
        if(lf > 0) { // LL
            cout << "LL" << endl;
            res = RightRotate(root);
        } else { // LR
            cout << "LR" << endl;
            root->left = LeftRotate(root->left);
            res = RightRotate(root);
        }
    }else if(nf <-1){
        int rf = BalanceFactor(root->right);
        if (rf < 0) { // RR
            cout << "RR" << endl;
            res = LeftRotate(root);
        } else { // RL
            cout << "RL" << endl;
            root->right = RightRotate(root->right);
            res = LeftRotate(root);
        }
    }else{
        cout << "Balance" << endl;
        // 保持平衡的情况
    }
    return res;
}
int main(){
    {
        //     1
        //    /
        //   2
        //  /
        // 3
        Node a('1',3);
        Node b('2',2);
        Node c('3',1);
        a.left = &b;
        b.left = &c;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        // 1
        //  \
        //   2
        //    \
        //     3
        Node a('1',3);
        Node b('2',2);
        Node c('3',1);
        a.right = &b;
        b.right = &c;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        //     1
        //    /
        //   2
        //    \
        //     3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        a.left = &b;
        b.right = &c;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        // 1
        //  \
        //   2
        //  /
        // 3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        a.right = &b;
        b.left = &c;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        //     1
        //    / \
        //   2   4
        //  / \
        // 3   5
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        //   1
        //  / \
        // 4   2
        //    / \
        //   5   3
        Node a('1', 3);
        Node b('2', 2);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 1);
        a.right = &b;
        a.left = &d;
        b.right = &c;
        b.left = &e;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //  /
        // 6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 2);
        Node d('4', 1);
        Node e('5', 1);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        c.left = &f;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //    \
        //     6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 2);
        Node d('4', 1);
        Node e('5', 1);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        c.right = &f;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //      /
        //     6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 2);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        e.left = &f;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }

    {
        //       1
        //      / \
        //     2   4
        //    / \
        //   3   5
        //        \
        //         6
        Node a('1', 4);
        Node b('2', 3);
        Node c('3', 1);
        Node d('4', 1);
        Node e('5', 2);
        Node f('6', 1);
        a.left = &b;
        a.right = &d;
        b.left = &c;
        b.right = &e;
        e.right = &f;
        cout << a << endl;
        Check(&a);
        cout << *Balance(&a) << endl;
        cout << "----------------" << endl;
    }
}

更新树高

/*
* 更新树高
*/
int UpdateHeight(Node* root){
    if(NULL == root) return 0;
    if(NULL == root->left && NULL == root->right) {
        root->height = 1;
    } else if(NULL == root->left) {
        root->height = 1 + UpdateHeight(root->right);
    } else if(NULL == root->right) {
        root->height = 1 + UpdateHeight(root->left);
    } else {
        root->height = 1 + max(UpdateHeight(root->left),UpdateHeight(root->right));
    }
    return root->height;
}

插入

与 BST(二叉搜索树)中类似,先进行一次失败的查找来确定插入的位置,插入节点后根据平衡因子来决定是否需要调整。

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第16张图片
二叉树的平衡1-右旋.png

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第17张图片
二叉树的平衡2-左旋.png

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第18张图片
二叉树的平衡3-左旋.png

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第19张图片
二叉树的平衡4-左旋.png

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第20张图片
二叉树的平衡5-右旋左旋.png

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第21张图片
二叉树的平衡6-右旋左旋.png
/*
* 插入AVL树
*/
bool Insert(Node*& root,char key){
    bool res;
    if (NULL == root){
        root = new Node(key);
        res = true;
    } else if (root->key == key){
        res = false;
    } else if (root->key < key){
        res = Insert(root->right, key);
    } else {
        res = Insert(root->left, key);
    }
    if(res){
        root = Balance(root);
        UpdateHeight(root); // 更新高度
    }
    return res;
}

删除

删除和 BST 类似,将结点与后继交换后再删除。
删除会导致树高以及平衡因子变化,这时需要沿着被删除结点到根的路径来调整这种变化。

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第22张图片
复制删除.png
高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第23张图片
合并删除.png
高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第24张图片
合并删除2.png

优点

查找、插入和删除在平均和最坏情况下都是O(logn)。

缺点

插入和删除旋转比较耗时,适用于插入和删除较少的情况。

参考代码

#include 
#include 
using namespace std;

struct Node{
    int key;        ///< 键
    Node *left;     ///< 左子节点
    Node *right;    ///< 右子节点
    int height;     ///< 节点高度
    Node(int key, int height) 
    :key(key),left(NULL),right(NULL),height(height){}
};

// 辅助操作
Node* Maximum(Node* node){
    if (NULL == node) return NULL;
    while (NULL != node->right) node = node->right;
    return node;
}

Node* Minimum(Node* node){
    if (NULL == node) return NULL;
    while (NULL != node->left) node = node->left;
    return node;
}

// 平衡因子:左子树树高-右子树树高
int BalanceFactor(const Node* root){
    if(NULL == root) return 0;
    if(NULL == root->left && NULL == root->right) return 0;
    if(NULL == root->left) return -root->right->height;
    if(NULL == root->right) return root->left->height;
    return root->left->height - root->right->height;
}

/*
 * 右旋
 *       Q                  P 
 *      / \                / \ 
 *     P   C  ------->    A   Q 
 *    / \                /   / \ 
 *   A   B              X'  B   C  
 *
 */
Node* RightRotate(Node* root){
    Node* pivot = root->left;  // 获取旋转节点
    root->left = pivot->right; // 旋转节点的子节点替换父节点的旋转节点
    pivot->right = root;       // 旋转节点父节点做旋转节点子节点
    return pivot;              // 返回旋转节点
}

/*
 * 左旋
 *      P                    Q
 *     / \                  / \ 
 *    A   Q     ----->     P   C 
 *       / \              / \   \ 
 *      B   C            A   B   X'  
 */
Node* LeftRotate(Node* root){
    Node* pivot = root->right; // 获取旋转节点
    root->right = pivot->left; // 旋转节点的子节点替换父节点的旋转节点
    pivot->left = root;        // 旋转节点父节点做旋转节点子节点
    return pivot;              // 返回旋转节点 
}

// 更新树高
int UpdateHeight(Node* root){
    if(NULL == root) return 0;
    if(NULL == root->left && NULL == root->right) {
        root->height = 1;
    } else if(NULL == root->left) {
        root->height = 1 + UpdateHeight(root->right);
    } else if(NULL == root->right) {
        root->height = 1 + UpdateHeight(root->left);
    } else {
        root->height = 1 + max(UpdateHeight(root->left),UpdateHeight(root->right));
    }
    return root->height;
}

// 平衡
Node* Balance(Node* root){
    Node *res = root;
    int nf = BalanceFactor(root);
    if(nf>1){
        int lf = BalanceFactor(root->left);
        if(lf > 0) { // LL
            cout << "LL" << endl;
            res = RightRotate(root);
        } else { // LR
            cout << "LR" << endl;
            root->left = LeftRotate(root->left);
            res = RightRotate(root);
        }
    }else if(nf <-1){
        int rf = BalanceFactor(root->right);
        if (rf < 0) { // RR
            cout << "RR" << endl;
            res = LeftRotate(root);
        } else { // RL
            cout << "RL" << endl;
            root->right = RightRotate(root->right);
            res = LeftRotate(root);
        }
    }else{
        cout << "Balance" << endl;
        // 保持平衡的情况
        // return res;
    }
    UpdateHeight(res);
    return res;
}

// 三个核心操作
Node* Insert(Node* node, int key){
    if(NULL == node) node = new Node(key,1);
    if (key < node->key) node->left = Insert(node->left, key);
    else if (key > node->key) node->right = Insert(node->right,key);
    node = Balance(node); // 平衡
    return node;
}

Node* Search(Node* node, int key){
    if(NULL == node) return NULL;
    if (key < node->key) return Search(node->left, key);
    else if (key > node->key) return Search(node->right, key);
    return node;
}

Node* Remove(Node* node, int key){
    if(NULL == node) return NULL;
    if (key < node->key) node->left = Remove(node->left, key);
    else if (key > node->key) node->right = Remove(node->right, key);
    else {
        if(NULL != node->right && NULL != node->left){// 有两个子树
            // 最小值删除
            Node* p = Minimum(node->right);
            node->key = p->key;
            node->right = Remove(node->right,p->key);
        } else {// 叶子节点或者只有一个子树
            Node* res = NULL;
            if(NULL != node->right) res = node->right;
            if(NULL != node->left) res = node->left;
            delete node;
            node = NULL;
            return res;
        }
    }
    node = Balance(node); // 平衡
    return node;
}
/////////////////////////////////////////////////////////////
ostream& operator<<(ostream& os,const Node root) {
    queue q;
    q.push(&root);
    while(!q.empty()){
        const Node* curr = q.front();
        q.pop();
        if (NULL != curr){
            os << curr->key << '[' << curr->height <<']';
            q.push(curr->left);
            q.push(curr->right);
        } else {
            os << '#';
        }
    }
    return os;        
}
void TestInsert(Node*& root){
    root = Insert(root,1);
    root = Insert(root,2);
    root = Insert(root,3);
    root = Insert(root,4);
    root = Insert(root,5);
    cout << *root << endl;
}
void TestSearch(Node* root,int key){
    cout <<"Search " << key << ":" << Search(root,key) << endl;
}
void TestRemove(Node*& root,int key){
    root = Remove(root, key);
    cout <<"Remove " << key << ":" ;
    if(NULL != root) cout << *root << endl;
    else cout << "#" << endl;
}
void TestMax(Node* root){
    Node* maxNode = Maximum(root);
    cout << "Max:"<< maxNode->key <<":"<< maxNode <key <<":"<< minNode <

BST与AVL比较

高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树)_第25张图片

你可能感兴趣的:(高级数据结构和算法4:BST(二叉搜索树)、AVL树(平衡二叉树))