当前位置:   article > 正文

AVL数的实现(C++)_avl c++

avl c++

二叉搜索树虽然可以加快查找效率,但当数据有序或接近有序时,二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

一颗AVL树或是空树,或是具有以下性质的二叉搜索树:

  • 它的左右子树都是AVL数
  • 它的左右子树高度之差(简称平衡因子)的绝对值不超过1可以取-1、0、1

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

AVL数的插入

AVL树是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。AVL树的插入过程可以分两步:

1.按照二叉搜索树的方式插入新结点。

1)如果树的根为空,新创建一个结点作为树的根,返回true。

2)如果树不为空,从根结点开始比较将要插入结点的值key和当前结点值cur->_key的大小。如果key<cur->_key,到当前结点的左子树去找;如果key>cur->_key,到当前结点的右子树去找;如果key==cur->_key,说明该树中有和新结点值相同的结点,就不插入了,返回false。按照此思路循环查找,直到当前结点为空,结束循环。此时parent为叶子结点。

3)插入新结点:新结点一定插入在parent的左侧或右侧。

2.调节结点的平衡因子。

新结点插入后,AVL树的平衡性可能遭到破坏,此时就需要更新平衡因子,并检查是否破坏了AVL树的平衡性。

当新结点cur插入后,parent的平衡因子一定需要调整。在插入结点之前,parent的平衡因子分为-1,0,1三种情况。

调节平衡因子
        1)如果cur插入到parent的左侧,给parent的平衡因子-1;
        2)如果cur插入到parent的右侧,给parent的平衡因子+1
        此时parent的平衡因子可能是:0、正负1、正负2
        如果parent的平衡因子是0,说明插入之前parent的平衡因子为正负1,插入后被调整成0,此时满足AVL数的性质,插入成功。
        如果parent的平衡因子是正负1,说明插入前parent的平衡因子一定为0,插入后更新成正负1,此时以parent为根的树的高度增加,需要继续向上更新。
        如果parent的平衡因子为正负2,则parent的平衡因子违反了平衡树的性质,需要对其进行旋转处理,以降低高度。

AVL树的旋转

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

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

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

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

AVL树的插入完整代码:

  1. bool Insert(const K& key,const V& value)
  2. {
  3. //如果树为空,插入新结点
  4. if (_root == nullptr)
  5. {
  6. _root = new Node(key,value);
  7. return true;
  8. }
  9. //按照二叉搜索树的性质找到要插入的位置
  10. Node* cur = _root;
  11. Node* parent = nullptr;
  12. while (cur)
  13. {
  14. if (key < cur->_key)
  15. {
  16. parent = cur;
  17. cur = cur->_left;
  18. }
  19. else if (key > cur->_key)
  20. {
  21. parent = cur;
  22. cur = cur->_right;
  23. }
  24. else
  25. {
  26. return false;
  27. }
  28. }
  29. //插入新结点
  30. cur = new Node(key,value);
  31. if (key < parent->_key)
  32. {
  33. parent->_left = cur;
  34. }
  35. else
  36. {
  37. parent->_right = cur;
  38. }
  39. while (parent)
  40. {
  41. //更新父亲的平衡因子
  42. if (cur == parent->_left)
  43. {
  44. parent->_bf--;
  45. }
  46. else
  47. {
  48. parent->_bf++;
  49. }
  50. //更新后检查父亲的平衡
  51. if (parent->_bf == 0)
  52. {
  53. break;
  54. }
  55. else if (abs(parent->_bf) == 1)
  56. {
  57. //向上更新
  58. cur = parent;
  59. parent = parent->_parent;
  60. }
  61. else if (abs(parent->_bf) == 2)
  62. {
  63. //插入新结点后,AVL数的平衡性遭到破坏,需要对以parent为根的树进行旋转处理
  64. if (parent->_bf == -2 && cur->_bf == -1)
  65. {
  66. RotateR(parent);
  67. }
  68. else if (parent->_bf == 2 && cur->_bf == 1)
  69. {
  70. RotateL(parent);
  71. }
  72. else if (parent->_bf == -2 && cur->_bf == 1)//左右双旋
  73. {
  74. RotateLR(parent);
  75. }
  76. else if (parent->_bf == 2 && cur->_bf == -1)//右左双旋
  77. {
  78. RotateRL(parent);
  79. }
  80. break;
  81. }
  82. else
  83. {
  84. assert(false);
  85. }
  86. }
  87. return true;
  88. }
  89. void RotateLR(Node* parent)
  90. {
  91. Node* subL = parent->_left;
  92. Node* subLR = subL->_right;
  93. int bf = subLR->_bf;
  94. RotateL(parent->_left);
  95. RotateR(parent);
  96. if (bf == -1)
  97. {
  98. parent->_bf = 1;
  99. subL->_bf = 0;
  100. }
  101. else if (bf == 1)
  102. {
  103. parent->_bf = 0;
  104. subL->_bf = -1;
  105. }
  106. else
  107. {
  108. parent->_bf = subL->_bf = 0;
  109. }
  110. subLR->_bf = 0;
  111. }
  112. void RotateRL(Node* parent)
  113. {
  114. Node* subR = parent->_right;
  115. Node* subRL = subR->_left;
  116. int bf = subRL->_bf;
  117. RotateR(parent->_right);
  118. RotateL(parent);
  119. if (bf == -1)
  120. {
  121. parent->_bf = 0;
  122. subR->_bf = 1;
  123. }
  124. else if (bf == 1)
  125. {
  126. parent->_bf = -1;
  127. subR->_bf = 0;
  128. }
  129. else
  130. {
  131. parent->_bf = subR->_bf = 0;
  132. }
  133. subRL->_bf = 0;
  134. }
  135. void RotateL(Node* parent)
  136. {
  137. Node* subR = parent->_right;
  138. Node* subRL = subR->_left;
  139. parent->_right = subRL;
  140. if (subRL)
  141. {
  142. subRL->_parent = parent;
  143. }
  144. subR->_left = parent;
  145. Node* pparent = parent->_parent;
  146. parent->_parent = subR;
  147. if (parent == _root)
  148. {
  149. _root = subR;
  150. }
  151. else
  152. {
  153. if (pparent->_left == parent)
  154. {
  155. pparent->_left = subR;
  156. }
  157. else
  158. {
  159. pparent->_right = subR;
  160. }
  161. }
  162. subR->_parent = pparent;
  163. subR->_bf = parent->_bf = 0;
  164. }
  165. void RotateR(Node* parent)
  166. {
  167. Node* subL = parent->_left;
  168. Node* subLR = subL->_right;
  169. parent->_left = subLR;
  170. if (subLR)
  171. {
  172. subLR->_parent = parent;
  173. }
  174. subL->_right = parent;
  175. Node* pparent = parent->_parent;
  176. parent->_parent = subL;
  177. if (parent == _root)
  178. {
  179. _root = subL;
  180. }
  181. else
  182. {
  183. if (pparent->_left = parent)
  184. {
  185. pparent->_left = subL;
  186. }
  187. else
  188. {
  189. pparent->_right = subL;
  190. }
  191. }
  192. subL->_parent = pparent;
  193. subL->_bf = parent->_bf = 0;
  194. }

AVL树的验证

1.验证其为二叉搜索树

如果中序遍历可以得到一个有序的序列,说明其为二叉搜索树。

2.验证其为平衡树

  • 每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子) 。
  • 节点的平衡因子是否计算正确。

 AVL树从构建到验证的完整代码

  1. #pragma once
  2. #include<iostream>
  3. #include<assert.h>
  4. using namespace std;
  5. template<class K,class V>
  6. struct AVLTreeNode
  7. {
  8. AVLTreeNode<K, V>* _left;
  9. AVLTreeNode<K, V>* _right;
  10. AVLTreeNode<K, V>* _parent;
  11. K _key;
  12. V _value;
  13. int _bf;
  14. AVLTreeNode(const K& key,const V& value)
  15. : _left(nullptr)
  16. , _right(nullptr)
  17. , _parent(nullptr)
  18. , _key(key)
  19. , _value(value)
  20. , _bf(0)
  21. {}
  22. };
  23. template<class K,class V>
  24. class AVLTree
  25. {
  26. typedef AVLTreeNode<K,V> Node;
  27. public:
  28. AVLTree()
  29. : _root(nullptr)
  30. {}
  31. ~AVLTree()
  32. {
  33. Destroy(_root);
  34. _root = nullptr;
  35. }
  36. bool Insert(const K& key,const V& value)
  37. {
  38. //如果树为空,插入新结点
  39. if (_root == nullptr)
  40. {
  41. _root = new Node(key,value);
  42. return true;
  43. }
  44. //按照二叉搜索树的性质找到要插入的位置
  45. Node* cur = _root;
  46. Node* parent = nullptr;
  47. while (cur)
  48. {
  49. if (key < cur->_key)
  50. {
  51. parent = cur;
  52. cur = cur->_left;
  53. }
  54. else if (key > cur->_key)
  55. {
  56. parent = cur;
  57. cur = cur->_right;
  58. }
  59. else
  60. {
  61. return false;
  62. }
  63. }
  64. //插入新结点
  65. cur = new Node(key,value);
  66. if (key < parent->_key)
  67. {
  68. parent->_left = cur;
  69. }
  70. else
  71. {
  72. parent->_right = cur;
  73. }
  74. //更新cur的父亲结点
  75. cur->_parent = parent;
  76. //插入新结点后,AVL树的平衡性可能遭到破坏,此时需要更新平衡因子,并检查是否破坏了AVL树的平衡性
  77. while (parent)
  78. {
  79. //更新父亲的平衡因子
  80. if (cur == parent->_left)
  81. {
  82. parent->_bf--;
  83. }
  84. else
  85. {
  86. parent->_bf++;
  87. }
  88. //更新后检查父亲的平衡
  89. if (parent->_bf == 0)
  90. {
  91. break;
  92. }
  93. else if (abs(parent->_bf) == 1)
  94. {
  95. //向上更新
  96. cur = parent;
  97. parent = parent->_parent;
  98. }
  99. else if (abs(parent->_bf) == 2)
  100. {
  101. //插入新结点后,AVL数的平衡性遭到破坏,需要对以parent为根的树进行旋转处理
  102. if (parent->_bf == -2 && cur->_bf == -1)
  103. {
  104. RotateR(parent);
  105. }
  106. else if (parent->_bf == 2 && cur->_bf == 1)
  107. {
  108. RotateL(parent);
  109. }
  110. else if (parent->_bf == -2 && cur->_bf == 1)//左右双旋
  111. {
  112. RotateLR(parent);
  113. }
  114. else if (parent->_bf == 2 && cur->_bf == -1)//右左双旋
  115. {
  116. RotateRL(parent);
  117. }
  118. break;
  119. }
  120. else
  121. {
  122. assert(false);
  123. }
  124. }
  125. return true;
  126. }
  127. void RotateLR(Node* parent)
  128. {
  129. Node* subL = parent->_left;
  130. Node* subLR = subL->_right;
  131. int bf = subLR->_bf;
  132. RotateL(parent->_left);
  133. RotateR(parent);
  134. if (bf == -1)
  135. {
  136. parent->_bf = 1;
  137. subL->_bf = 0;
  138. }
  139. else if (bf == 1)
  140. {
  141. parent->_bf = 0;
  142. subL->_bf = -1;
  143. }
  144. else
  145. {
  146. parent->_bf = subL->_bf = 0;
  147. }
  148. subLR->_bf = 0;
  149. }
  150. void RotateRL(Node* parent)
  151. {
  152. Node* subR = parent->_right;
  153. Node* subRL = subR->_left;
  154. int bf = subRL->_bf;
  155. RotateR(parent->_right);
  156. RotateL(parent);
  157. if (bf == -1)
  158. {
  159. parent->_bf = 0;
  160. subR->_bf = 1;
  161. }
  162. else if (bf == 1)
  163. {
  164. parent->_bf = -1;
  165. subR->_bf = 0;
  166. }
  167. else
  168. {
  169. parent->_bf = subR->_bf = 0;
  170. }
  171. subRL->_bf = 0;
  172. }
  173. void RotateL(Node* parent)
  174. {
  175. Node* subR = parent->_right;
  176. Node* subRL = subR->_left;
  177. parent->_right = subRL;
  178. if (subRL)
  179. {
  180. subRL->_parent = parent;
  181. }
  182. subR->_left = parent;
  183. Node* pparent = parent->_parent;
  184. parent->_parent = subR;
  185. if (parent == _root)
  186. {
  187. _root = subR;
  188. }
  189. else
  190. {
  191. if (pparent->_left == parent)
  192. {
  193. pparent->_left = subR;
  194. }
  195. else
  196. {
  197. pparent->_right = subR;
  198. }
  199. }
  200. subR->_parent = pparent;
  201. subR->_bf = parent->_bf = 0;
  202. }
  203. void RotateR(Node* parent)
  204. {
  205. Node* subL = parent->_left;
  206. Node* subLR = subL->_right;
  207. parent->_left = subLR;
  208. if (subLR)
  209. {
  210. subLR->_parent = parent;
  211. }
  212. subL->_right = parent;
  213. Node* pparent = parent->_parent;
  214. parent->_parent = subL;
  215. if (parent == _root)
  216. {
  217. _root = subL;
  218. }
  219. else
  220. {
  221. if (pparent->_left = parent)
  222. {
  223. pparent->_left = subL;
  224. }
  225. else
  226. {
  227. pparent->_right = subL;
  228. }
  229. }
  230. subL->_parent = pparent;
  231. subL->_bf = parent->_bf = 0;
  232. }
  233. void Inorder()
  234. {
  235. _Inorder(_root);
  236. cout << endl;
  237. }
  238. void Height()
  239. {
  240. cout << _Height(_root) << endl;
  241. }
  242. bool IsBalanceTree()
  243. {
  244. return _IsBalanceTree(_root);
  245. }
  246. int _Height(Node* root)
  247. {
  248. if (root == nullptr)
  249. return 0;
  250. int leftHeight = _Height(root->_left);
  251. int rightHeight = _Height(root->_right);
  252. return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
  253. }
  254. bool _IsBalanceTree(Node* root)
  255. {
  256. if (_root == nullptr)
  257. return true;
  258. int leftHeight = _Height(root->_left);
  259. int rightHeight = _Height(root->_right);
  260. if (abs(leftHeight - rightHeight) > 2 || (leftHeight - rightHeight) != root->_bf)
  261. {
  262. cout << " 平衡因子错误" << endl;
  263. return false;
  264. }
  265. return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
  266. }
  267. private:
  268. void Destroy(Node* root)
  269. {
  270. if (root)
  271. {
  272. Destroy(root->_left);
  273. Destroy(root->_right);
  274. delete root;
  275. }
  276. }
  277. void _Inorder(Node* root)
  278. {
  279. if (root == nullptr)
  280. return;
  281. _Inorder(root->_left);
  282. cout << root->_key << " ";
  283. _Inorder(root->_right);
  284. }
  285. Node* _root;
  286. };
  287. void TestAVLTree()
  288. {
  289. AVLTree<int,int> tree;
  290. int arr[] = { 26, 18, 14, 5, 3 };
  291. for (auto& e : arr)
  292. {
  293. tree.Insert(e,e);
  294. }
  295. tree.Inorder();
  296. tree.Height();
  297. tree.IsBalanceTree();
  298. }

AVL树的性能

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/511580
推荐阅读
相关标签
  

闽ICP备14008679号