介绍
AVL树是根据它的发明者G.M. Adelson-Velsky 和 E.M. Landis命名的。
AVL树是高度平衡的二叉树,它的特点是:AVL树中任何结点的两个子树的高度最大差别为1。
AVL树的查找、插入和删除操作在平均和最坏情况下都是O(logn)。
如果在AVL树中插入或删除结点后,使得高度之差大于1,此时,AVL树的平衡状态就被破坏,它就不是一颗平衡二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。学AVL树,重点的地方也就是它的旋转算法。
————————————————————————————————————————————————————————————————————————————
算法实现
树的定义
树的结点
template<class T>
class AVLTreeNode
{
public:
T key; // 关键字(键值)
int height; // 高度
AVLTreeNode *left; // 左孩子
AVLTreeNode *right; // 右孩子
AVLTreeNode(T value, AVLTreeNode *l, AVLTreeNode *r) :
key(value) ,left(l),right(r) {}
};
树的类
template<class T>
class AVLTree
{
private:
AVLTreeNode<T> *root; // 根结点
public:
// 外部接口
AVLTree();
~AVLTree();
// 获取树的高度
int height();
// 比较两个值的大小
int max(int a, int b);
// 前序遍历
void preOrder();
// 中序遍历
void inOrder();
// 后序遍历
void postOrder();
// (递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* search(T key);
// (非递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* iterativeSearch(T key);
// 查找最小结点:返回最小结点的键值
T minimum();
// 查找最大结点:返回最大结点的键值
T maximum();
// 将结点插入到AVL树中
void insert(T key);
// 删除结点
void remove(T key);
// 销毁AVL树
void destroy();
// 打印AVL树
void print();
private:
// 内部接口
// 获取树的高度
int height(AVLTreeNode<T> *tree);
// 前序遍历
void preOrder(AVLTreeNode<T> *tree) const;
// 中序遍历
void inOrder(AVLTreeNode<T> *tree) const;
// 后序遍历
void postOrder(AVLTreeNode<T> *tree) const;
// (递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* search(AVLTreeNode<T> *x, T key) const;
// (非递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* iterativeSearch(AVLTreeNode<T> *x, T key) const;
// 返回最小结点
AVLTreeNode<T>* minimum(AVLTreeNode<T> *tree);
// 返回最大结点
AVLTreeNode<T>* maximum(AVLTreeNode<T> *tree);
// 将结点插入到AVL树中
AVLTreeNode<T>* insert(AVLTreeNode<T>* &tree, T key);
// 删除结点,并返回被删除的结点
AVLTreeNode<T>* remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z);
// 销毁AVL树
void destroy(AVLTreeNode<T>* &tree);
// 打印AVL树
void print(AVLTreeNode<T> *tree,T key,int direction);
// LL:左左对应的情况(左单旋转)
AVLTreeNode<T>* leftLeftRotation(AVLTreeNode<T> *k2);
// RR:右右对应的情况(右单旋转)
AVLTreeNode<T>* rightRightRotation(AVLTreeNode<T> *k1);
// LR:左右对应的情况(左双旋转)
AVLTreeNode<T>* leftRightRotation(AVLTreeNode<T> *k3);
// RL:右左对应的情况(右双旋转)
AVLTreeNode<T>* rightLeftRotation(AVLTreeNode<T> *k1);
};
树的高度
采用维基百科上的定义:树的高度为最大层次,即空的二叉树的高度是0,非空树的高度等于它的最大层次(根的层次为1,根的子节点为第2层,依次类推)。
template<class T>
int AVLTree<T>::height(AVLTreeNode<T> *tree)
{
if(tree!=NULL)
return tree->height;
return 0;
}
template<class T>
int AVLTree<T>::height()
{
return height(root);
}
旋转
如果在AVL树中进行插入或删除结点后,可能导致AVL树失去平衡。这种失去平衡可以概括为4种姿态:LL(左左)、LR(左右)、RR(右右)、和RL(右左)。
下面给出它们的示意图:
它们各自的定义如下:
1)LL:插入或删除一个结点后,根节点的左子树的左子树还有非空结点,导致根的左子树的高度比根的右子树的高度大2,AVL树因此失去平衡。
例如,在上面LL情况中,由于根节点(8)的左子树(4)的左子树(2)还有非空子节点,而根节点(8)的右子树(12)没有子节点;导致根节点(8)的左子树(4)的高度比根节点(8)的右子树(12)高2。
2)LR:插入或删除一个结点后,根节点的左子树的右子树还有非空结点,导致根的左子树的高度比根的右子树的高度大2,AVL树因此失去平衡。
例如,在上面LR情况中,由于根节点(8)的左子树(4)的右子树(6)还有非空子节点,而根节点(8)的右子树(12)没有子节点;导致根节点(8)的左子树(4)的高度比根节点(8)的右子树(12)高2。
3)RL:插入或删除一个结点后,根节点的右子树的左子树还有非空结点,导致根的右子树的高度比根的左子树的高度大2,AVL树因此失去平衡。
例如,在上面RL情况中,由于根节点(8)的右子树(12)的左子树(10)还有非空子节点,而根节点(8)的左子树(4)没有子节点;导致根节点(8)的右子树(12)的高度比根节点(8)的左子树高2。
4)RR:插入或删除一个结点后,根节点的右子树的右子树还有非空结点,导致根的右子树的高度比根的左子树的高度大2,AVL树因此失去平衡。
例如,在上面RR情况中,由于根节点(8)的右子树(12)的右子树(14)还有非空子节点,而根节点(8)的左子树(4)没有子节点;导致根节点(8)的右子树(12)的高度比根节点(8)的左子树高2。
在AVL树失去平衡之后,可以通过相应的旋转使其恢复平衡,对应的旋转方法如下:
1)LL的旋转
LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡,如下图:
可以理解为:LL旋转是围绕失去平衡的AVL根节点进行的,也就是节点k2;而且由于是LL情况,就用手抓着左孩子(即k1)使劲摇,使得k1变成根节点,k2变成k1的右子树,k1的右子树变成k2的左子树。
旋转代码:
template<class T>
AVLTreeNode<T>* AVLTree<T>::leftLeftRotation(AVLTreeNode<T> *k2)
{
AVLTreeNode<T> *k1;
k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2->height = max(height(k2->left), height(k2->right)) + 1;
k1->height = max(height(k1->left), k2->height) + 1;
return k1;
}
2)RR的旋转
理解了LL之后,RR就相当容易理解了。RR是LL对称的情况,示意图如下:
旋转代码:
template<class T>
AVLTreeNode<T>* AVLTree<T>::rightRightRotation(AVLTreeNode<T> *k1)
{
AVLTreeNode<T> *k2;
k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1->height = max(height(k1->left), height(k1->right)) + 1;
k2->height = max(k1->height, height(k2->right)) + 1;
return k2;
}
3)LR的旋转
LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡,如下图所示:
第一次旋转是围绕k1进行RR旋转,第二次是围绕k3进行LL旋转。
旋转代码:
template <class T>
AVLTreeNode<T>* AVLTree<T>::leftRightRotation(AVLTreeNode<T>* k3)
{
k3->left = rightRightRotation(k3->left);
return leftLeftRotation(k3);
}
4)RL的旋转
RL是与LR对称的情况,示意图如下:
第一次旋转是围绕k3进行的LL旋转,第二次是围绕k1进行的RR旋转。
旋转代码:
template <class T>
AVLTreeNode<T>* AVLTree<T>::rightLeftRotation(AVLTreeNode<T>* k1)
{
k1->right = leftLeftRotation(k1->right);
return rightRightRotation(k1);
}
插入
template<class T>
AVLTreeNode<T>* AVLTree<T>::insert(AVLTreeNode<T>* &tree, T key)
{
if(tree==NULL)
{
// 新建结点
tree = new AVLTreeNode<T>(key, NULL, NULL);
if(tree==NULL)
{
cout<<"ERROR: create avltree node failed!"<<endl;
return NULL;
}
}
else if(key<tree->key)
{
tree->left = insert(tree->left, key);
// 插入结点后,若AVL树失去平衡,则进行相应的调节
if(height(tree->left)-height(tree->right)==2)
{
if(key<tree->left->key)
tree = leftLeftRotation(tree);
else
tree = leftRightRotaion(tree);
}
}
else
{
tree->right = insert(tree->right, key);
// 插入结点后,若AVL树失去平衡,则进行相应的调节
if(height(tree->right)-height(tree->left)==2)
{
if(key>tree->right->key)
tree = rightRightRotation(tree);
else
tree = rightLeftRotaion(tree);
}
}
tree->height = max(height(tree->left), height(tree->right)) + 1;
return tree;
}
template<class T>
void AVLTree<T>::insert(T key)
{
insert(root,key);
}
删除
template<class T>
AVLTreeNode<T>* AVLTree<T>::remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z)
{
// 根为空 或者 没有要删除的结点
if(tree==NULL || z==NULL)
return NULL;
if(z->key<tree->key)
{
tree->left = remove(tree->left, z);
// 删除结点后,若AVL树失去平衡,则进行相应调节
if(height(tree->right)-height(tree->left)==2)
{
AVLTreeNode<T> *r = tree->right;
if(height(r->left)>height(r->right))
tree = rightLeftRotation(tree);
else
tree = rightRightRotation(tree);
}
}
else if(z->key>tree->key)
{
tree->right = remove(tree->right, z);
if(height(tree->left)-height(tree->right)==2)
{
AVLTreeNode<T> *r = tree->left;
if(height(r->left)<height(r->right))
tree = leftRightRotation(tree);
else
tree = leftLeftRotation(tree);
}
}
else // tree是对应要删除的结点
{
// tree的左右孩子都非空
if((tree->left!=NULL)&&(tree->right!=NULL))
{
if(height(tree->left)>height(tree->right))
{
// 如果tree的左子树比右子树高;
// 则(01)找出tree的左子树中的最大节点
// (02)将该最大节点的值赋值给tree。
// (03)删除该最大节点。
// 这类似于用"tree的左子树中最大节点"做"tree"的替身;
// 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。
AVLTreeNode<T> *max = maximum(tree->left);
tree->key = max->key;
tree->left = remove(tree->left, max);
}
else
{
// 如果tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)
// 则(01)找出tree的右子树中的最小节点
// (02)将该最小节点的值赋值给tree。
// (03)删除该最小节点。
// 这类似于用"tree的右子树中最小节点"做"tree"的替身;
// 采用这种方式的好处是:删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。
AVLTreeNode<T> *min = minimum(tree->right);
tree->key = min->key;
tree->right = remove(tree->right, min);
}
}
else
{
AVLTreeNode<T> *tmp = tree;
tree = (tree->left!=NULL) ? tree->left : tree->right;
delete tmp;
}
}
return tree;
}
template<class T>
void AVLTree<T>::remove(T key)
{
AVLTreeNode<T> *z;
if((z=search(root,key))!=NULL)
root = remove(root,z);
}
关于AVL树的前序遍历、中序遍历、后序遍历、最大值、最小值、查找、打印、销毁等接口与二叉查找树基本一样,这些已经介绍过了就不再单独介绍了。
完整实现
头文件:AVLTree.h
#ifndef AVL_TREE
#define AVL_TREE
#include<iomanip>
#include<iostream>
using namespace std;
template<class T>
class AVLTreeNode
{
public:
T key; // 关键字(键值)
int height; // 高度
AVLTreeNode *left; // 左孩子
AVLTreeNode *right; // 右孩子
AVLTreeNode(T value, AVLTreeNode *l, AVLTreeNode *r) :
key(value) ,left(l),right(r) {}
};
template<class T>
class AVLTree
{
private:
AVLTreeNode<T> *root; // 根结点
public:
// 外部接口
AVLTree();
~AVLTree();
// 获取树的高度
int height();
// 比较两个值的大小
int max(int a, int b);
// 前序遍历
void preOrder();
// 中序遍历
void inOrder();
// 后序遍历
void postOrder();
// (递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* search(T key);
// (非递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* iterativeSearch(T key);
// 查找最小结点:返回最小结点的键值
T minimum();
// 查找最大结点:返回最大结点的键值
T maximum();
// 将结点插入到AVL树中
void insert(T key);
// 删除结点
void remove(T key);
// 销毁AVL树
void destroy();
// 打印AVL树
void print();
private:
// 内部接口
// 获取树的高度
int height(AVLTreeNode<T> *tree);
// 前序遍历
void preOrder(AVLTreeNode<T> *tree) const;
// 中序遍历
void inOrder(AVLTreeNode<T> *tree) const;
// 后序遍历
void postOrder(AVLTreeNode<T> *tree) const;
// (递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* search(AVLTreeNode<T> *x, T key) const;
// (非递归实现)查找AVL树中键值为key的结点
AVLTreeNode<T>* iterativeSearch(AVLTreeNode<T> *x, T key) const;
// 返回最小结点
AVLTreeNode<T>* minimum(AVLTreeNode<T> *tree);
// 返回最大结点
AVLTreeNode<T>* maximum(AVLTreeNode<T> *tree);
// 将结点插入到AVL树中
AVLTreeNode<T>* insert(AVLTreeNode<T>* &tree, T key);
// 删除结点,并返回被删除的结点
AVLTreeNode<T>* remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z);
// 销毁AVL树
void destroy(AVLTreeNode<T>* &tree);
// 打印AVL树
void print(AVLTreeNode<T> *tree,T key,int direction);
// LL:左左对应的情况(左单旋转)
AVLTreeNode<T>* leftLeftRotation(AVLTreeNode<T> *k2);
// RR:右右对应的情况(右单旋转)
AVLTreeNode<T>* rightRightRotation(AVLTreeNode<T> *k1);
// LR:左右对应的情况(左双旋转)
AVLTreeNode<T>* leftRightRotation(AVLTreeNode<T> *k3);
// RL:右左对应的情况(右双旋转)
AVLTreeNode<T>* rightLeftRotation(AVLTreeNode<T> *k1);
};
template<class T>
AVLTree<T>::AVLTree(): root(NULL)
{
}
template<class T>
AVLTree<T>::~AVLTree()
{
destroy(root);
}
template<class T>
int AVLTree<T>::height(AVLTreeNode<T> *tree)
{
if(tree!=NULL)
return tree->height;
return 0;
}
template<class T>
int AVLTree<T>::height()
{
return height(root);
}
template<class T>
int AVLTree<T>::max(int a, int b)
{
return a>b ? a : b;
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::leftLeftRotation(AVLTreeNode<T> *k2)
{
AVLTreeNode<T> *k1;
k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2->height = max(height(k2->left), height(k2->right)) + 1;
k1->height = max(height(k1->left), k2->height) + 1;
return k1;
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::rightRightRotation(AVLTreeNode<T> *k1)
{
AVLTreeNode<T> *k2;
k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1->height = max(height(k1->left), height(k1->right)) + 1;
k2->height = max(k1->height, height(k2->right)) + 1;
return k2;
}
template <class T>
AVLTreeNode<T>* AVLTree<T>::leftRightRotation(AVLTreeNode<T>* k3)
{
k3->left = rightRightRotation(k3->left);
return leftLeftRotation(k3);
}
template <class T>
AVLTreeNode<T>* AVLTree<T>::rightLeftRotation(AVLTreeNode<T>* k1)
{
k1->right = leftLeftRotation(k1->right);
return rightRightRotation(k1);
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::insert(AVLTreeNode<T>* &tree, T key)
{
if(tree==NULL)
{
// 新建结点
tree = new AVLTreeNode<T>(key, NULL, NULL);
if(tree==NULL)
{
cout<<"ERROR: create avltree node failed!"<<endl;
return NULL;
}
}
else if(key<tree->key)
{
tree->left = insert(tree->left, key);
// 插入结点后,若AVL树失去平衡,则进行相应的调节
if(height(tree->left)-height(tree->right)==2)
{
if(key<tree->left->key)
tree = leftLeftRotation(tree);
else
tree = leftRightRotation(tree);
}
}
else
{
tree->right = insert(tree->right, key);
// 插入结点后,若AVL树失去平衡,则进行相应的调节
if(height(tree->right)-height(tree->left)==2)
{
if(key>tree->right->key)
tree = rightRightRotation(tree);
else
tree = rightLeftRotation(tree);
}
}
tree->height = max(height(tree->left), height(tree->right)) + 1;
return tree;
}
template<class T>
void AVLTree<T>::insert(T key)
{
insert(root,key);
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z)
{
// 根为空 或者 没有要删除的结点
if(tree==NULL || z==NULL)
return NULL;
if(z->key<tree->key)
{
tree->left = remove(tree->left, z);
// 删除结点后,若AVL树失去平衡,则进行相应调节
if(height(tree->right)-height(tree->left)==2)
{
AVLTreeNode<T> *r = tree->right;
if(height(r->left)>height(r->right))
tree = rightLeftRotation(tree);
else
tree = rightRightRotation(tree);
}
}
else if(z->key>tree->key)
{
tree->right = remove(tree->right, z);
if(height(tree->left)-height(tree->right)==2)
{
AVLTreeNode<T> *r = tree->left;
if(height(r->left)<height(r->right))
tree = leftRightRotation(tree);
else
tree = leftLeftRotation(tree);
}
}
else // tree是对应要删除的结点
{
// tree的左右孩子都非空
if((tree->left!=NULL)&&(tree->right!=NULL))
{
if(height(tree->left)>height(tree->right))
{
// 如果tree的左子树比右子树高;
// 则(01)找出tree的左子树中的最大节点
// (02)将该最大节点的值赋值给tree。
// (03)删除该最大节点。
// 这类似于用"tree的左子树中最大节点"做"tree"的替身;
// 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。
AVLTreeNode<T> *max = maximum(tree->left);
tree->key = max->key;
tree->left = remove(tree->left, max);
}
else
{
// 如果tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)
// 则(01)找出tree的右子树中的最小节点
// (02)将该最小节点的值赋值给tree。
// (03)删除该最小节点。
// 这类似于用"tree的右子树中最小节点"做"tree"的替身;
// 采用这种方式的好处是:删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。
AVLTreeNode<T> *min = minimum(tree->right);
tree->key = min->key;
tree->right = remove(tree->right, min);
}
}
else
{
AVLTreeNode<T> *tmp = tree;
tree = (tree->left!=NULL) ? tree->left : tree->right;
delete tmp;
}
}
return tree;
}
template<class T>
void AVLTree<T>::remove(T key)
{
AVLTreeNode<T> *z;
if((z=search(root,key))!=NULL)
root = remove(root,z);
}
template<class T>
void AVLTree<T>::preOrder(AVLTreeNode<T> *tree) const
{
if(tree!=NULL)
{
cout<<tree->key<<" ";
preOrder(tree->left);
preOrder(tree->right);
}
}
template<class T>
void AVLTree<T>::preOrder()
{
preOrder(root);
}
template<class T>
void AVLTree<T>::inOrder(AVLTreeNode<T> *tree) const
{
if(tree!=NULL)
{
inOrder(tree->left);
cout<<tree->key<<" ";
inOrder(tree->right);
}
}
template<class T>
void AVLTree<T>::inOrder()
{
inOrder(root);
}
template<class T>
void AVLTree<T>::postOrder(AVLTreeNode<T> *tree) const
{
if(tree!=NULL)
{
postOrder(tree->left);
postOrder(tree->right);
cout<<tree->key<<" ";
}
}
template<class T>
void AVLTree<T>::postOrder()
{
postOrder(root);
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::search(AVLTreeNode<T> *x, T key) const
{
if(x==NULL || x->key==key)
return x;
if(key<x->key)
return search(x->left, key);
else
return search(x->right, key);
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::search(T key)
{
return search(root, key);
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::iterativeSearch(AVLTreeNode<T> *x, T key) const
{
while(x!=NULL && x->key!=key)
{
if(key<x->key)
x = x->left;
else
x = x->right;
}
return x;
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::iterativeSearch(T key)
{
return iterativeSearch(root, key);
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::minimum(AVLTreeNode<T> *tree)
{
if(tree==NULL)
return NULL;
while(tree->left!=NULL)
tree = tree->left;
return tree;
}
template<class T>
T AVLTree<T>::minimum()
{
AVLTreeNode<T> *p = minimum(root);
if(p!=NULL)
return p->key;
return (T)NULL;
}
template<class T>
AVLTreeNode<T>* AVLTree<T>::maximum(AVLTreeNode<T> *tree)
{
if(tree==NULL)
return NULL;
while(tree->right!=NULL)
tree = tree->right;
return tree;
}
template<class T>
T AVLTree<T>::maximum()
{
AVLTreeNode<T> *p = maximum(root);
if(p!=NULL)
return p->key;
return (T)NULL;
}
template<class T>
void AVLTree<T>::destroy(AVLTreeNode<T> *&tree)
{
if(tree==NULL)
return ;
if(tree->left!=NULL)
destroy(tree->left);
if(tree->right!=NULL)
destroy(tree->right);
delete tree;
}
template<class T>
void AVLTree<T>::destroy()
{
destroy(root);
}
template<class T>
void AVLTree<T>::print(AVLTreeNode<T> *tree, T key, int direction)
{
if(tree!=NULL)
{
if(direction==0)
cout<<setw(2)<<tree->key<<"is root"<<endl;
else
cout<<setw(2)<<tree->key<<"is"<<setw(2)<<key<<"'s"<<setw(12)<<(direction==1 ? "right child" : "left child")<<endl;
print(tree->left, tree->key, -1);
print(tree->right, tree->key, 1);
}
}
template<class T>
void AVLTree<T>::print()
{
if(root!=NULL)
print(root, root->key, 0);
}
#endif
测试文件:AVLTreeTest.cpp
#include<iostream>
#include "AVLTree.h"
using namespace std;
static int arr[] = {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
int main()
{
int i,len;
AVLTree<int> *tree = new AVLTree<int>();
cout<<"依次添加:";
len = sizeof(arr)/sizeof(arr[0]);
for(i=0;i<len;++i)
{
cout<<arr[i]<<" ";
tree->insert(arr[i]);
}
cout<<"\n前序遍历:";
tree->preOrder();
cout<<"\n中序遍历:";
tree->inOrder();
cout<<"\n后序遍历:";
tree->postOrder();
cout<<"\n高度: "<<tree->height()<<endl;
cout<<"最小值: "<<tree->minimum()<<endl;
cout<<"最大值: "<<tree->maximum()<<endl;
cout<<"树的详细信息: "<<endl;
tree->print();
i = 8;
cout<<"\n删除根节点:"<<i;
tree->remove(i);
cout<<"\n高度: "<<tree->height()<<endl;
cout<<"中序遍历:";
tree->inOrder();
cout<<"\n树的详细信息: "<<endl;
tree->print();
// 销毁二叉树
tree->destroy();
return 0;
}
测试程序示意图:
(1)添加3,2:
(2)添加1:
(3)添加4:
(4)添加5:
(5)... ....
(6)添加完所有数据后,得到的AVL树如下:
(7)删除节点8:
程序运行结果如下:
参考资料:
感谢作者如果天空不死 :AVL树