AVL tree (Adelson-Velskii-Landis tree)
一颗AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树。加了额外的平衡条件是为了确保整棵树的深度为O(logN)
在高度为h的AVL树,最少节点数S(h)=S(h-1)+S(h-2)+1.
============================================================
由于只有“插入至根节点”路径上的各节点可能改变平衡状态,因此,只要调整其中最深的那个节点,可使得整棵树重新获得平衡。
平衡破坏的条件是:假设该最深节点为X,X的左右两颗子树的高度相差2。
据此,将平衡被破坏的情况分为4种:
- 插入节点位于X的左子节点的左子树——左左
- 插入节点位于X的左子节点的右子树——左右
- 插入节点位于X的右子节点的右子树——右右
- 插入节点位于X的右子节点的左子树——右左
其中,1,3彼此对称,称为外侧插入,可以采用单旋转调整;2,4彼此对称,称为内侧插入,可以采用双旋转完成。
==========================================================================================
单旋中的右旋:可解决左左
TreeNode* right_rotate(TreeNode* y) {
TreeNode* x =y->left;
//第一步:
y->left = x->right;
if (x->right) {
x->right->p = y;
}
//第二步:将新的根节点与原来的父节点接上,没有父指针时,可忽略
x->p = y->p;
if (y->p == nullptr) {
;
}else if (y->p->left == y) {
y->p->left = x;
}
else {
y->p->right = x;
}
//第三步:
x->right = y;
y->p = x;
x->height = max(Height(x->left), Height(x->right)) + 1;
y->height = max(Height(y->left), Height(y->right)) + 1;
return x;
}
右旋可分为3步:
1. 将y的左子树指向x的右子树
2. 因为这里有父指针,新的根节点x要与y原来的父节点接上,如果原来的y不是root的话;
3. 将x的右孩子指向y.
左右情况的解决:双旋中的先对X的左子树左旋,在对X右旋,这里的X认为是值为5的节点。
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
struct TreeNode {
TreeNode* left;
TreeNode* right;
TreeNode* p;
int height;
int val;
TreeNode() {
left = right =p= nullptr;
val = 0;
height = 0;
}
TreeNode(int v) {
left = right = p = nullptr;
val = v;
height = 0;
}
};
static int Height(TreeNode* p) {
if (p == nullptr)
return -1;
else return p->height;
}
//中序遍历
void inorder_walk1(TreeNode* root) {
TreeNode* p = root;
stack<TreeNode*> s;
while (p || !s.empty()) {
while(p) {
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
cout <<p ->val << " ";
s.pop();
p = p->right;
}
}
}
void inorder_walk2(TreeNode* root) {
if (!root) return;
inorder_walk2(root->left);
cout << root->val << " ";
inorder_walk2(root->right);
}
//先序遍历
void preorder_walk1(TreeNode* root) {
TreeNode* p = root;
stack<TreeNode*> s;
while (p || !s.empty()) {
while (p) {
cout << p->val << " ";
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
s.pop();
p = p->right;
}
}
}
void preorder_walk2(TreeNode* root) {
if (!root) return;
cout << root->val << " ";
preorder_walk2(root->left);
preorder_walk2(root->right);
}
//破坏平衡条件,旋转
TreeNode* left_rotate( TreeNode* x) {
TreeNode* y = x->right;
x->right = y->left;
if (y->left) {
y->left->p = x;
}
y->p = x->p;
if (x->p == nullptr) {
;
}
else if (x->p->left == x) {
x->left->p = y;
}
else {
x->right->p = y;
}
y->left = x;
x->p = y;
x->height = max(Height(x->left), Height(x->right)) + 1;
y->height = max(Height(y->left), Height(y->right)) + 1;
return y;
}
TreeNode* right_rotate(TreeNode* y) {
TreeNode* x =y->left;
//第一步:
y->left = x->right;
if (x->right) {
x->right->p = y;
}
//第二步:将新的根节点与原来的父节点接上,没有父指针时,可忽略
x->p = y->p;
if (y->p == nullptr) {
;
}else if (y->p->left == y) {
y->p->left = x;
}
else {
y->p->right = x;
}
//第三步:
x->right = y;
y->p = x;
x->height = max(Height(x->left), Height(x->right)) + 1;
y->height = max(Height(y->left), Height(y->right)) + 1;
return x;
}
TreeNode* double_right_rotate(TreeNode* k3)//左右
{
k3->left=left_rotate(k3->left);
return right_rotate(k3);
}
TreeNode* double_left_rotate(TreeNode* k3)//右左
{
k3->right = right_rotate(k3->right);
return left_rotate(k3);
}
//插入新节点
TreeNode* insert_node(TreeNode* root, int v) {
if (root == nullptr) {
return new TreeNode(v);
}
TreeNode* node = new TreeNode(v);
if (v < root->val) {
root->left = insert_node(root->left, v);
if (Height(root->left) - Height(root->right) == 2) {//插入后破坏了平衡条件
if (v < root->left->val)//左左
root = right_rotate(root);
else
root = double_right_rotate(root);
}
}
else if (v > root->val) {
root->right = insert_node(root->right, v);
if (Height(root->right) - Height(root->left) == 2) {
if (v > root->right->val)
root = left_rotate(root);
else
root = double_left_rotate(root);
}
}
root->height = max(Height(root->left), Height(root->right)) + 1;
return root;
}
int main() {
// int iv[9] = { 22,18,26,14,20,24,12,16 ,15};
int iv[9] = { 5,2,6,1,3,4 };
TreeNode* root = nullptr;
for (int i = 0; i < 6; i++) {
root = insert_node(root, iv[i]);
}
cout << "中序1:";
inorder_walk1(root);
cout << endl;
cout << "中序2:";
inorder_walk2(root);
cout << endl;
cout << "先序1:";
preorder_walk1(root);
cout << endl;
cout << "先序2:";
preorder_walk2(root);
cout << endl;
system("pause");
}
下面是对左右情况例子的输出