AVL 平衡树

  AVL是一种平衡二叉树,它通过对二叉搜索树中的节点进行旋转使得二叉搜索树达到平衡。AVL在所有的平衡二叉搜索树中具有最高的平衡性。

定义

    平衡二叉树或者为空树或者为满足如下性质的二叉搜索树:

  1. 左右子树的高度之差绝对值不超过1
  2. 左右子树仍然为平衡二叉树

    定义平衡因子 BF(x) = x的左子树高度 - x的右子树的高度。平衡二叉树的每个节点的平衡因子只能为-1, 0, 1.

维持平衡思想

    若二叉树当前为平衡状态,此时插入/删除一个新的节点,此时有可能造成二叉树不满足平衡条件,此时需要通过对节点进行旋转来使得二叉树达到平衡状态。从被插入/删除的节点开始向上查找,找到第一个不满足 |BF| <= 1的祖先节点P,此时对P和P的子节点(或P的子节点的子节点)进行旋转(可能分为下面的四种情况)。

旋转

    (1)LL型平衡旋转法 
    由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1增至2而失去平衡。故需进行一次顺时针旋转操作。 即将A的左孩子B向右上旋转代替A作为根结点,A向右下旋转成为B的右子树的根结点。而原来B的右子树则变成A的左子树。 
LL旋转

    (2)RR型平衡旋转法 
    由于在A的右孩子C 的右子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。故需进行一次逆时针旋转操作。即将A的右孩子C向左上旋转代替A作为根结点,A向左下旋转成为C的左子树的根结点。而原来C的左子树则变成A的右子树。 
RR旋转

    (3)LR型平衡旋转法 
    由于在A的左孩子B的右子数上插入结点F,使A的平衡因子由1增至2而失去平衡。故需进行两次旋转操作(先逆时针,后顺时针)。即先将A结点的左孩子B的右子树的根结点D向左上旋转提升到B结点的位置,然后再把该D结点向右上旋转提升到A结点的位置。即先使之成为LL型,再按LL型处理。 
LR旋转 
    如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到A的左子树上,此时成为LL型,再按LL型处理成平衡型。

    (4)RL型平衡旋转法 
    由于在A的右孩子C的左子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。故需进行两次旋转操作(先顺时针,后逆时针),即先将A结点的右孩子C的左子树的根结点D向右上旋转提升到C结点的位置,然后再把该D结点向左上旋转提升到A结点的位置。即先使之成为RR型,再按RR型处理。 
RL旋转 
    如图中所示,即先将圆圈部分先调整为平衡树,然后将其以根结点接到A的左子树上,此时成为RR型,再按RR型处理成平衡型。

实现(c++)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include<iostream>
using namespace std;
#define MAX(a, b) a > b? a:b
struct TreeNode{
    int data;
    TreeNode* child[2];
    int size;
    int height;
    int count;
    TreeNode(int val){
        data = val;
        size = count = height = 1;
        child[0] = child[1] = NULL;
    }
    void Update(){
        size = count;
        height = 1;
        if (child[0]){
            size += child[0]->size;
            height = MAX(height, 1 + child[0]->height);
        }
        if (child[1]){
            size += child[1]->size;
            height = MAX(height, 1 + child[1]->height);
        }
    }
};
 
struct AVL{
    TreeNode* root;
    AVL() :root(NULL){};
 
    int GetHeight(TreeNode* node){
        if (!node)
            return 0;
        return node->height;
    }
    int GetSize(TreeNode* node){
        if (!node)
            return 0;
        return node->size;
    }
 
    //注意这里使用指针的引用
    void Rotate(TreeNode*& node, int dir){
        TreeNode* ch = node->child[dir];
        node->child[dir] = ch->child[!dir];
        ch->child[!dir] = node;
        node->Update();
        node = ch;
    }
    void Maintain(TreeNode*& node){
        if (!node){
            return;
        }
        int bf = GetHeight(node->child[0]) - GetHeight(node->child[1]);
        if (bf >= -1 && bf <= 1){
            return;
        }
        if (bf == 2){
            int bf2 = GetHeight(node->child[0]->child[0]) - GetHeight(node->child[0]->child[1]);
            if (bf2 == 1){ //左左旋转
                Rotate(node, 0);
            }
            else if (bf2 == -1){ //左右旋转
                Rotate(node->child[0], 1);
                Rotate(node, 0);
            }
        }
        else if (bf == -2){
            int bf2 = GetHeight(node->child[1]->child[0]) - GetHeight(node->child[1]->child[1]);
            if (bf2 == 1){ //右左旋转
                Rotate(node, 1);
            }
            else if (bf2 == -1){ //右右旋转
                Rotate(node->child[1], 0);
                Rotate(node, 1);
            }
        }
 
    }
    void Insert(TreeNode*& node, int val){
        if (!node){
            node = new TreeNode(val);
        }
        else if (node->data == val){
            node->count++;
        }
        else{
            int dir = node->data < val;
            Insert(node->child[dir], val);
        }
        //维持树的平衡
        Maintain(node);
        //更新节点
        node->Update();
    }
 
    //注意参数为指针的引用
    void Delete(TreeNode*& node, int val){
        if (!node){
            return;
        }else if (node->data == val){
            if (node->child[0] && node->child[1]){
                int dir = GetHeight(node->child[0]) < GetHeight(node->child[1]);
                //将子树中较高的那棵,旋转
                Rotate(node, dir);
                //递归调用delete,直到叶子节点才进行真正的删除
                Delete(node->child[! dir], val);
            }
            else{
                TreeNode* tmp_node = NULL;
                if (node->child[0]){
                    tmp_node = node->child[0];
                }
                else if (node->child[1]){
                    tmp_node = node->child[1];
                }
                delete node;
                node = tmp_node; //使用引用
            }
        }
        else{
            int dir = node->data < val;
            Delete(node->child[dir], val);
        }
        Maintain(node);  //维持平衡
        node->Update();  //更新节点
    }
    int GetKth(TreeNode* node, int k){
        while (node){
            if (! node->child[0]){
                if (k <= node->count){
                    return node->data;
                }
                else{
                    k -= node->count;
                    node = node->child[1];
                }
            }
            else{
                if (node->child[0]->size < k && node->child[0]->size + node->count >= k){
                    return node->data;
                }
                else if (node->child[0]->size > k){
                    node = node->child[0];
                }
                else{
                    k -= (node->child[0]->size + node->count);
                    node = node->child[1];
                }
            }
        }
        return -1;
    }
};

 参考: 
平衡树 balanced binary tree (AVL tree)   
AVL树 模板

posted @   农民伯伯-Coding  阅读(274)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示