一,基本概念
AVL树是一种结构平衡的BST树,被称为平衡二叉树。
AVL树的具体特点是,每一个节点的左子树和右子树的高度差的绝对值最多为1,且其左子树和右子树也是AVL树。
BST树有时候会退化为一个链表,但是AVL树不会,因为AVL树具有自平衡属性。
AVL的自平衡是基于平衡因子来维持,平衡因子就是BST树中每个节点的左子树和右子树的高度差。因此对于AVL树来说,平衡因子的值应始终为 -1、0 或 +1。
如果平衡因子为1,则左子树比右子树深一级。
如果平衡因子为0,则左右子树处于相同的深度。
如果平衡因子为-1,则左子树比右子树浅一级。
**最小不平衡子树:**距离插入节点最近,且以平衡因子绝对值大于1的节点为根结点的子树。
二,AVL树的基本操作
插入节点和删除节点的操作,请参考前面写过的BST树的基本操作。
此处主要讲AVL树的再平衡问题,因AVL树是否平衡是基于平衡因子来衡量的,而插入节点和删除节点的操作容易打破AVL树原有的平衡,使平衡因子的绝对值大于1。此时的AVL树变成了不平衡的BST树,为了让BST树再次平衡成为AVL树,需要进行一系列的操作来改变树的结构,这个操作被称为旋转。
当整个AVL树失去平衡时,仅需要对最小不平衡子树进行旋转即可。
旋转操作的本质是子节点和根节点位置的互换。
1.左旋
1.发现一个子树的平衡因子为-2,定为最小不平衡子树。
2.找到破坏平衡的节点,即最小不平衡子树的根节点。
3.左旋最小不平衡子树,使破坏平衡的节点成为子树的左子节点。
2.右旋
1.发现一个子树的平衡因子为2,定为最小不平衡子树
2.找到破坏平衡的节点,即最小不平衡子树的根节点。
3.右旋最小不平衡子树,使破坏平衡的节点成为子树的右子节点。
3.左右旋
左旋+右旋的组合
对根节点的左子树执行左旋。
对整个不平衡子树执行右旋。
4.右左旋
右旋+左旋的组合
对根节点的右子树执行右旋。
对整个不平衡子树执行左旋。
三,AVL树的代码实现
案例场景:
原始的AVL树:
插入节点"9",基于BST树的插入操作,生成新的不平衡的BST树。
此时,BST树的最小不平衡子树是:11->8->9(广度优先遍历)。
最小不平衡子树经过左右旋以后达到再平衡,生成新的AVL树。
再平衡以后的AVL树。
代码实现:
Python实现:
python
import sys
#初始化节点
class TreeNode(object):
def __init__(self, key):
self.key = key
self.left = None
self.right = None
self.height = 1
class AVLTree(object):
def insert_node(self, root, key):
#基于BST树的方式插入节点
if not root:
return TreeNode(key)
elif key < root.key:
root.left = self.insert_node(root.left, key)
else:
root.right = self.insert_node(root.right, key)
root.height = 1 + max(self.getHeight(root.left),
self.getHeight(root.right))
#BST树再平衡
balanceFactor = self.getBalance(root)
if balanceFactor > 1:
if key < root.left.key:
return self.rightRotate(root)
else:
root.left = self.leftRotate(root.left)
return self.rightRotate(root)
if balanceFactor < -1:
if key > root.right.key:
return self.leftRotate(root)
else:
root.right = self.rightRotate(root.right)
return self.leftRotate(root)
return root
def leftRotate(self, z):
y = z.right
T2 = y.left
y.left = z
z.right = T2
z.height = 1 + max(self.getHeight(z.left),
self.getHeight(z.right))
y.height = 1 + max(self.getHeight(y.left),
self.getHeight(y.right))
return y
def rightRotate(self, z):
y = z.left
T3 = y.right
y.right = z
z.left = T3
z.height = 1 + max(self.getHeight(z.left),
self.getHeight(z.right))
y.height = 1 + max(self.getHeight(y.left),
self.getHeight(y.right))
return y
def getHeight(self, root):
if not root:
return 0
return root.height
def getBalance(self, root):
if not root:
return 0
return self.getHeight(root.left) - self.getHeight(root.right)
def preOrder(self, root):
if not root:
return
print("{0} ".format(root.key), end="")
self.preOrder(root.left)
self.preOrder(root.right)
def printTree(self, currPtr, indent, last):
if currPtr != None:
sys.stdout.write(indent)
if last:
sys.stdout.write("R----")
indent += " "
else:
sys.stdout.write("L----")
indent += "| "
print(currPtr.key)
self.printTree(currPtr.left, indent, False)
self.printTree(currPtr.right, indent, True)
myTree = AVLTree()
root = None
nums = [33, 13, 53, 11, 21, 61, 8]
for num in nums:
root = myTree.insert_node(root, num)
myTree.printTree(root, "", True)
new_node = 9
root = myTree.insert_node(root, new_node)
print("After Insert: ")
myTree.printTree(root, "", True)
运行结果:
bash
R----33
L----13
| L----11
| | L----8
| R----21
R----53
R----61
After Insert:
R----33
L----13
| L----9
| | L----8
| | R----11
| R----21
R----53
R----61
C++实现:
cpp
#include <iostream>
using namespace std;
//初始化节点
class Node {
public:
int key;
Node* left;
Node* right;
int height;
};
int max(int a, int b);
int height(Node* N) {
if (N == NULL)
return 0;
return N->height;
}
int max(int a, int b) {
return (a > b) ? a : b;
}
Node* newNode(int key) {
Node* node = new Node();
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1;
return (node);
}
Node* rightRotate(Node* y) {
Node* x = y->left;
Node* T2 = x->right;
x->right = y;
y->left = T2;
y->height = max(height(y->left),
height(y->right)) +
1;
x->height = max(height(x->left),
height(x->right)) +
1;
return x;
}
Node* leftRotate(Node* x) {
Node* y = x->right;
Node* T2 = y->left;
y->left = x;
x->right = T2;
x->height = max(height(x->left),
height(x->right)) +
1;
y->height = max(height(y->left),
height(y->right)) +
1;
return y;
}
int getBalanceFactor(Node* N) {
if (N == NULL)
return 0;
return height(N->left) -
height(N->right);
}
Node* insertNode(Node* node, int key) {
//基于BST树的方式插入节点
if (node == NULL)
return (newNode(key));
if (key < node->key)
node->left = insertNode(node->left, key);
else if (key > node->key)
node->right = insertNode(node->right, key);
else
return node;
//BST树再平衡
node->height = 1 + max(height(node->left),
height(node->right));
int balanceFactor = getBalanceFactor(node);
if (balanceFactor > 1) {
if (key < node->left->key) {
return rightRotate(node);
}
else if (key > node->left->key) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
}
if (balanceFactor < -1) {
if (key > node->right->key) {
return leftRotate(node);
}
else if (key < node->right->key) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
}
return node;
}
void printTree(Node* root, string indent, bool last) {
if (root != nullptr) {
cout << indent;
if (last) {
cout << "R----";
indent += " ";
}
else {
cout << "L----";
indent += "| ";
}
cout << root->key << endl;
printTree(root->left, indent, false);
printTree(root->right, indent, true);
}
}
int main() {
Node* root = NULL;
root = insertNode(root, 33);
root = insertNode(root, 13);
root = insertNode(root, 53);
root = insertNode(root, 11);
root = insertNode(root, 21);
root = insertNode(root, 61);
root = insertNode(root, 8);
printTree(root, "", true);
root = insertNode(root, 9);
cout << "After Insert:" << endl;
printTree(root, "", true);
}
运行结果:
bash
R----33
L----13
| L----11
| | L----8
| R----21
R----53
R----61
After Insert:
R----33
L----13
| L----9
| | L----8
| | R----11
| R----21
R----53
R----61