目录
一、概念
AVL树,是平衡二叉搜索树的一种,以发明它的前苏联科学家的名字(G. M. Adelson-Velsky和E. M. Landis)命名。
1.AVL树是平衡二叉搜索树的一种,也就是说,每一个AVL树的左右子树的高度差都不超过1,且其左右子树也为AVL树。
2.空树也是AVL树。
为什么AVL树的左右子树的高度差不能超过1而不是0呢,因为在某些情况下,平衡二叉搜索树做不到完全平衡,比如两个或者四个结点的情况,这种情况下是必然会出现左右子树的高度差的,因此只要我们把左右子树的高度差控制在1的范围内就好。
AVL树的实现其实有很多版本,本博客挑选了比较容易理解的平衡因子版本来进行探究和实现。
二、模拟实现
1.平衡因子
在AVL树的模拟实现中,我们在每个结点中增添了平衡因子这一成员变量,平衡因子在其中表示的含义是:右子树高度减左子树高度。
平衡因子会出现的三种情况:
1. 如果bf(平衡因子,balance factor)等于0,说明该结点的左右子树高度相等,满足AVL树平衡条件;
2. 如果bf(平衡因子,balance factor)等于1或-1,说明该结点的左右子树的高度差为1,仍满足AVL树的平衡条件;
3. 如果bf(平衡因子,balance factor)等于2或-2,说明该结点的左右子树高度差达到了2,AVL树以已经不平衡了,需要我们做必要的调整(旋转,后面会重点说)。
既然结点中加入了平衡因子这个变量,那么就会涉及到平衡因子的更新,为了更加方便快速地更新平衡因子,我们还需要向结点中添加父结点这一成员变量。
2.搭建框架
只需要在前面实现的二叉搜索树的框架基础上,把增加一下结点的成员变量即可。
// key/value版本的AVLTree
template<class K, class V>
struct AVLTNode
{
pair<K, V> _kv;
int _bf; // balance factor 平衡因子
AVLTNode<K, V>* _parent; // 父结点,方便快速更新平衡因子
AVLTNode<K, V>* _left;
AVLTNode<K, V>* _right;
AVLTNode(const pair<K, V>& kv)
:_kv(kv)
,_bf(0)
,_parent(nullptr)
, _left(nullptr)
, _right(nullptr)
{}
};
template<class K, class V>
class AVLTree
{
using Node = AVLTNode<K, V>;
public:
private:
Node* _root = nullptr;
};
3.插入
我们先顺着来:
插入的第一步肯定还是需要查找,就是找到需要插入的位置,如果已经有这个结点了,返回false,如果没有,就插入。(同二叉搜索树)
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root, * parent = nullptr;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
// 相等,不能插入
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first > kv.first) parent->_left = cur;
else parent->_right = cur;
// 至此为普通二叉搜索树的插入
// 不过由于我们的Node引入了额外的成员变量,所以还需要更新平衡因子和parent结点指针
}
到现在为止的操作都还是与二叉搜索树的操作一样的。
不过插入之后呢,由于我们结点的成员变量多出了平衡因子和父结点,所以这两个成员变量还需要我们去维护,父结点的维护就很简单了,在插入cur之后加一句cur->_parent = parent;就ok,下面是平衡因子的维护:
对平衡因子的更新,可以分为3种情况:
1. 平衡因子更新后为0:这种情况肯定是平衡因子从1或-1更新过来的,也就是原来该结点的左右子树高度差为1,更新后高度差为0,也就是说该结点的父结点对应的子树高度没有变化,所以就不必再继续更新。
2. 平衡因子更新后为1或-1:由于插入前该树是AVL树,所以平衡因子必定是从0变成的1或-1,那么该结点的父结点的对应子树高度会+1,要继续向上更新。
3. 平衡因子更新后为2或-2:这种情况肯定是平衡因子从1或-1更新来的,也就是说该结点的左右子树的高度差变成了2,此时该树就不是AVL树了,那么就应该对平衡因子为2的部分进行一定的操作(旋转)来解决。
注意:
1. 更新平衡因子最多会更新到根节点,不会更新到根节点的另外一条子树上。
2. 更新过程中,结点左子树插入了结点那么_bf--,右子树插入了结点_bf++
下面是维护父结点和更新平衡因子的版本(还没有旋转):
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root, * parent = nullptr;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
// 相等,不能插入
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first > kv.first) parent->_left = cur;
else parent->_right = cur;
// 至此为普通二叉搜索树的插入
// 不过由于我们的Node引入了额外的成员变量,所以还需要更新平衡因子和parent结点指针
// cur的父结点维护
cur->_parent = parent;
// 平衡因子的更新
// parent是nullptr(cur是根结点)或者parent->_bf == 0时循环结束
while (parent)
{
// 插入在parent右结点,parent的_bf++
// 插入在parent左结点,parent的_bf--
if (cur = parent->_right) parent->_bf++;
else parent->_bf--;
// 更新parent平衡因子后,进行判断
// 继续向上更新/停止更新/旋转
if (parent->_bf == 0)
{
// 停止更新,也不必做任何调整
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
// 继续向上更新
cur = parent;
parent = cur->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
// 旋转
}
else
{
// 如果平衡因子的逻辑出错出现意料之外的值,就会直接报错
assert(false);
}
}
}
4.旋转——处理平衡因子为2或-2的情况
旋转分四种情况,这四种情况又可以分为两组,同一组之间的两个旋转比较类似(对称),下面我来解释一下这四种情况的产生:
首先我们需要一个空树,其实这个空树就是AVL树。
接着我们插入两个结点(一个根结点和一个孩子结点)(由于左右的对称性我就随便插入了)
此时,该树它仍是AVL树
接着插入第三个结点:
如果是这样,该树仍然平衡,仍然是AVL树
考虑一下另外的情况:
如果是这样子,很明显该树就不平衡了,就不是AVL树了 ,而这其实就是旋转的两种情况,其它两种情况与这两种情况完全对称:
为什么只是列举了插入三个结点的情况,却能代表所有?
因为该列举的树的根节点也有可能是其它结点的孩子结点 ,而列举的这些结点的前两个结点(也可以有左右子树,只不过画的为空树)在插入第三个结点前也保持着AVL树的规范。
如果不是很明白,我后面会分析很一般的情况。
至于这些旋转它们的命名,相信你看完原理之后自然会明白。
三、旋转原理及实现
1.右单旋
右单旋,也就是刚刚列举的这个:
一起分析一下比较一般的情况:
这个旋转的大致是5转到10,10转到后来的5的右子树位置,看起来就像整体向右旋转(其实是顺时针),所以叫右单旋。
结点的名称含义:
parent:当前AVL树(可能是局部)的根结点subL:sub替补L左边,parent的左孩子结点
subLR:parent的左孩子结点的右孩子结点
右单旋的过程:
parent连接到subL的右孩子上,subLR连接到parent的左孩子上。
那么我们来实现代码~
等等......代码真的有那么简单吗?不!
别忘了,我们的Node中多出的成员变量,需要我们再分析一下平衡因子和parent的更新
从刚刚图上可以看得,parent和subL的平衡因子都变成了0,其余的a,b,c中的平衡因子不变(因为他们的平衡因子在刚插入还未旋转的时候就已经更新过了)
另外,该AVL树可能是一个AVL树的局部的一部分,所以该AVL树旋转后的根结点的parent也要更新。不仅如此,该结点的parent的左/右孩子结点也要更新。
右单旋的代码实现:
// 右单旋 rotate 旋转 right 右
void RotateR(Node* parent)
{
// 连接
Node* subL = parent->_left;
Node* subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
// 更新平衡因子
subL->_bf = 0;
parent->_bf = 0;
// 更新_parent
subL->_parent = parent->_parent;
parent->_parent = subL;
if (subLR) subLR->_parent = parent;
// 根结点的情况
if (parent == _root) _root = subL;
// 非根结点 更新“看不见的”parent
else if (parent == subL->_parent->_left) subL->_parent->_left = subL;
else subL->_parent->_right = subL;
}
2.左单旋
与右单旋对称,大家可以自行推导,我给出图供大家参考
左单旋的代码实现
// 左单旋
void RotateL(Node* parent)
{
// 连接
Node* subR = parent->_right;
Node* subRL = subL->_left;
subL->_left = parent;
parent->_right = subRL;
// 更新平衡因子
subR->_bf = 0;
parent->_bf = 0;
// 更新_parent
subR->_parent = parent->_parent;
parent->_parent = subR;
if (subRL) subRL->_parent = parent;
// 根结点的情况
if (parent == _root) _root = subR;
// 非根结点 更新“看不见的”parent
else if (parent == subR->_parent->_left) subR->_parent->_left = subR;
else subR->_parent->_right = subR;
}
3.左右双旋
需要左右双旋的情况:
抽象情况:
我们分解一下b:
由上面的分析我们可以知道,5和10都做不了当前局部AVL树的根节点,那么小于10但是大于5的结点8是否可以呢?
答案是可行,如果我们先以5为parent对其进行左单旋,就会变成:
再以10为parent对其进行右单旋:
现在得到的树就是AVL树了。
这里面需要注意的点:
插入结点在subLR的左子树还是右子树,这会影响到平衡因子的变化。
如果插入结点在subLR的左子树,那么该结点会随第一次的左单旋接到subL的右子树上,subL的平衡因子为0,parent的平衡因子为1,反之subL的平衡因子为-1,parent的平衡因子为0。
所以刚开始要判断一下subLR的平衡因子,以便后面平衡因子的更新。
第一次是左单旋,第二次是右单旋,所以叫左右双旋。
左右双旋的代码实现
// 左右双旋
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(subL);
RotateR(parent);
if (bf == -1)
{
// 不是RotateL和RotateR中已经把subL和subLR的_bf置为0了吗,为什么还要这样写
// 减少函数之间的耦合度
subLR->_bf = 0;
subL->_bf = 0;
parent->_bf = 1;
}
else if (bf == 1)
{
subLR->_bf = 0;
subL->_bf = -1;
parent->_bf = 0;
}
else if (bf == 0)
{
subLR->_bf = 0;
subL->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
4.右左双旋
与左右双旋完全对称哦,大家自行研究~
右左双旋的代码实现
// 右左双旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);
RotateL(parent);
if (bf == -1)
{
// 不是RotateL和RotateR中已经把subL和subLR的_bf置为0了吗,为什么还要这样写
// 减少函数之间的耦合度
subRL->_bf = 0;
subR->_bf = 1;
parent->_bf = 0;
}
else if (bf == 1)
{
subRL->_bf = 0;
subR->_bf = 0;
parent->_bf = -1;
}
else if (bf == 0)
{
subRL->_bf = 0;
subR->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
5.插入最终代码
在之前的插入代码实现中,就差最后的旋转就能完成了,我们只需要判断一下哪种情况需要哪个结点进行什么样的旋转,就ok了~
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root, * parent = nullptr;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
// 相等,不能插入
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first > kv.first) parent->_left = cur;
else parent->_right = cur;
// 至此为普通二叉搜索树的插入
// 不过由于我们的Node引入了额外的成员变量,所以还需要更新平衡因子和parent结点指针
// cur的父结点维护
cur->_parent = parent;
// 平衡因子的更新
// parent是nullptr(cur是根结点)或者parent->_bf == 0时循环结束
while (parent)
{
// 插入在parent右结点,parent的_bf++
// 插入在parent左结点,parent的_bf--
if (cur == parent->_right) parent->_bf++;
else parent->_bf--;
// 更新parent平衡因子后,进行判断
// 继续向上更新/停止更新/旋转
if (parent->_bf == 0)
{
// 停止更新,也不必做任何调整
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
// 继续向上更新
cur = parent;
parent = cur->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
// 旋转
if (parent->_bf == -2 && cur->_bf == -1)
RotateR(parent);
else if (parent->_bf == -2 && cur->_bf == 1)
RotateLR(parent);
else if (parent->_bf == 2 && cur->_bf == 1)
RotateL(parent);
else if (parent->_bf == 2 && cur->_bf == -1)
RotateRL(parent);
else
assert(false);
break;
}
else
{
// 如果平衡因子的逻辑出错出现意料之外的值,就会直接报错
assert(false);
}
}
return true;
}
// 右单旋 rotate 旋转 right 右
void RotateR(Node* parent)
{
// 连接
Node* subL = parent->_left;
Node* subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
// 更新平衡因子
subL->_bf = 0;
parent->_bf = 0;
// 更新_parent
subL->_parent = parent->_parent;
parent->_parent = subL;
if (subLR) subLR->_parent = parent;
// 根结点的情况
if (parent == _root) _root = subL;
// 非根结点 更新“看不见的”parent
else if (parent == subL->_parent->_left) subL->_parent->_left = subL;
else subL->_parent->_right = subL;
}
// 左单旋
void RotateL(Node* parent)
{
// 连接
Node* subR = parent->_right;
Node* subRL = subR->_left;
subR->_left = parent;
parent->_right = subRL;
// 更新平衡因子
subR->_bf = 0;
parent->_bf = 0;
// 更新_parent
subR->_parent = parent->_parent;
parent->_parent = subR;
if (subRL) subRL->_parent = parent;
// 根结点的情况
if (parent == _root) _root = subR;
// 非根结点 更新“看不见的”parent
else if (parent == subR->_parent->_left) subR->_parent->_left = subR;
else subR->_parent->_right = subR;
}
// 左右双旋
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(subL);
RotateR(parent);
if (bf == -1)
{
// 不是RotateL和RotateR中已经把subL和subLR的_bf置为0了吗,为什么还要这样写
// 减少函数之间的耦合度
subLR->_bf = 0;
subL->_bf = 0;
parent->_bf = 1;
}
else if (bf == 1)
{
subLR->_bf = 0;
subL->_bf = -1;
parent->_bf = 0;
}
else if (bf == 0)
{
subLR->_bf = 0;
subL->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
// 右左双旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);
RotateL(parent);
if (bf == -1)
{
// 不是RotateL和RotateR中已经把subL和subLR的_bf置为0了吗,为什么还要这样写
// 减少函数之间的耦合度
subRL->_bf = 0;
subR->_bf = 1;
parent->_bf = 0;
}
else if (bf == 1)
{
subRL->_bf = 0;
subR->_bf = 0;
parent->_bf = -1;
}
else if (bf == 0)
{
subRL->_bf = 0;
subR->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
四、测试
主要需要测试一下我们实现的AVL树的平衡因子是否正常,高度差是否正常,以及验证一下我们实现的AVL树的插入和查找效率。
下面给出的是包含测试代码的整体本博客所有代码:
// AVLTree.h
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
// key/value版本的AVLTree
template<class K, class V>
struct AVLTNode
{
pair<K, V> _kv;
int _bf; // balance factor 平衡因子
AVLTNode<K, V>* _parent; // 父结点,方便快速更新平衡因子
AVLTNode<K, V>* _left;
AVLTNode<K, V>* _right;
AVLTNode(const pair<K, V>& kv)
:_kv(kv)
,_bf(0)
,_parent(nullptr)
, _left(nullptr)
, _right(nullptr)
{}
};
template<class K, class V>
class AVLTree
{
using Node = AVLTNode<K, V>;
public:
// 查找(和二叉搜索树一样)
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_kv.first < key)
cur = cur->_right;
else if (cur->_kv.first > key)
cur = cur->_left;
else
return cur;
}
return nullptr;
}
// 插入
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root, * parent = nullptr;
while (cur)
{
if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->_left;
}
else
{
// 相等,不能插入
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first > kv.first) parent->_left = cur;
else parent->_right = cur;
// 至此为普通二叉搜索树的插入
// 不过由于我们的Node引入了额外的成员变量,所以还需要更新平衡因子和parent结点指针
// cur的父结点维护
cur->_parent = parent;
// 平衡因子的更新
// parent是nullptr(cur是根结点)或者parent->_bf == 0时循环结束
while (parent)
{
// 插入在parent右结点,parent的_bf++
// 插入在parent左结点,parent的_bf--
if (cur == parent->_right) parent->_bf++;
else parent->_bf--;
// 更新parent平衡因子后,进行判断
// 继续向上更新/停止更新/旋转
if (parent->_bf == 0)
{
// 停止更新,也不必做任何调整
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
// 继续向上更新
cur = parent;
parent = cur->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
// 旋转
if (parent->_bf == -2 && cur->_bf == -1)
RotateR(parent);
else if (parent->_bf == -2 && cur->_bf == 1)
RotateLR(parent);
else if (parent->_bf == 2 && cur->_bf == 1)
RotateL(parent);
else if (parent->_bf == 2 && cur->_bf == -1)
RotateRL(parent);
else
assert(false);
break;
}
else
{
// 如果平衡因子的逻辑出错出现意料之外的值,就会直接报错
assert(false);
}
}
return true;
}
// 右单旋 rotate 旋转 right 右
void RotateR(Node* parent)
{
// 连接
Node* subL = parent->_left;
Node* subLR = subL->_right;
subL->_right = parent;
parent->_left = subLR;
// 更新平衡因子
subL->_bf = 0;
parent->_bf = 0;
// 更新_parent
subL->_parent = parent->_parent;
parent->_parent = subL;
if (subLR) subLR->_parent = parent;
// 根结点的情况
if (parent == _root) _root = subL;
// 非根结点 更新“看不见的”parent
else if (parent == subL->_parent->_left) subL->_parent->_left = subL;
else subL->_parent->_right = subL;
}
// 左单旋
void RotateL(Node* parent)
{
// 连接
Node* subR = parent->_right;
Node* subRL = subR->_left;
subR->_left = parent;
parent->_right = subRL;
// 更新平衡因子
subR->_bf = 0;
parent->_bf = 0;
// 更新_parent
subR->_parent = parent->_parent;
parent->_parent = subR;
if (subRL) subRL->_parent = parent;
// 根结点的情况
if (parent == _root) _root = subR;
// 非根结点 更新“看不见的”parent
else if (parent == subR->_parent->_left) subR->_parent->_left = subR;
else subR->_parent->_right = subR;
}
// 左右双旋
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(subL);
RotateR(parent);
if (bf == -1)
{
// 不是RotateL和RotateR中已经把subL和subLR的_bf置为0了吗,为什么还要这样写
// 减少函数之间的耦合度
subLR->_bf = 0;
subL->_bf = 0;
parent->_bf = 1;
}
else if (bf == 1)
{
subLR->_bf = 0;
subL->_bf = -1;
parent->_bf = 0;
}
else if (bf == 0)
{
subLR->_bf = 0;
subL->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
// 右左双旋
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(subR);
RotateL(parent);
if (bf == -1)
{
// 不是RotateL和RotateR中已经把subL和subLR的_bf置为0了吗,为什么还要这样写
// 减少函数之间的耦合度
subRL->_bf = 0;
subR->_bf = 1;
parent->_bf = 0;
}
else if (bf == 1)
{
subRL->_bf = 0;
subR->_bf = 0;
parent->_bf = -1;
}
else if (bf == 0)
{
subRL->_bf = 0;
subR->_bf = 0;
parent->_bf = 0;
}
else
{
assert(false);
}
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
int Height()
{
return _Height(_root);
}
int Size()
{
return _Size(_root);
}
bool IsBalanceTree()
{
return _IsBalanceTree(_root);
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
int _Size(Node* root)
{
if (root == nullptr)
return 0;
return _Size(root->_left) + _Size(root->_right) + 1;
}
bool _IsBalanceTree(Node* root)
{
// 空树也是AVL树
if (nullptr == root)
return true;
// 计算pRoot结点的平衡因子:即pRoot左右子树的高度差
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
int diff = rightHeight - leftHeight;
// 如果计算出的平衡因子与pRoot的平衡因子不相等
// 或者pRoot平衡因子的绝对值超过1,则一定不是AVL树
if (abs(diff) >= 2)
{
cout << root->_kv.first << "高度差异常" << endl;
return false;
}
if (root->_bf != diff)
{
cout << root->_kv.first << "平衡因子异常" << endl;
return false;
}
// pRoot的左和右如果都是AVL树,则该树一定是AVL树
return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
}
private:
Node* _root = nullptr;
};
// Test.cpp
#include<vector>
#include"AVLTree.h"
void TestAVLTree1()
{
AVLTree<int, int> t;
// 常规的测试用例
//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
// 特殊的带有双旋场景的测试用例
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
t.Insert({ e, e });
}
t.InOrder();
cout << t.IsBalanceTree() << endl;
}
// 插入一堆随机值,测试平衡,顺便测试一下高度和性能等
void TestAVLTree2()
{
const int N = 1000000;
vector<int> v;
v.reserve(N);
srand(time(0));
for (size_t i = 0; i < N; i++)
{
v.push_back(rand() + i);
}
size_t begin2 = clock();
AVLTree<int, int> t;
for (auto e : v)
{
t.Insert(make_pair(e, e));
}
size_t end2 = clock();
cout << "Insert:" << end2 - begin2 << endl;
cout << t.IsBalanceTree() << endl;
cout << "Height:" << t.Height() << endl;
cout << "Size:" << t.Size() << endl;
size_t begin1 = clock();
// 确定在的值
//for (auto e : v)
//{
// t.Find(e);
//}
// 随机值
for (size_t i = 0; i < N; i++)
{
t.Find((rand() + i));
}
size_t end1 = clock();
cout << "Find:" << end1 - begin1 << endl;
}
int main()
{
TestAVLTree2();
return 0;
}
okkkk,以上就是本博客的全部内容啦~
完结撒花~~~~~~~~~~~
໒( = ᴥ =)ʋ