• <AVL树>——《C++高阶》


    目录

    1.AVL树

    1.1AVL树的概念

    1.2 AVL树节点的定义

    1.3 AVL树的插入

    1.4 AVL树的旋转

    1. 新节点插入较高左子树的左侧---左左:右单旋​

     2. 新节点插入较高右子树的右侧---右右:左单旋​

    3. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋​

    4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋​

     1.5 AVL树的验证

    1.6 AVL树的删除(了解)

    1.7 AVL树的性能

    2.AVL树的实现:

    2.1功能函数:

    (1)定义AVL树的基本结构:​

    (2)Insert函数以及平衡因子bf的调整:​

    (3)左单旋RotateL:​

    (4)右单旋RotateR:​

    (5)左右双旋RotateLR:​ 

    (6)右左双旋RotateRL:​

    (7)遍历(递归版):

    (8)求树的高度:​

    (9)判断是否为平衡二叉树: 

    (10)测试用例:​

    2.2完整源码:

    (1)AVLTree.h:

    (2)test.cpp:

    2.3总结:

    后记:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!

                                                                           ——By 作者:新晓·故知


     

    1.AVL树

    1.1AVL树的概念

    二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年 发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的 绝对值 不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均 搜索长度。
    一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
    它的左右子树都是AVL树
    左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

    如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在
    O(log_2 n),搜索时间复杂度O(log_2 n)

    1.2 AVL树节点的定义

    AVL树节点的定义:
    1. template<class T>
    2. struct AVLTreeNode
    3. {
    4. AVLTreeNode(const T& data)
    5. : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
    6. , _data(data), _bf(0)
    7. {}
    8. AVLTreeNode* _pLeft;   // 该节点的左孩子
    9. AVLTreeNode* _pRight;  // 该节点的右孩子
    10. AVLTreeNode* _pParent; // 该节点的双亲
    11. T _data;
    12. int _bf;                  // 该节点的平衡因子
    13. };

     1.3 AVL树的插入

    AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么
    AVL树的插入过程可以分为两步:
    1. 按照二叉搜索树的方式插入新节点
    2. 调整节点的平衡因子
    1. bool Insert(const T& data)
    2. {
    3. // 1. 先按照二叉搜索树的规则将节点插入到AVL树中
    4. // ...
    5. // 2. 新节点插入后,AVL树的平衡性可能会遭到破坏,此时就需要更新平衡因子,并检测是否破坏了AVL树
    6. //   的平衡性
    7. /*
    8. pCur插入后,pParent的平衡因子一定需要调整,在插入之前,pParent
    9. 的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:
    10.  1. 如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可
    11.  2. 如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可
    12.  
    13. 此时:pParent的平衡因子可能有三种情况:0,正负1, 正负2
    14.  1. 如果pParent的平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整
    15. 成0,此时满足
    16.     AVL树的性质,插入成功
    17.  2. 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更
    18. 新成正负1,此
    19.     时以pParent为根的树的高度增加,需要继续向上更新
    20.  3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进
    21. 行旋转处理
    22. */
    23. while (pParent)
    24. {
    25. // 更新双亲的平衡因子
    26. if (pCur == pParent->_pLeft)
    27. pParent->_bf--;
    28. else
    29. pParent->_bf++;
    30. // 更新后检测双亲的平衡因子
    31. if (0 == pParent->_bf)
    32. {
    33. break;
    34. }
    35. else if (1 == pParent->_bf || -1 == pParent->_bf)
    36. {
    37. // 插入前双亲的平衡因子是0,插入后双亲的平衡因为为1 或者 -1 ,说明以双亲
    38. 为根的二叉树
    39. // 的高度增加了一层,因此需要继续向上调整
    40. pCur = pParent;
    41. pParent = pCur->_pParent;
    42. }
    43. else
    44. {
    45. // 双亲的平衡因子为正负2,违反了AVL树的平衡性,需要对以pParent
    46. // 为根的树进行旋转处理
    47. if (2 == pParent->_bf)
    48. {
    49. // ...
    50. }
    51. else
    52. {
    53. // ...
    54. }
    55. }
    56. }
    57. return true;
    58. }

    1.4 AVL树的旋转

    如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:

    1. 新节点插入较高左子树的左侧---左左:右单旋

    1. /*
    2.  上图在插入前,AVL树是平衡的,新节点插入到30的左子树(注意:此处不是左孩子)中,30左子树增加了一层,
    3. 导致以60为根的二叉树不平衡,要让60平衡,只能将60左子树的高度减少一层,右子树增加一层, 即将左子树往上提,
    4. 这样60转下来,因为60比30大,只能将其放在30的右子树,而如果30有 右子树,右子树根的值一定大于30,小于60,
    5. 只能将其放在60的左子树,旋转完成后,更新节点 的平衡因子即可。在旋转过程中,
    6. 有以下几种情况需要考虑:
    7. 1. 30节点的右孩子可能存在,也可能不存在
    8. 2. 60可能是根节点,也可能是子树
    9. 如果是根节点,旋转完成后,要更新根节点 如果是子树,
    10. 可能是某个节点的左子树,也可能是右子树
    11. 同学们再此处可举一些详细的例子进行画图,考虑各种情况,加深旋转的理解 */
    12. void _RotateR(PNode pParent)
    13. {
    14. // pSubL: pParent的左孩子
    15. // pSubLR: pParent左孩子的右孩子,注意:该
    16. PNode pSubL = pParent->_pLeft;
    17. PNode pSubLR = pSubL->_pRight;
    18. // 旋转完成之后,30的右孩子作为双亲的左孩子
    19. pParent->_pLeft = pSubLR;
    20. // 如果30的左孩子的右孩子存在,更新亲双亲
    21. if(pSubLR)
    22. pSubLR->_pParent = pParent;
    23. // 60 作为 30的右孩子
    24. pSubL->_pRight = pParent;
    25. // 因为60可能是棵子树,因此在更新其双亲前必须先保存60的双亲
    26. PNode pPParent = pParent->_pParent;
    27. // 更新60的双亲
    28. pParent->_pParent = pSubL;
    29. // 更新30的双亲
    30. pSubL->_pParent = pPParent;
    31. // 如果60是根节点,根新指向根节点的指针
    32. if (NULL == pPParent)
    33. {
    34. _pRoot = pSubL;
    35. pSubL->_pParent = NULL;
    36. }
    37. else
    38. {
    39. // 如果60是子树,可能是其双亲的左子树,也可能是右子树
    40. if (pPParent->_pLeft == pParent)
    41. pPParent->_pLeft = pSubL;
    42. else
    43. pPParent->_pRight = pSubL;
    44. }
    45. // 根据调整后的结构更新部分节点的平衡因子
    46. pParent->_bf = pSubL->_bf = 0;
    47. }

     2. 新节点插入较高右子树的右侧---右右:左单旋

    实现及情况考虑可参考右单旋。

    3. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋

    将双旋变成单旋后再旋转,即:先对30进行左单旋,然后再对90进行右单旋,旋转完成后再
    考虑平衡因子的更新。
    1. // 旋转之前,60的平衡因子可能是-1/0/1,旋转完成之后,根据情况对其他节点的平衡因子进行调整
    2. void _RotateLR(PNode pParent)
    3. {
    4. PNode pSubL = pParent->_pLeft;
    5. PNode pSubLR = pSubL->_pRight;
    6. // 旋转之前,保存pSubLR的平衡因子,旋转完成之后,需要根据该平衡因子来调整其他节
    7. 点的平衡因子
    8. int bf = pSubLR->_bf;
    9. // 先对30进行左单旋
    10. _RotateL(pParent->_pLeft);
    11. // 再对90进行右单旋
    12. _RotateR(pParent);
    13. if (1 == bf)
    14. pSubL->_bf = -1;
    15. else if (-1 == bf)
    16. pParent->_bf = 1;
    17. }

    4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

    参考右左双旋。
    总结:
    假如以pParent为根的子树不平衡,即pParent的平衡因子为2或者-2,分以下情况考虑
    1. pParent的平衡因子为2,说明pParent的右子树高,设pParent的右子树的根为pSubR
    当pSubR的平衡因子为1时,执行左单旋
    当pSubR的平衡因子为-1时,执行右左双旋
    2. pParent的平衡因子为-2,说明pParent的左子树高,设pParent的左子树的根为pSubL
    • 当pSubL的平衡因子为-1是,执行右单旋
    • 当pSubL的平衡因子为1时,执行左右双旋
    旋转完成后,原pParent为根的子树个高度降低,已经平衡,不需要再向上更新。

     1.5 AVL树的验证

    AVL树是在二叉搜索树的基础上加入了平衡性的限制,因此要验证AVL树,可以分两步:
    1. 验证其为二叉搜索树
    如果中序遍历可得到一个有序的序列,就说明为二叉搜索树
    2. 验证其为平衡树
    • 每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
    • 节点的平衡因子是否计算正确

    1. int _Height(PNode pRoot);
    2. bool _IsBalanceTree(PNode pRoot)
    3. {
    4. // 空树也是AVL树
    5. if (nullptr == pRoot) return true;
    6. // 计算pRoot节点的平衡因子:即pRoot左右子树的高度差
    7. int leftHeight = _Height(pRoot->_pLeft);
    8. int rightHeight = _Height(pRoot->_pRight);
    9. int diff = rightHeight - leftHeight;
    10. // 如果计算出的平衡因子与pRoot的平衡因子不相等,或者
    11. // pRoot平衡因子的绝对值超过1,则一定不是AVL树
    12. if (diff != pRoot->_bf || (diff > 1 || diff < -1))
    13. return false;
    14. // pRoot的左和右如果都是AVL树,则该树一定是AVL树
    15. return _IsBalanceTree(pRoot->_pLeft) && _IsBalanceTree(pRoot - > _pRight);
    16. }
    3. 验证用例
    结合上述代码按照以下的数据次序,自己动手画AVL树的创建过程,验证代码
    是否有漏洞。
    • 常规场景1
          {16, 3, 7, 11, 9, 26, 18, 14, 15}
    • 特殊场景2
          {4, 2, 6, 1, 3, 5, 15, 7, 16, 14}

    1.6 AVL树的删除(了解)

    因为AVL树也是二叉搜索树,可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不 错与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。
    具体实现可参考《算法导论》或《数据结构-用面向对象方法与C++描述》殷人昆版。

    1.7 AVL树的性能

    AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这 样可以保证查询时高效的时间复杂度,即$log_2 (N)$。但是如果要对AVL树做一些结构修改的操 作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时, 有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数 据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

    2.AVL树的实现:

    通过功能函数的模块化,然后进行封装,实现AVL的数据插入、遍历、树的高度求解、树的平衡判断。在插入数据的过程中,会涉及到树的结构的调整,这就需要借助平衡因子使得调整更加方便。

    2.1功能函数:

    (1)定义AVL树的基本结构:

    (2)Insert函数以及平衡因子bf的调整: (3)左单旋RotateL:

    (4)右单旋RotateR: 

    (5)左右双旋RotateLR: 

    (6)右左双旋RotateRL: (7)遍历(递归版):

     

    (8)求树的高度:

     

    (9)判断是否为平衡二叉树: 

    (10)测试用例: 

     

    2.2完整源码:

    (1)AVLTree.h:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. template<class K,class V>
    12. struct AVLTreeNode
    13. {
    14. pair _kv; //key<=>(pair*)->first value<=>(pair*)->second
    15. AVLTreeNode* _left;
    16. AVLTreeNode* _right;
    17. AVLTreeNode* _parent;
    18. int _bf; //balance factor 这里定义成右子树-左子树
    19. //AVL并无强制规定设计平衡因子,这里选择使用,方便控制平衡
    20. AVLTreeNode(const pair& kv)
    21. :_kv(kv)
    22. , _left(nullptr)
    23. , _right(nullptr)
    24. , _parent(nullptr)
    25. , _bf(0)
    26. {}
    27. };
    28. template<class K,class V>
    29. class AVLTree
    30. {
    31. typedef AVLTreeNode Node;
    32. public:
    33. //Find
    34. //Erase
    35. //插入数据
    36. bool Insert(const pair& kv)
    37. {
    38. //1.先按照搜索树的规则插入数据
    39. //2.判断是否遵循平衡规则,若违反,就旋转进行调整
    40. if (_root == nullptr)
    41. {
    42. _root = new Node(kv);
    43. _root->_bf = 0;
    44. return true;
    45. }
    46. Node* parent = nullptr;
    47. Node* cur = _root;
    48. while (cur)
    49. {
    50. if (cur->_kv.first < kv.first)
    51. {
    52. parent = cur;
    53. cur = cur->_right;
    54. }
    55. else if (cur->_kv.first > kv.first)
    56. {
    57. parent = cur;
    58. cur = cur->_left;
    59. }
    60. else
    61. {
    62. return false;
    63. }
    64. }
    65. cur = new Node(kv);
    66. if (parent->_kv.first < kv.first)
    67. {
    68. parent->_right = cur;
    69. }
    70. else
    71. {
    72. parent->_left = cur;
    73. }
    74. cur->_parent = parent;
    75. //更新平衡因子:
    76. //插入新结点后:
    77. //1.树的高度层次增加,要一直更新到根结点(_root)的bf
    78. //2.树的高度不变,只更新当前的parent的bf,就更新完成
    79. //3.更新完成后,若违反规则,处理旋转
    80. //注:更新bf,parent和cur也会更新
    81. //插入结点后,平衡因子的判断、更新
    82. while (parent)
    83. {
    84. //当前新插入这个结点的parent一定会更新,后面的需要进行判断
    85. if (cur == parent->_right)
    86. {
    87. parent->_bf++;
    88. }
    89. else
    90. {
    91. parent->_bf--;
    92. }
    93. // 是否继续更新?
    94. if (parent->_bf == 0) //原来的bf:1 or -1 -> 0 插入节点填上矮的那边
    95. {
    96. // 高度不变,更新结束
    97. break;
    98. }
    99. else if (parent->_bf == 1 || parent->_bf == -1)
    100. {
    101. // 原来的bf:0 -> 1 或 -1 插入节点导致一边变高了
    102. // 子树的高度变了,继续更新,这里更新后,parent也变了,后续是否更新要进行判断
    103. cur = cur->_parent;
    104. parent = parent->_parent;
    105. }
    106. else if (parent->_bf == 2 || parent->_bf == -2)
    107. {
    108. // -1 or 1 -> 2 或 -2 插入节点导致本来高一边又变高了
    109. // 子树不平衡 -- 需要旋转处理
    110. if (parent->_bf == 2 && cur->_bf == 1) // 左单旋
    111. {
    112. RotateL(parent);
    113. }
    114. else if (parent->_bf == -2 && cur->_bf == -1) // 右单旋
    115. {
    116. RotateR(parent);
    117. }
    118. else if (parent->_bf == -2 && cur->_bf == 1) // 左右双旋
    119. {
    120. RotateLR(parent);
    121. }
    122. else if (parent->_bf == 2 && cur->_bf == -1) // 右左双旋
    123. {
    124. RotateRL(parent);
    125. }
    126. break;
    127. }
    128. else
    129. {
    130. // 插入之前AVL就存在不平衡子树,|平衡因子| >= 2的节点
    131. assert(false);
    132. }
    133. }
    134. return true;
    135. }
    136. private:
    137. //1.右边高,向左单旋转
    138. void RotateL(Node* parent)
    139. {
    140. Node* subR = parent->_right;
    141. Node* subRL = subR->_left;
    142. parent->_right = subRL;
    143. if (subRL)
    144. subRL->_parent = parent;
    145. Node* ppNode = parent->_parent;
    146. subR->_left = parent;
    147. parent->_parent = subR;
    148. if (parent == _root)
    149. {
    150. _root = subR;
    151. _root->_parent = nullptr;
    152. }
    153. else
    154. {
    155. if (parent == ppNode->_left)
    156. {
    157. ppNode->_left = subR;
    158. }
    159. else
    160. {
    161. ppNode->_right = subR;
    162. }
    163. subR->_parent = ppNode;
    164. }
    165. // 更新平衡因子
    166. parent->_bf = 0;
    167. subR->_bf = 0;
    168. }
    169. //2.左边高,向右单旋转
    170. void RotateR(Node* parent)
    171. {
    172. Node* subL = parent->_left;
    173. Node* subLR = subL->_right;
    174. parent->_left = subLR;
    175. if (subLR)
    176. subLR->_parent = parent;
    177. Node* ppNode = parent->_parent;
    178. subL->_right = parent;
    179. parent->_parent = subL;
    180. if (parent == _root)
    181. {
    182. _root = subL;
    183. _root->_parent = nullptr;
    184. }
    185. else
    186. {
    187. if (ppNode->_left == parent)
    188. {
    189. ppNode->_left = subL;
    190. }
    191. else
    192. {
    193. ppNode->_right = subL;
    194. }
    195. subL->_parent = ppNode;
    196. }
    197. subL->_bf = parent->_bf = 0;
    198. }
    199. //3.左右双旋
    200. void RotateLR(Node* parent)
    201. {
    202. Node* subL = parent->_left;
    203. Node* subLR = subL->_right;
    204. int bf = subLR->_bf;
    205. RotateL(parent->_left);
    206. RotateR(parent);
    207. // 更新平衡因子
    208. if (bf == 0)
    209. {
    210. parent->_bf = 0;
    211. subL->_bf = 0;
    212. subLR->_bf = 0;
    213. }
    214. else if (bf == 1)
    215. {
    216. parent->_bf = 0;
    217. subL->_bf = -1;
    218. subLR->_bf = 0;
    219. }
    220. else if (bf == -1)
    221. {
    222. parent->_bf = 1;
    223. subL->_bf = 0;
    224. subLR->_bf = 0;
    225. }
    226. else
    227. {
    228. // subLR->_bf旋转前就有问题
    229. assert(false);
    230. }
    231. }
    232. //4.右左双旋
    233. void RotateRL(Node* parent)
    234. {
    235. Node* subR = parent->_right;
    236. Node* subRL = subR->_left;
    237. int bf = subRL->_bf;
    238. RotateR(parent->_right);
    239. RotateL(parent);
    240. if (bf == 0)
    241. {
    242. subRL->_bf = 0;
    243. parent->_bf = 0;
    244. subR->_bf = 0;
    245. }
    246. else if (bf == 1)
    247. {
    248. subRL->_bf = 0;
    249. parent->_bf = -1;
    250. subR->_bf = 0;
    251. }
    252. else if (bf == -1)
    253. {
    254. subRL->_bf = 0;
    255. parent->_bf = 0;
    256. subR->_bf = 1;
    257. }
    258. else
    259. {
    260. // subLR->_bf旋转前就有问题
    261. assert(false);
    262. }
    263. }
    264. //中序遍历(递归版)
    265. void _InOrder(Node* root)
    266. {
    267. if (root == nullptr)
    268. return;
    269. _InOrder(root->_left);
    270. cout << root->_kv.first << " ";
    271. _InOrder(root->_right);
    272. }
    273. //前序遍历(递归版)
    274. void _PrevOrder(Node* root)
    275. {
    276. if (root == nullptr)
    277. return;
    278. cout << root->_kv.first << " ";
    279. _PrevOrder(root->_left);
    280. _PrevOrder(root->_right);
    281. }
    282. //后序遍历(递归版)
    283. void _PostOrder(Node* root)
    284. {
    285. if (root == nullptr)
    286. return;
    287. _PostOrder(root->_left);
    288. _PostOrder(root->_right);
    289. cout << root->_kv.first << " ";
    290. }
    291. //求树的高度
    292. int _Height(Node* root)
    293. {
    294. if (root == nullptr)
    295. return 0;
    296. int lh = _Height(root->_left);
    297. int rh = _Height(root->_right);
    298. return lh > rh ? lh + 1 : rh + 1;
    299. }
    300. //判断是否为平衡树
    301. bool _IsBalanceTree(Node* root)
    302. {
    303. // 空树也是AVL树
    304. if (nullptr == root)
    305. return true;
    306. // 计算pRoot节点的平衡因子:即pRoot左右子树的高度差
    307. int leftHeight = _Height(root->_left);
    308. int rightHeight = _Height(root->_right);
    309. int diff = rightHeight - leftHeight;
    310. // 如果计算出的平衡因子与pRoot的平衡因子不相等,或者
    311. // pRoot平衡因子的绝对值超过1,则一定不是AVL树
    312. if (abs(diff) >= 2)
    313. {
    314. cout << root->_kv.first << "节点平衡因子异常!" << endl;
    315. return false;
    316. }
    317. if (diff != root->_bf)
    318. {
    319. cout << root->_kv.first << "节点平衡因子不符合实际!" << endl;
    320. return false;
    321. }
    322. // pRoot的左和右如果都是AVL树,则该树一定是AVL树
    323. return _IsBalanceTree(root->_left)
    324. && _IsBalanceTree(root->_right);
    325. }
    326. public:
    327. //1.中序遍历(递归版)
    328. void InOrder()
    329. {
    330. _InOrder(_root);
    331. cout << endl;
    332. }
    333. //2.前序遍历(递归版)
    334. void PrevOrder()
    335. {
    336. _PrevOrder(_root);
    337. cout << endl;
    338. }
    339. //3.后序序遍历(递归版)
    340. void PostOrder()
    341. {
    342. _PostOrder(_root);
    343. cout << endl;
    344. }
    345. //4.层序遍历
    346. vectorint>> levelOrder()
    347. {
    348. vectorint>> vv;
    349. if (_root == nullptr)
    350. return vv;
    351. queue q;
    352. int levelSize = 1;
    353. q.push(_root);
    354. while (!q.empty())
    355. {
    356. // levelSize控制一层一层出
    357. vector<int> levelV;
    358. while (levelSize--)
    359. {
    360. Node* front = q.front();
    361. q.pop();
    362. levelV.push_back(front->_kv.first);
    363. if (front->_left)
    364. q.push(front->_left);
    365. if (front->_right)
    366. q.push(front->_right);
    367. }
    368. vv.push_back(levelV);
    369. for (auto e : levelV)
    370. {
    371. cout << e << " ";
    372. }
    373. cout << endl;
    374. // 上一层出完,下一层就都进队列
    375. levelSize = q.size();
    376. }
    377. return vv;
    378. }
    379. bool IsBalanceTree()
    380. {
    381. return _IsBalanceTree(_root);
    382. }
    383. int Height()
    384. {
    385. return _Height(_root);
    386. }
    387. private:
    388. Node* _root = nullptr;
    389. };

    (2)test.cpp:

    1. #include"AVLTree.h"
    2. void TestAVLTree1()
    3. {
    4. AVLTree<int, int> t;
    5. t.Insert(make_pair(1, 1));
    6. t.Insert(make_pair(2, 2));
    7. t.Insert(make_pair(4, 3));
    8. t.Insert(make_pair(4, 4));
    9. }
    10. void TestAVLTree2()
    11. {
    12. int a[] = { 5,3,7,1,4,6,8,0,2,9 };
    13. AVLTree<int, int> t;
    14. for (auto e : a)
    15. {
    16. t.Insert(make_pair(e, e));
    17. }
    18. cout << endl;
    19. t.levelOrder();
    20. t.Insert(make_pair(10,10));
    21. t.Insert(make_pair(11,11));
    22. t.levelOrder();
    23. }
    24. void TestAVLTree3()
    25. {
    26. //使用随机值测试
    27. const size_t N = 100;
    28. vector<int> v;
    29. v.reserve(N);
    30. srand(time(0));
    31. for (size_t i = 0; i < N; ++i)
    32. {
    33. v.push_back(rand());
    34. }
    35. AVLTree<int, int> t;
    36. for (auto e : v)
    37. {
    38. t.Insert(make_pair(e, e));
    39. }
    40. t.levelOrder();
    41. cout << endl;
    42. }
    43. void TestAVLTree4()
    44. {
    45. //使用有序测试
    46. const size_t N = 20; //测试N个数据
    47. vector<int> v;
    48. v.reserve(N);
    49. srand(time(0));
    50. for (size_t i = 0; i < N; ++i)
    51. {
    52. //v.push_back(rand());
    53. v.push_back(i);
    54. }
    55. AVLTree<int, int> t;
    56. for (auto e : v)
    57. {
    58. t.Insert(make_pair(e, e));
    59. }
    60. //t.levelOrder();
    61. //t.InOrder();
    62. //t.PrevOrder();
    63. //t.PostOrder();
    64. cout << "是否平衡?(返回值1代表是,返回值0代表不是):" << t.IsBalanceTree() << endl;
    65. cout << "高度:" << t.Height() << endl;
    66. cout << endl;
    67. }
    68. void TestAVLTree5()
    69. {
    70. int a[] = { 5,3,7,1,4,6,8,0,2,9 };
    71. //int a[] = {0,1,2,3,4,5,6,7,8,9 };
    72. //int a[] = { 1,1,1,1,1,1,1,1,1 };
    73. AVLTree<int, int> t;
    74. for (auto e : a)
    75. {
    76. t.Insert(make_pair(e, e));
    77. }
    78. t.levelOrder();
    79. cout << "是否为平衡树?(1:是 0:不是):" << t.IsBalanceTree() << endl;
    80. cout << "树的高度:" << t.Height() << endl;
    81. cout << endl;
    82. t.Insert(make_pair(10, 10));
    83. t.Insert(make_pair(11, 11));
    84. t.levelOrder();
    85. cout << endl;
    86. //t.InOrder();
    87. //t.PrevOrder();
    88. //t.PostOrder();
    89. cout << "是否为平衡树?(1:是 0:不是):" << t.IsBalanceTree() << endl;
    90. cout << "树的高度:" << t.Height() << endl;
    91. cout << endl;
    92. }
    93. int main()
    94. {
    95. //TestAVLTree1();
    96. //TestAVLTree2();
    97. TestAVLTree3();
    98. //TestAVLTree4();
    99. //TestAVLTree5();
    100. return 0;
    101. }

    2.3总结:

    通过上述过程,实现了对Insert过程中对二叉树调整、判断等。而AVL树还有Find、Erase等操作,由于难度较大,具体实现可参考教材或其他资料。

    这里的AVL借助了平衡因子使得二叉树结构的判断以及调整更加方便,遇到难以理解的过程要画图分析或编译器调试。

    后记:
    ●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!

                                                                           ——By 作者:新晓·故知

  • 相关阅读:
    程序员如何运营好博客平台
    Unity优化(1)——合并Mesh
    系统运维(零):安装系统时挂载点设置不当导致的麻烦
    Ceph文件系统
    windows服务器证书算法升级
    WPF handyControl 学习样例
    Android的PendingIntent.getBroadcast()PendingIntent.FLAG_IMMUTABLE问题
    独立产品灵感周刊 DecoHack #039 - 制作自己的音乐墙
    Vue - 列表拖曳排序 / 鼠标拖动改变顺序排列高效简洁组件(支持PC端与移动端触屏拖动,也可在滚动条内排序自动滚动,流畅丝滑无 BUG)
    CSS中去掉li前面的圆点方法
  • 原文地址:https://blog.csdn.net/m0_57859086/article/details/126306455