1 先创建节点类,就是一个普通的节点类的创建,用结构体也可以,唯一值的注意的是要有一个表示当前节点高度的成员,因为节点高度是判断平衡二叉树是否平衡的标志。
#include <iostream>
using namespace std;
template<class T>
class TreeNode
{
public:
T val;
TreeNode<T>* lc;
TreeNode<T>* rc;
int height;
public:
TreeNode(T _val=0,TreeNode<T> *_lc=NULL,TreeNode<T>* _rc=NULL,int _height=0):val(_val), lc(_lc),rc(_rc),height(_height)
{
}
~TreeNode()
{}
TreeNode<T>*Getlc()const{
return lc;
}
// void CreateNode(TreeNode)
void Setlc(TreeNode<T>* _lc);
TreeNode<T>* Getrc() const;
void Setrc(TreeNode<T>* _rc);
void SetVal(T _val);
T GetVal() const
{
return val;
}
bool IsLeaf();
static TreeNode<T>*CreateNode();
};
template<class T>
TreeNode<T>* TreeNode<T>::CreateNode()
{
cout<<“请输入当前节点的值:”;
T n;
cin>>n;
if(n<0)
{
return;
}
TreeNode<T> *Node_ptr=new TreeNode<T>(n);
Node_ptr->lc=TreeNode<T>::CreateNode();
Node_ptr->rc=TreeNode<T>::CreateNode();
return Node_ptr;
}
template<class T>
void TreeNode<T>::SetVal(T _val)
{
val=_val;
}
template<class T>
void TreeNode<T>::Setlc(TreeNode<T>* _lc)
{
lc=_lc;
}
template<class T>
void TreeNode<T>::Setrc(TreeNode<T>* _rc)
{
rc=_rc;
}
template<class T>
TreeNode<T>* TreeNode<T>::Getrc() const
{
return rc;
}
接下来是AVL树的创建
1 AVL树的介绍
AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 “An algorithm for the organization of information” 中发表了它。
其实说白了 AVL树还是一棵二叉查找树(如果不理解什么是二叉查找树一定要先弄懂这个),只不过相对于二叉查找树它多了一个自平衡的特性,就是左右子树的高度差不能大于1,如果大于1了,就要通过旋转来是二叉树重新到达平衡。
下面先看我们实现平衡二叉树类的各种功能,然后我们在一边讲解一边逐一实现。
平衡二叉树的类:
class BalancedBinaryTree
{
private:
TreeNode<T>*subroot;
TreeNode<T>* InsertNode(TreeNode<T>* &_root,T _val);//插入节点
TreeNode<T>* RightHand(TreeNode<T>* &_root); //右旋
TreeNode<T>* LeftHand(TreeNode<T>* &_root); //左旋
TreeNode<T>* RightLeftHand(TreeNode<T>* &_root); //右左
TreeNode<T>* LeftRightHand(TreeNode<T>* &_root); //右左
TreeNode<T>* RemoveNode(TreeNode<T>* _root,T _val);//删除值为_val的节点,返回值是删除后的根节点
TreeNode<T>* MinNode(TreeNode<T>* _root) const;//获取树中的最小值,一直返回左子树的值,直到左子树为空
TreeNode<T>* MaxNode(TreeNode<T>* _root) const;//获取树中的最大值
TreeNode<T>* FindNode(TreeNode<T>*_root,T key) const;//查找值为Key的节点
void DestroyNode(TreeNode<T>* &_root); //销毁树
void TravelPreorderNode(TreeNode<T>* _root) const; //前序遍历-》深度优先遍历
inline int getheight(TreeNode<T> *_Node) const //获取当前节点的高度
{
if(NULL==_Node)
{
return 0;
}
return _Node->height;
}
public:
BalancedBinaryTree(TreeNode<T>* _subroot=NULL):subroot(_subroot)
{}
BalancedBinaryTree(BalancedBinaryTree<T> *Tree)
{
subroot=Tree->GetRoot();
}
~BalancedBinaryTree()
{}
TreeNode<T>* GetRoot() const
{
return subroot;
}
void InsertKey(T _val);
void RemoveKey(T _val);
void DestroyTree(); //销毁树
void TravelPreorderTree() const;
TreeNode<T> * FindKey(T _key);
int TreeHeight() const; //获取树的高度
void TravelInfixorder(TreeNode<T>* _root) const; //中序遍历-》深度优先遍历
void ExtentTravel(TreeNode<T>* _root) const; //广度优先遍历
};
通过上面的代码我们可以看到AVL树的成员函数,在这里要说一下,为什么把所有的函数分为private:和public:这两类,是因为这样符合封装性。再说一下写获取树高度的内联函数的原因,因为在插入或者删除后都要根据左右子树高度差来判断当前AVL树有没有失去平衡。写这个函数最重要的原因是对传入的Node进行了是否为NULL的判断是NULL则返回0,如果写程序的时候直接用Node->lc->height来获取左子树的高度,如果左子树为NULL的话就会报段错误,这种错误编译过程是检查不出来的。
平衡二叉树最重要的就是插入和删除函数,而精髓就是对于四中不平衡情况的旋转,我们先来介绍四种情况的旋转。
1 右右:这种情况是当前节点作为右子树的右节点插入造成AVL树不平衡造成的,这种情况的解决办法是以当前根节点进行左旋
判断是否属于右右情况的代码:
if(getheight(_root->rc)-getheight(_root->lc)==2)// 右插后失衡
{
if(_val>_root->rc->val)
{
//右右
}
}
上面代码if后就需要左旋来维护AVL树的平衡性。
左旋是以把根节点(4)的右子节点(5)作为新的根节点,如果右子节点(5)有左子树的话,那么左子树赋给根节点(4)的右节点,根节点(4)赋给右子节点(5)的左子节点。节点操作后,要更新新根节点还有原根节点的高度,旋转后返回旋转后的新的根节点的指针,这个旋转函数要求传入根节点指针的引用。
代码:
TreeNode<T>* BalancedBinaryTree<T>::LeftHand(TreeNode<T> *&_root)
{
TreeNode<T>* _rootrc=_root->rc;
_root->rc=_rootrc->lc;
_rootrc->lc=_root; _rootrc->height=getheight(_rootrc->lc)>getheight(_rootrc->rc)?getheight(_rootrc->lc)+1:getheight(_rootrc->rc)+1;
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
return _rootrc;
}
2 右左:这种情况是当前节点作为右子树的左节点插入造成AVL树不平衡造成的,这种情况的解决办法是以当前根节点的右子节点为根节点进行右旋,然后再以当前根节点进行左旋。
图例解释:先右转又左转
先把右左的节点以失衡根节点(6)的右子节点(8)作为根节点进行右转后就变成了图5的情况,也就是右右,然后再以根节点(6)进行左旋。
代码:
TreeNode<T>* BalancedBinaryTree<T>::RightLeftHand(TreeNode<T> *&_root)
{
_root->lc=LeftHand(_root->lc);
return RightHand(_root);
}
左右和左左的情况和这个相反,大家可以自己画一画,在这我就不说了,直接上代码。
右旋:针对左左
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::RightHand(TreeNode<T> *&_root)
{
TreeNode<T> * _rootlc=_root->lc;
_root->lc=_rootlc->rc;
_rootlc->rc=_root;
_rootlc->height=getheight(_rootlc->lc)>getheight(_rootlc->rc)?getheight(_rootlc->lc)+1:getheight(_rootlc->rc)+1;
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
return _rootlc;//返回的就是作为参数传过来的节点在树中的位置
}
先左旋后右旋:针对左右
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::LeftRightHand(TreeNode<T> *&_root)
{
_root->rc=RightHand(_root->rc);
return LeftHand(_root);
}
4种旋转理解后你已经了解AVL树的精髓了,但还不足以自己写出AVL树的代码,接下来我们逐渐完成AVL树的各个功能的代码。
1 插入节点:
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::InsertNode(TreeNode<T> *&_root,T _val)
{
if(NULL==_root)
{
_root=new TreeNode<T>(_val);
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
}
//判断当前节点应该插入根节点的左子树还是右子树
else if(_val<_root->val)
{
_root->lc=InsertNode(_root->lc,_val);
if(getheight(_root->lc)-getheight(_root->rc)==2)//插入后失衡
{
if(_val<_root->lc->val)
{
_root=RightHand(_root);//左左的旋转
}
else
{
_root=LeftRightHand(_root);//左右的旋转
}
}
}
else
{
_root->rc=InsertNode(_root->rc,_val);
if(getheight(_root->rc)-getheight(_root->lc)==2)// 右插后失衡
{
if(_val<_root->rc->val)
{
_root=RightLeftHand(_root);//右左
}
else
{
_root=LeftHand(_root); //右右
}
}
}
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
return _root;//返回插入的这个值
}
void BalancedBinaryTree<T>::InsertKey(T _val)
{
subroot=InsertNode(subroot,_val);
}
插入节点需要注意:
1 在插入节点时,一定要传入根节点的引用,这样在插入后进行旋转操作时,才不会造成节点丢失的现象。
2 对于左右子节点插入后,要判断当前根节点的二叉树是否失衡,如果失衡则要进行相应的调整。如果当前值插入左子树中那么就进行左左,左右的判断,判断依旧就是看当前值与左子节点的值的比较就可以。右右,右左的情况相信大家可以想明白了吧。
2 删除节点
删除节点过程中需要判断要删除的值与根节点的值的关系,如果不等于根节点的值那么就要进行递归调用,如果当前节点的值就是要删除节点的值,那么就要判断它的子节点数,如果左右子节点都存在那么,就要找高度较高的子树中的最大值或者最小值的节点来替换当前节点,然后在删除那个最小节点,这样就不会破坏AVL树的平衡性。
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::RemoveNode(TreeNode<T> *_root, T _val)
{
if(NULL==_root)
{
return NULL;
}
if(_val<_root->val)
{
_root->lc=RemoveNode(_root->lc,_val);
//删除左子树上的节点相当于在右子树上插入节点
if(getheight(_root->rc)-getheight(_root->lc)==2)//对于子树上的节点被删除后要判断平衡性是否被破坏并进行调整。
{
//相当于在右子树上插入左节点造成的失衡(情况四)
if (getheight(_root->rc->lc)>getheight(_root->rc->rc))
{
//相当与插入的右左
_root=RightLeftHand(_root);
}
else
{
//相当于插入的右右
_root=LeftHand(_root);
}
}
}
else if(_val>_root->val)
{
_root->rc=RemoveNode(_root->rc,_val);
if(getheight(_root->lc)-getheight(_root->rc)==2)
{
//删除右子树的节点相当与在左子树上插入节点,下面就判断是在左子树的右子树插入还是左子树的左子树插入的
if(getheight(_root->lc->lc)>getheight(_root->lc->rc))//左左
{
_root=RightHand(_root);
}
else
{
_root=LeftRightHand(_root);
}
}
}
else
{
//删除过程要判断:
//1 当前节点是不是叶节点
//2 删除之后还要看看是否破坏了平衡性
if(NULL!=_root->lc&&NULL!=_root->rc)
{
//从左右子树中较高的子树中找到对应的最大最小的点来替换,如果是左子树就用最大值,如果是右子树就用最小值,因为这样才不会破坏AVL树的平衡性
if(getheight(_root->lc)>getheight(_root->rc))//左边子树高度大
{
//获取左边节点最大值
TreeNode<T>* _MaxNode=MaxNode(_root->lc);
_root->val=_MaxNode->val;
_root->lc=RemoveNode(_root->lc,_MaxNode->val);
}
else
{//获取右边子树的最小值
TreeNode<T>* _MinNode=MinNode(_root->rc);
_root->val=_MinNode->val;
_root->rc=RemoveNode(_root->rc,_MinNode->val);
}
}
else//只有一个为NULL
{
TreeNode<T> *NowNode=_root;
if(NULL!=_root->lc)
{
_root=_root->lc;
}
else if(NULL!=_root->rc)
{
_root=_root->rc;
}
else
{
_root=NULL;// 当前节点是叶节点没有子节点
}
delete NowNode;
}
}
return _root;//把删除的节点返回
}
template<class T>
void BalancedBinaryTree<T>::RemoveKey(T _val)
{
subroot=RemoveNode(subroot,_val);
}
AVL树主要的精髓就是插入和删除,当然根据具体实现的功能也会有些许改动这面可以当做理解AVL树的一个参考。下面直接附上其余操作全部的代码。
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
template<class T>
class TreeNode
{
public:
T val;
TreeNode<T>* lc;
TreeNode<T>* rc;
int height;
public:
TreeNode(T _val=0,TreeNode<T> *_lc=NULL,TreeNode<T>* _rc=NULL,int _height=0):val(_val), lc(_lc),rc(_rc),height(_height)
{
}
~TreeNode()
{}
TreeNode<T>*Getlc()const{
return lc;
}
// void CreateNode(TreeNode)
void Setlc(TreeNode<T>* _lc);
TreeNode<T>* Getrc() const;
void Setrc(TreeNode<T>* _rc);
void SetVal(T _val);
T GetVal() const
{
return val;
}
bool IsLeaf();
static TreeNode<T>*CreateNode();
};
template<class T>
TreeNode<T>* TreeNode<T>::CreateNode()
{
cout<<"请输入当前节点的值:";
T n;
cin>>n;
if(n<0)
{
return;
}
TreeNode<T> *Node_ptr=new TreeNode<T>(n);
Node_ptr->lc=TreeNode<T>::CreateNode();
Node_ptr->rc=TreeNode<T>::CreateNode();
return Node_ptr;
}
template<class T>
void TreeNode<T>::SetVal(T _val)
{
val=_val;
}
template<class T>
void TreeNode<T>::Setlc(TreeNode<T>* _lc)
{
lc=_lc;
}
template<class T>
void TreeNode<T>::Setrc(TreeNode<T>* _rc)
{
rc=_rc;
}
template<class T>
TreeNode<T>* TreeNode<T>::Getrc() const
{
return rc;
}
//创建平衡二叉树
//平衡二叉树概念:平衡二叉树的跟节点,一定比他的左子树大,并且比它的右子树小,且每个根节点的左子树与右子树的高度相差不超过1.
template <class T>
class BalancedBinaryTree
{
private:
TreeNode<T>*subroot;
TreeNode<T>* InsertNode(TreeNode<T>* &_root,T _val);//插入节点
TreeNode<T>* RightHand(TreeNode<T>* &_root); //右旋
TreeNode<T>* LeftHand(TreeNode<T>* &_root); //左旋
TreeNode<T>* RightLeftHand(TreeNode<T>* &_root); //右左
TreeNode<T>* LeftRightHand(TreeNode<T>* &_root); //右左
TreeNode<T>* RemoveNode(TreeNode<T>* _root,T _val); //删除值为_val的节点,返回值是删除后的根节点
TreeNode<T>* MinNode(TreeNode<T>* _root) const; //获取树中的最小值,一直返回左子树的值,直到左子树为空
TreeNode<T>* MaxNode(TreeNode<T>* _root) const; //获取树中的最大值
TreeNode<T>* FindNode(TreeNode<T>*_root,T key) const; //查找值为Key的节点
void DestroyNode(TreeNode<T>* &_root); //销毁树
void TravelPreorderNode(TreeNode<T>* _root) const; //前序遍历-》深度优先遍历
public:
BalancedBinaryTree(TreeNode<T>* _subroot=NULL):subroot(_subroot)
{}
BalancedBinaryTree(BalancedBinaryTree<T> *Tree)
{
subroot=Tree->GetRoot();
}
~BalancedBinaryTree()
{}
TreeNode<T>* GetRoot() const
{
return subroot;
}
inline int getheight(TreeNode<T> *_Node) const
{
if(NULL==_Node)
{
return 0;
}
return _Node->height;
}
void InsertKey(T _val);
void RemoveKey(T _val);
void DestroyTree(); //销毁树
void TravelPreorderTree() const;
TreeNode<T> * FindKey(T _key);
int TreeHeight() const; //获取树的高度
void TravelInfixorder(TreeNode<T>* _root) const; //中序遍历-》深度优先遍历
void ExtentTravel(TreeNode<T>* _root) const; //广度优先遍历
};
template<class T>
void BalancedBinaryTree<T>::TravelPreorderTree() const
{
TravelPreorderNode(subroot);
}
template<class T>
void BalancedBinaryTree<T>::DestroyTree()
{
DestroyNode(subroot);
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::FindKey(T _key)
{
return FindNode(subroot,_key);
}
template<class T>
void BalancedBinaryTree<T>::RemoveKey(T _val)
{
subroot=RemoveNode(subroot,_val);
}
template<class T>
void BalancedBinaryTree<T>::InsertKey(T _val)
{
subroot=InsertNode(subroot,_val);
}
template<class T>
void BalancedBinaryTree<T>::DestroyNode(TreeNode<T> *&_root)
{
if(NULL!=_root)
{
DestroyNode(_root->lc);
DestroyNode(_root->rc);
delete _root;
_root=NULL;
}
}
template<class T>
int BalancedBinaryTree<T>::TreeHeight() const
{
return subroot->height;
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::FindNode(TreeNode<T>*_root,T key) const
{
if(NULL==_root)
{
return NULL;
}
if(_root->val==key)
{
return _root;
}
else if(key<_root->val)
{
return FindNode(_root->lc,key);
}
else
{
return FindNode(_root->rc,key);
}
}
template<class T>
void BalancedBinaryTree<T>::TravelPreorderNode(TreeNode<T> *_root) const
{
if(NULL==_root)
{
return;
}
cout<<_root->val<<" ";
TravelPreorderNode(_root->lc);
TravelPreorderNode(_root->rc);
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::MaxNode(TreeNode<T> *_root) const
{
if(NULL==_root)
{
return NULL;
}
while(NULL!=_root->rc)
{
_root=_root->rc;
}
return _root;
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::MinNode(TreeNode<T> *_root) const
{
if(NULL==_root)
{
return NULL;
}
while(NULL!=_root->lc)
{
_root=_root->lc;
}
return _root;
}
// 如果要删除的子树左右节点都为空,那么就用左节点的最大值或者右节点的最小值进行替换,这样不会破坏二叉树的平衡性
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::RemoveNode(TreeNode<T> *_root, T _val)
{
if(NULL==_root)
{
return NULL;
}
if(_val<_root->val)
{
_root->lc=RemoveNode(_root->lc,_val);
//删除左子树上的节点相当于在右子树上插入节点
if(getheight(_root->rc)-getheight(_root->lc)==2)
{
//相当于在右子树上插入左节点造成的失衡(情况四)
if (getheight(_root->rc->lc)>getheight(_root->rc->rc))
{
//相当与插入的右左
_root=RightLeftHand(_root);
}
else
{
//相当于插入的右右
_root=LeftHand(_root);
}
}
}
else if(_val>_root->val)
{
_root->rc=RemoveNode(_root->rc,_val);
if(getheight(_root->lc)-getheight(_root->rc)==2)
{
//删除右子树的节点相当与在左子树上插入节点,下面就判断是在左子树的右子树插入还是左子树的左子树插入的
if(getheight(_root->lc->lc)>getheight(_root->lc->rc))//左左
{
_root=RightHand(_root);
}
else
{
_root=LeftRightHand(_root);
}
}
}
else
{
//删除过程要判断:
//1 当前节点是不是叶节点
//2 删除之后还要看看是否破坏了平衡性
if(NULL!=_root->lc&&NULL!=_root->rc)
{
//从左右子树中较高的子树中找到对应的最大最小的点来替换,如果是左子树就用最大值,如果是右子树就用最小值
if(getheight(_root->lc)>getheight(_root->rc))//左边子树高度大
{
//获取左边节点最大值
TreeNode<T>* _MaxNode=MaxNode(_root->lc);
_root->val=_MaxNode->val;
_root->lc=RemoveNode(_root->lc,_MaxNode->val);
}
else
{
TreeNode<T>* _MinNode=MinNode(_root->rc);
_root->val=_MinNode->val;
_root->rc=RemoveNode(_root->rc,_MinNode->val);
}
}
else//只有一个为NULL
{
TreeNode<T> *NowNode=_root;
if(NULL!=_root->lc)
{
_root=_root->lc;
}
else if(NULL!=_root->rc)
{
_root=_root->rc;
}
else
{
_root=NULL;// 当前节点是叶节点没有子节点
}
delete NowNode;
}
}
return _root;//把删除的节点返回
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::LeftHand(TreeNode<T> *&_root)
{
TreeNode<T>* _rootrc=_root->rc;
_root->rc=_rootrc->lc;
_rootrc->lc=_root;
_rootrc->height=getheight(_rootrc->lc)>getheight(_rootrc->rc)?getheight(_rootrc->lc)+1:getheight(_rootrc->rc)+1;
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
return _rootrc;
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::RightHand(TreeNode<T> *&_root)
{
TreeNode<T> * _rootlc=_root->lc;
_root->lc=_rootlc->rc;
_rootlc->rc=_root;
_rootlc->height=getheight(_rootlc->lc)>getheight(_rootlc->rc)?getheight(_rootlc->lc)+1:getheight(_rootlc->rc)+1;
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
return _rootlc;//返回的就是作为参数传过来的节点在树中的位置
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::RightLeftHand(TreeNode<T> *&_root)
{
_root->lc=LeftHand(_root->lc);
return RightHand(_root);
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::LeftRightHand(TreeNode<T> *&_root)
{
_root->rc=RightHand(_root->rc);
return LeftHand(_root);
}
template<class T>
TreeNode<T>* BalancedBinaryTree<T>::InsertNode(TreeNode<T> *&_root,T _val)
{
if(NULL==_root)
{
_root=new TreeNode<T>(_val);
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
}
//判断当前节点应该插入根节点的左子树还是右子树
else if(_val<_root->val)
{
_root->lc=InsertNode(_root->lc,_val);
if(getheight(_root->lc)-getheight(_root->rc)==2)//插入后失衡
{
if(_val<_root->lc->val)
{
_root=RightHand(_root);//左左的旋转
}
else
{
_root=LeftRightHand(_root);//左右的旋转
}
}
}
else
{
_root->rc=InsertNode(_root->rc,_val);
if(getheight(_root->rc)-getheight(_root->lc)==2)// 右插后失衡
{
if(_val<_root->rc->val)
{
_root=RightLeftHand(_root);//右左
}
else
{
_root=LeftHand(_root); //右右
}
}
}
_root->height=getheight(_root->lc)>getheight(_root->rc)?getheight(_root->lc)+1:getheight(_root->rc)+1;
return _root;//返回插入的这个值
}
int main(int argc,char **argv)
{
BalancedBinaryTree<int>* root=new BalancedBinaryTree<int>();
for(int i=1;i<10;i++)
{
root->InsertKey(i);
}
root->RemoveKey(2);
root->RemoveKey(8);
root->TravelPreorderTree();
return 0;
}
对获取最大值与最小值代码做一下说明,因为AVL树的排序特性还和BST一样,所以树中最小的值就是最左节点的值。树中最大的值就是最右节点的值。