目录
Test.c
在本篇博客中,作者将会使用C++来带领你理解和实现AVLTree,同时,在学习AVLTree之前,你可以先看看下面这篇二叉搜索树的博客,因为AVTree也是一种二叉搜索树,它们有一些规则是一样的。
一.什么是AVLTree
在二叉搜索树的博客中,我们提到了,当插入的数据有序或者接近有序的时候,二叉搜索树会退化成单支树,导致其效率变低,所以为了解决这种情况,于是我们提出了AVLTree,即二叉平衡搜索树。
如下图就是一棵二叉搜索树退化成的单支树。
那么AVLTree又是如何实现使二叉树搜索树不会退化成单支树的呢,它又是如何保证效率的呢?
因为AVLTree严格的要求左右子树的高度差****不能大于1,且每一棵子树也一样。 如下图所示。
通过这样严格的高度差要求,该树就可以达到一个非常平衡的状态,以致于它的插入、删除、查找等操作的效率非常的高,其时间复杂度就是O(logN),N为结点的个数。
那么它又是如何实现这样的要求的?
前面说了,AVLTree保证了每个结点的左右子树的高度差不大于1,那是因为当有一个结点的左右子树高度差为2时,它会进行旋转,使其保证平衡,至于怎么旋转,我们接着往下看。
二.AVLTree的实现
知道了AVLTree的规则,那么我们就可以来实现一下AVLTree了。
1.树结点的定义
在树结点的定义中,对比平常的二叉树,多了两个变量,一个是父结点的指针_parent,一个是**_bf平衡因子**。
其中**_parent指针**是方便我们在后续的操作中,去倒着往上去找父结点。
_bf平衡因子是存储该结点的左右子树的高度差,这里默认为右子树的高度减去****左子树的高度,通过_bf平衡因子,我们可以很快的知道该结点下的树是否平衡。
cpp
template<class T>
struct TreeNode
{
//成员变量
T _data;//树结点存储的数据类型
TreeNode<T>* _left;//左孩子指针
TreeNode<T>* _right;//右孩子指针
TreeNode<T>* _parent;//父结点指针
int _bf;//平衡因子
//成员函数
TreeNode(cosnt T& tmp)//构造函数
:_data(tmp)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{}
};
对于平衡因子来说,如下图所示。
_bf平衡因子=右子树的高度 - 左子树的高度
当**_bf平衡因子的绝对值大于1**时,说明该结点的左右子树高度差大于1,这个时候需要进行旋转处理。如下图所示。
2.类的定义
对于类的定义,就比较简单,就是一个**_root指针**指向根节点。
cpp
template<class T>
class AVLTree
{
typedef TreeNode<T> Node;
public:
//构造函数
AVLTree()
:_root(nullptr)
{}
private:
Node* _root;//根节点的指针
};
3.插入结点
对于AVLTree来说,最重要的就是插入结点,同时,这也是比较难的一部分,代码也比较长,但是不要怕,我们把AVLTree的插入分成如下几个部分。
**1.**先按二叉搜索树的规则插入结点,就是先不管三七二十一,先把结点插入进去再说。
至于二叉搜索树的插入,可以看开头的博客链接。
**2.**更新平衡因子,插入新结点后会影响平衡因子,所以插入新结点后,要更新平衡因子。
**3.**判断是否要旋转,更新完平衡因子后,要判断直接结束了还是要进行旋转调整。
接下来我们要把上面的三个过程转换成代码,这里代码会有点长,我们把这个insert函数分成三部分来说。如下是这个函数的函数名 和参数 。tmp为要插入的值。
cpp
bool insert(const T& tmp)
①按二叉搜索树规则插入结点
对于这一部分来说,没那么难,整个插入过程如下图所示。
就是用tmp从根结点开始进行比较,一直往下找空位,找到空位后,再把结点插入进去。
cpp
//如果根节点为空,则直接插入
if (_root == nullptr)
{
_root = new Node(tmp);
return true;
}
//如果根节点不为空,则先按二叉搜索树的规则进行插入
Node* cur = _root;
Node* cur_parent = nullptr;
while (cur != nullptr)//往下找空位
{
if (tmp > cur->_data)
{
cur_parent = cur;
cur = cur->_right;
}
else if (tmp < cur->_data)
{
cur_parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//找到空位后,给空位一个新结点
cur = new Node(tmp);
if (cur->_data > cur_parent->_data)
{
cur_parent->_right = cur;
cur->_parent = cur_parent;
}
else
{
cur_parent->_left = cur;
cur->_parent = cur_parent;
}
②更新平衡因子
插入完结点后, 我们要更新平衡因子,那么怎么更新呢,我们往下看。
首先,当插入一个新结点的时候,只会影响新结点一路往上的_parent结点。如下图所示。
所以当我们更新平衡因子的时候,只需要通过_parent指针,一路向上更新即可,但是也不一定一直更新到根节点,为什么呢?我继续往下看。
既然是更新平衡因子,那么怎么个更新呢?
在开头,我们提到**_bf平衡因子 = 右子树的高度 - 左子树的高度**。
那么看上图,cur为新结点,cur_parent为cur的父结点,对于cur_parent来说,它的左子树新增了一个结点,也就是说左子树的高度+1,所以对于**_bf = 右子树高度 - 左子树高度这个公式来说,左子树高度+1,即_bf-1,如果cur是cur_parent的右子树反之+1**。这里可能会很乱,没事,我们来看下图。
当更新完一个结点的平衡因子的时候,这个时候会有三种情况:
**1.**更新完该结点后,会影响****向上的父结点,继续更新。
**2.**更新完该结点后,不会影响****向上的父结点,更新结束。
3.更新完该结点后,该结点的平衡因子==2或==-2,此时需要进行旋转处理。
整个过程的代码如下。
cpp
//插入完结点后,要更新平衡因子
while (cur_parent != nullptr)
{
if (cur_parent->_right == cur)//说明新增结点是cur_parent的右子树,即右子树高度增加1
{
cur_parent->_bf++;
}
else
{
cur_parent->_bf--;
}
if (cur_parent->_bf == 0)//如果cur_parent的平衡因子为0,结束更新
{
break;
}
else if (cur_parent->_bf == 1 || cur_parent-> == -1)//如果cur_parent的平衡因子为1或者-1,则继续向上更新
{
cur = cur_parent;
cur_parent = cur_parent->_parent;
}
else if (cur_parent->_bf == 2 || cur_parent->_bf == -2)
{
//进行旋转处理
}
更新平衡因子情况分析
更新完后,为什么平衡因子==0就停止更新,==1或者==-1要继续向上更新?
我们来分析一下。首先来看**==0情况**。如下图所示
我们插入20,插入后结点15的平衡因子要更新为0,
从图中,我们可以轻易的看出对于结点10来说,它的平衡因子是不受影响的,那么是为什么呢?
因为树的高度是由高的子树来决定的,对于结点10来说,它的高的子树是**(15~12)这个两个结点构成的子树** ,而新增的结点20没有增加到高的子树上去,所以对于结点10来说,高度没变。如下图所示。
接下来看看==1或者==-1的情况,
首先是一棵正常的树,我们插入新结点20,插入后,结点18的平衡因子要变为1,
因为结点18的平衡因子为1,所以要继续向上更新,为什么呢?
解释与上面那种情况类似,当一个结点的平衡因子由0变为1或者-1的时候,说明该结点的高度增加了1,说明该结点的子树高度增加了1,这个时候会影响上面结点的高度,所以平衡因子要一直向上更新。
③判断是否要旋转
至于当平衡因子==2或者==-2的时候,要进行旋转处理就没什么好说的了,因为AVLTree就是严格的要求平衡因子的绝对值不能大于2。
那么旋转又是怎么旋转的呢?
旋转又可以分为四种情况:左单旋,右单旋,左右双旋,右左双旋。
我们来分析一下。
左单旋
当一个结点的_bf为2,且它的右孩子的_bf为1时,要进行左单旋。 如下图所示
旋转完后,如下图所示。
对于左单旋的所有情况,我们可以用下面这两个抽象图来表示所有情况。
进行旋转处理后,如下图所示。
对于整个旋转过程来说,就是去改变cur_parent和cur结点的指针关系。
cur_parent的右指针,去指向cur的左子树,
cur的左指针,去指向cur_parent,
注意,这里还要改变****cur_parent和cur结点的**_parent指针**。
但是这里注意的时,cur_parent不一定如上图所示为根结点,它有可能是某个结点的子树,如下图所示。
所以旋转完成后还要进行一次判断,是否需要将cur结点链接到上一个结点。
cpp
//左单旋
void RotateL(Node* cur_parent)
{
Node* cur = cur_parent->_right;
Node* cur_left = cur->_left;
//改变指针的链接关系
cur_parent->_right = cur_left;
if (cur_left != nullptr)
{
cur_left->_parent = cur_parent;
}
cur->_left = cur_parent;
Node* cur_parent_parent = cur_parent->_parent;//提前保存cur_parent的父结点
cur_parent->_parent = cur;
//旋转完成后要判断cur_parent是否为根
if (cur_parent_parent != nullptr)//说明cur_parent不是根
{
if (cur_parent_parent->_data < cur_parent->_data)
{
cur_parent_parent->_right = cur;
cur->_parent = cur_parent_parent;
}
else
{
cur_parent_parent->_left = cur;
cur->_parent = cur_parent_parent;
}
}
else//说明cur_parent是根
{
_root = cur;
cur->_parent = nullptr;
}
//旋转完成后,平衡因子调整为0
cur_parent->_bf = cur->_bf = 0;
}
右单旋
同样的右单旋与左单旋类似,只不过是反过来而已,这里不再做过多的解释,只给出抽象图出来。
经过右单旋后,变成如下图所示。
cpp
//右单旋
void RotateR(Node* cur_parent)
{
Node* cur = cur_parent->_left;
Node* cur_right = cur->_right;
cur_parent->_left = cur_right;
if (cur_right != nullptr)
{
cur_right->_parent = cur_parent;
}
cur->_right = cur_parent;
Node* cur_parent_parent = cur_parent->_parent;
cur_parent->_parent = cur;
if (cur_parent_parent != nullptr)
{
if (cur_parent_parent->_data > cur_parent->_data)
{
cur_parent_parent->_left = cur;
cur->_parent = cur_parent_parent;
}
else
{
cur_parent_parent->_right = cur;
cur->_parent = cur_parent_parent;
}
}
else
{
_root = cur;
cur->_parent = nullptr;
}
cur_parent->_bf = cur->_bf = 0;
}
左右单旋
左单旋和右单旋解释完成后,接下来要将双旋了,那么什么情况下要用双旋呢?
我们来看一下抽象图
当新插入结点时,如果符合上图中的情况,则要进行左右双旋操作,注意!!! 新增的红色结点也有可能插入在结点15的右树,其旋转过程就是先对结点10进行一个左单旋,再对结点20进行一个右单旋。如下图所示。
先对结点10进行一个左单旋,再对结点20进行一个右单旋。
但是上面这个抽象图不能代表双旋的所有情况,因为双旋有一种特殊的情况,如下图所示。
对于这种特殊情况,我们只需要先前保存cur_right的平衡因子,双旋完成后,如果平衡因子为0,说明就是这种特殊情况,再进行特殊处理即可。
cpp
//左右双旋
void RotateLR(Node* cur_parent)
{
Node* cur = cur_parent->_left;
Node* cur_right = cur->_right;
int bf = cur_right->_bf;//这里保存平衡因子的原因是,新增的结点有可能插入在左树,也有可能插入在右树,通过保存平衡因子来进行判断是哪一种情况
//先对cur进行一个左单旋
RotateL(cur);
//再对cur_parent进行一个右单旋
RotateR(cur_parent);
//旋转完成后,要更新平衡因子
if (bf == -1)//说明新增的结点是插入在左树
{
cur->_bf = 0;
cur_parent->_bf = 1;
cur_right->_bf = 0;
}
else if (bf == 1)//说明新增的结点是插入在右树
{
cur->_bf = -1;
cur_parent->_bf = 0;
cur_right->_bf = 0;
}
else if (bf == 0)//特殊情况
{
cur->_bf = 0;
cur_parent->_bf = 0;
cur_right->_bf = 0;
}
}
右左双旋
对于右左双旋来说,与左右单旋类似,就是换了个方向而已,这里不再过多的解释,直接给出抽象图和代码。
先进行一个右单旋,再进行一个左单旋,旋转如下图所示。
同样的,这里也要处理特殊情况,就不在过多的解释。
cpp
//右左双旋
void RotateRL(Node* cur_parent)
{
Node* cur = cur_parent->_right;
Node* cur_left = cur->_left;
int bf = cur_left->_bf;
//先对cur进行一个右单旋
RotateR(cur);
//再对cur_parent进行一个左单旋
RotateL(cur_parent);
//更新平衡因子
if (bf == -1)
{
cur->_bf = 1;
cur_parent->_bf = 0;
cur_left->_bf = 0;
}
else if (bf == 1)
{
cur->_bf = 0;
cur_parent->_bf = -1;
cur_left->_bf = 0;
}
else if (bf == 0)
{
cur->_bf = 0;
cur_parent->_bf = 0;
cur_left->_bf = 0;
}
}
走到这一步,我们的旋转代码就已经全部写好了,接下来可以接着补充我们的插入函数的旋转部分。
cpp
bool insert(const T& tmp)
{
//如果根节点为空,则直接插入
if (_root == nullptr)
{
_root = new Node(tmp);
return true;
}
//如果根节点不为空,则先按二叉搜索树的规则进行插入
Node* cur = _root;
Node* cur_parent = nullptr;
while (cur != nullptr)//往下找空位
{
if (tmp > cur->_data)
{
cur_parent = cur;
cur = cur->_right;
}
else if (tmp < cur->_data)
{
cur_parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//找到空位后,给空位一个新结点
cur = new Node(tmp);
if (cur->_data > cur_parent->_data)
{
cur_parent->_right = cur;
cur->_parent = cur_parent;
}
else
{
cur_parent->_left = cur;
cur->_parent = cur_parent;
}
//插入完结点后,要更新平衡因子
while (cur_parent != nullptr)
{
if (cur_parent->_right == cur)
{
cur_parent->_bf++;
}
else
{
cur_parent->_bf--;
}
if (cur_parent->_bf == 0)
{
break;
}
else if (cur_parent->_bf == 1 || cur_parent->_bf == -1)
{
cur = cur_parent;
cur_parent = cur_parent->_parent;
}
else if (cur_parent->_bf == 2 || cur_parent->_bf == -2)
{
//进行旋转处理
if (cur_parent->_bf == 2)
{
if (cur->_bf == 1)//左单旋
{
RotateL(cur_parent);
}
else if(cur->_bf == -1)//右左双旋
{
RotateRL(cur_parent);
}
}
else if (cur_parent->_bf == -2)
{
if (cur->_bf == 1)//左右单旋
{
RotateLR(cur_parent);
}
else if (cur->_bf == -1)//右单旋
{
RotateR(cur_parent);
}
}
break;
}
}
return true;
}
写到这里,我们的插入代码就完成了,这也是AVLTree实现的最核心的部分。
4.删除、查找和修改函数
对于一个数据结构来说,最基本的操作是增删改查,现在增已经实现了,那么还有剩下的三个函数。
删除:
对于AVLTree的删除来说,情况比插入还稍许复杂,又由于博主的能力和精力有限,在这里就不讲了。
查找:
对于AVLTree的查找来说,就显得很简单,跟二叉搜索树的查找一样,就不过多的解释,等下下面直接给出代码。
修改:
对于AVLTree的修改来说,一般来说,是不允许修改的,因为AVLTree是一种搜索树,它的中序遍历是绝对的有序的,如果进行修改,就会破坏整棵树的性质,导致不再是搜索树,但是也有允许修改的情况,当树中存的是一个pair键值对,我们可以对pair键值对的val进行修改,具体解释,参考这篇博客中的kv模型【C++】二叉搜索树-CSDN博客
查找结点
cpp
//查找结点
Node* find(const T& tmp)
{
Node* cur = _root;
while (cur != nullptr)
{
if (tmp > cur->_data)
{
cur = cur->_right;
}
else if (tmp < cur->_data)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
三.测试
既然我们的插入已经完成了,那么我们又如何判断我们写的代码是对的呢,接下来讲一下如何测试我们写的AVLTree。
1.判断是否是搜索树
既然是AVLTree,那么它一定是一棵搜索树,所以它的中序遍历一定是有序的,所以我们可以写一个中序遍历来看看是否是搜索树。
cpp
//中序遍历
void InOrder()
{
Node* cur = _root;
_InOrder(cur);
}
//中序遍历的子函数
void _InOrder(Node* cur)
{
if (cur == nullptr)
return;
_InOrder(cur->_left);
cout << cur->_data << " ";
_InOrder(cur->_right);
}
2.判断每一个结点的左右子树高度差是否不大于1
判断完了确定是搜索树,接下来就要判断是否是AVLTree树,即每一个结点的左右子树高度差都不大于1。
首先,我们可以先写一个求树的高度的函数。
cpp
//求树的高度
int height(Node* cur)
{
if (cur == nullptr)
return 0;
//返回左右子树高的那一个子树+1,fmax是库函数,求两个参数的较大值
return fmax(height(cur->_left), height(cur->_right)) + 1;
}
然后就可以写一个判断是否平衡的函数。
cpp
//判断是否平衡
bool JudgeBanlance()
{
Node* cur = _root;
return _JudgeBanlance(cur);
}
//判断是否平衡的子函数
bool _JudgeBanlance(Node* cur)
{
if (cur == nullptr)
return true;
int left_height = height(cur->_left);//求cur左子树的高度
int right_height = height(cur->_right);//求cur右子树的高度
//abs是求左右子树高度差的绝对值
return abs(left_height - right_height) < 2
&& _JudgeBanlance(cur->_left)
&& _JudgeBanlance(cur->_right);
}
写到这里,我们的判断是否是AVLTree也完成了,AVLTree也基本实现了。
四.所有源代码
AVLTree.h
cpp
#pragma once
#include<iostream>
#include<time.h>
using namespace std;
//编写一篇博客
namespace blog_AVLTree
{
template<class T>
struct TreeNode
{
//成员变量
T _data;//树结点存储的数据类型
TreeNode<T>* _left;//左孩子指针
TreeNode<T>* _right;//右孩子指针
TreeNode<T>* _parent;//父结点指针
int _bf;//平衡因子
//成员函数
TreeNode(const T& tmp)//构造函数
:_data(tmp)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{}
};
template<class T>
class AVLTree
{
typedef TreeNode<T> Node;
public:
AVLTree()
:_root(nullptr)
{}
//插入
bool insert(const T& tmp)
{
//如果根节点为空,则直接插入
if (_root == nullptr)
{
_root = new Node(tmp);
return true;
}
//如果根节点不为空,则先按二叉搜索树的规则进行插入
Node* cur = _root;
Node* cur_parent = nullptr;
while (cur != nullptr)//往下找空位
{
if (tmp > cur->_data)
{
cur_parent = cur;
cur = cur->_right;
}
else if (tmp < cur->_data)
{
cur_parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
//找到空位后,给空位一个新结点
cur = new Node(tmp);
if (cur->_data > cur_parent->_data)
{
cur_parent->_right = cur;
cur->_parent = cur_parent;
}
else
{
cur_parent->_left = cur;
cur->_parent = cur_parent;
}
//插入完结点后,要更新平衡因子
while (cur_parent != nullptr)
{
if (cur_parent->_right == cur)
{
cur_parent->_bf++;
}
else
{
cur_parent->_bf--;
}
if (cur_parent->_bf == 0)
{
break;
}
else if (cur_parent->_bf == 1 || cur_parent->_bf == -1)
{
cur = cur_parent;
cur_parent = cur_parent->_parent;
}
else if (cur_parent->_bf == 2 || cur_parent->_bf == -2)
{
//进行旋转处理
if (cur_parent->_bf == 2)
{
if (cur->_bf == 1)//左单旋
{
RotateL(cur_parent);
}
else if(cur->_bf == -1)//右左双旋
{
RotateRL(cur_parent);
}
}
else if (cur_parent->_bf == -2)
{
if (cur->_bf == 1)//左右单旋
{
RotateLR(cur_parent);
}
else if (cur->_bf == -1)//右单旋
{
RotateR(cur_parent);
}
}
break;
}
}
return true;
}
//查找结点
Node* find(const T& tmp)
{
Node* cur = _root;
while (cur != nullptr)
{
if (tmp > cur->_data)
{
cur = cur->_right;
}
else if (tmp < cur->_data)
{
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
//中序遍历
void InOrder()
{
Node* cur = _root;
_InOrder(cur);
}
//求树的高度
int height(Node* cur)
{
if (cur == nullptr)
return 0;
return fmax(height(cur->_left), height(cur->_right)) + 1;
}
//判断是否平衡
bool JudgeBanlance()
{
Node* cur = _root;
return _JudgeBanlance(cur);
}
private:
//左单旋
void RotateL(Node* cur_parent)
{
Node* cur = cur_parent->_right;
Node* cur_left = cur->_left;
//改变指针的链接关系
cur_parent->_right = cur_left;
if (cur_left != nullptr)
{
cur_left->_parent = cur_parent;
}
cur->_left = cur_parent;
Node* cur_parent_parent = cur_parent->_parent;
cur_parent->_parent = cur;
//旋转完成后要判断cur_parent是否为根
if (cur_parent_parent != nullptr)//说明cur_parent不是根
{
if (cur_parent_parent->_data < cur_parent->_data)
{
cur_parent_parent->_right = cur;
cur->_parent = cur_parent_parent;
}
else
{
cur_parent_parent->_left = cur;
cur->_parent = cur_parent_parent;
}
}
else//说明cur_parent是根
{
_root = cur;
cur->_parent = nullptr;
}
//旋转完成后,平衡因子调整为0
cur_parent->_bf = cur->_bf = 0;
}
//右单旋
void RotateR(Node* cur_parent)
{
Node* cur = cur_parent->_left;
Node* cur_right = cur->_right;
cur_parent->_left = cur_right;
if (cur_right != nullptr)
{
cur_right->_parent = cur_parent;
}
cur->_right = cur_parent;
Node* cur_parent_parent = cur_parent->_parent;
cur_parent->_parent = cur;
if (cur_parent_parent != nullptr)
{
if (cur_parent_parent->_data > cur_parent->_data)
{
cur_parent_parent->_left = cur;
cur->_parent = cur_parent_parent;
}
else
{
cur_parent_parent->_right = cur;
cur->_parent = cur_parent_parent;
}
}
else
{
_root = cur;
cur->_parent = nullptr;
}
cur_parent->_bf = cur->_bf = 0;
}
//左右双旋
void RotateLR(Node* cur_parent)
{
Node* cur = cur_parent->_left;
Node* cur_right = cur->_right;
int bf = cur_right->_bf;
//先对cur进行一个左单旋
RotateL(cur);
//再对cur_parent进行一个右单旋
RotateR(cur_parent);
//旋转完成后,要更新平衡因子
if (bf == -1)
{
cur->_bf = 0;
cur_parent->_bf = 1;
cur_right->_bf = 0;
}
else if (bf == 1)
{
cur->_bf = -1;
cur_parent->_bf = 0;
cur_right->_bf = 0;
}
else if (bf == 0)//特殊情况
{
cur->_bf = 0;
cur_parent->_bf = 0;
cur_right->_bf = 0;
}
}
//右左双旋
void RotateRL(Node* cur_parent)
{
Node* cur = cur_parent->_right;
Node* cur_left = cur->_left;
int bf = cur_left->_bf;
//先对cur进行一个右单旋
RotateR(cur);
//再对cur_parent进行一个左单旋
RotateL(cur_parent);
//更新平衡因子
if (bf == -1)
{
cur->_bf = 1;
cur_parent->_bf = 0;
cur_left->_bf = 0;
}
else if (bf == 1)
{
cur->_bf = 0;
cur_parent->_bf = -1;
cur_left->_bf = 0;
}
else if (bf == 0)
{
cur->_bf = 0;
cur_parent->_bf = 0;
cur_left->_bf = 0;
}
}
//中序遍历的子函数
void _InOrder(Node* cur)
{
if (cur == nullptr)
return;
_InOrder(cur->_left);
cout << cur->_data << " ";
_InOrder(cur->_right);
}
//判断是否平衡的子函数
bool _JudgeBanlance(Node* cur)
{
if (cur == nullptr)
return true;
int left_height = height(cur->_left);//求cur左子树的高度
int right_height = height(cur->_right);//求cur右子树的高度
return abs(left_height - right_height) < 2
&& _JudgeBanlance(cur->_left)
&& _JudgeBanlance(cur->_right);
}
private:
Node* _root;
};
void Test1()
{
AVLTree<int> root;
//int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
root.insert(arr[i]);
}
root.InOrder();
cout << root.JudgeBanlance() << endl;
}
void Test2()
{
srand(time(0));
AVLTree<int> root;
const int n = 100;
for (int i = 0; i < n; i++)
{
root.insert(rand());
}
root.InOrder();
cout << root.JudgeBanlance() << endl;
}
}
Test.c
cpp
#include"AVLTree.h"
int main()
{
blog_AVLTree::Test1();
//blog_AVLTree::Test2();
return 0;
}