• C++:AVL树


    目录

    一.AVL树介绍

    1.AVL树的概念

    2.AVL树性质

    平衡因子:左右子树高度之差

    3.为什么设计高度差不超过1?

    4.AVL相比满二叉树:

    5.AVL树图例

    二.模拟实现AVL树

    阶段一:左单旋

    阶段二:右单旋 

    三:左右双旋

    1.先左后右

    2.先右后左 双旋:

    情况1: 

    情况2:

    AVL树总代码:


     

     

    一.AVL树介绍

    1.AVL树的概念

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

    2.AVL性质

    一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
    它的左右子树都是 AVL
    左右子树高度之差 ( 简称平衡因子 ) 的绝对值不超过1(-1/0/1)(即:树中任何一个子树高度差都不超过1)

    078b3e1a5d6f4403b86a91b57297009e.png

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

    平衡因子左右子树高度之差

    平衡因子不是必须要维护的,在操作时也可以直接通过高度函数来算,只不过比较麻烦

    3.为什么设计高度差不超过1?

    只有满二叉树才能保证每个子树高度差是0(2^h-1)
    做不到相等,退而求其次,左右高度差不超过1

    4.AVL相比满二叉树:

    完全二叉树:最后一层缺一些节点
    AVL二叉树:最后两层缺一些节点

    5.AVL树图

    8d1598ea5d474046aaafe711526b9e4f.png

    二.模拟实现AVL树

    c20c271fa8a74704b335d973ef557f33.png

    阶段一:左单旋

    右边高--左旋转
    旋转原则:
    1、保持搜索树的规则
    2、子树变平衡

    左单旋的条件:(30)parent->_bf = 2,(60)subR->_bf = 1   (_bf是平衡因子,subR是parent的右孩子)

    左单旋规则:对30进行左单旋,60必须是30的右支,父亲30是儿子60的左支就是左旋,右支就是右旋(如果在b下加子节点 就等价 先右后左双旋的情况2了,图在下面)

    左单旋:(右边高)在c下插入一个节点时,把b给根30右节点,再把30给60的左节点。

     

    27854139de3b43b4a8c52d6a87b21c0a.png

     

    30这棵树可能是局部的子树,上面还有根节点ppNode,更新完30开始的这颗子树的平衡因子后不必再向上更新,因为30为根的这个树旋转前高度是h+2(30,60,h),旋转后高度还是h+2 没变

    7186070b04e94ac79bd7a4afcb83f1e3.png
    0e964a0620634840af80b9d0e94212af.png

    (如果在b下加子节点 就等价 先右后左双旋的情况2了

    dbed78404e534eb4b4d072042b95b9ae.png

     

     20f934a46ed34ffeafbcdf9da2e5e19a.png

     

     

     

    1. #pragma once
    2. template<class K, class V>
    3. struct AVLTreeNode
    4. {
    5. pair _kv;
    6. AVLTreeNode* _left;
    7. AVLTreeNode* _right;
    8. AVLTreeNode* _parent;
    9. // 右子树-左子树的高度差
    10. int _bf; // balance factor
    11. AVLTreeNode(const pair& kv)
    12. :_kv(kv)
    13. , _left(nullptr)
    14. , _right(nullptr)
    15. , _parent(nullptr)
    16. , _bf(0)
    17. {}
    18. // AVL树并没有规定必须要设计平衡因子
    19. // 只是一个实现的选择,方便控制平衡
    20. };
    21. template<class K, class V>
    22. class AVLTree
    23. {
    24. typedef AVLTreeNode Node;
    25. public:
    26. bool Insert(const pair& kv)
    27. {
    28. // 1、搜索树的规则插入
    29. // 2、看是否违反平衡规则,如果违反就需要处理:旋转
    30. if (_root == nullptr)
    31. {
    32. _root = new Node(kv);
    33. _root->_bf = 0;
    34. return true;
    35. }
    36. Node* parent = nullptr;
    37. Node* cur = _root;
    38. while (cur)
    39. {
    40. if (cur->_kv.first < kv.first)
    41. {
    42. parent = cur;
    43. cur = cur->_right;
    44. }
    45. else if (cur->_kv.first > kv.first)
    46. {
    47. parent = cur;
    48. cur = cur->_left;
    49. }
    50. else
    51. {
    52. return false;
    53. }
    54. }
    55. cur = new Node(kv);
    56. if (parent->_kv.first < kv.first)
    57. {
    58. parent->_right = cur;
    59. }
    60. else
    61. {
    62. parent->_left = cur;
    63. }
    64. cur->_parent = parent;
    65. // ...
    66. // 更新平衡因子
    67. while (parent) // 最远要更新根
    68. {
    69. if (cur == parent->_right)
    70. {
    71. parent->_bf++;
    72. }
    73. else
    74. {
    75. parent->_bf--;
    76. }
    77. // 是否继续更新?
    78. if (parent->_bf == 0) // 1 or -1 -》 0 插入节点填上矮的那边
    79. {
    80. // 高度不变,更新结束
    81. break;
    82. }
    83. else if (parent->_bf == 1 || parent->_bf == -1)
    84. // 0 -》 1 或 -1 插入节点导致一边变高了
    85. {
    86. // 子树的高度变了,继续更新祖先
    87. cur = cur->_parent;
    88. parent = parent->_parent;
    89. }
    90. else if (parent->_bf == 2 || parent->_bf == -2)
    91. // -1 or 1 -》 2 或 -2 插入节点导致本来高一边又变高了
    92. {
    93. // 子树不平衡 -- 需要旋转处理
    94. // ...
    95. }
    96. else
    97. {
    98. // 插入之前AVL就存在不平衡子树,|平衡因子| >= 2的节点
    99. assert(false);
    100. }
    101. }
    102. return true;
    103. }
    104. private:
    105. void RotateL(Node* parent)
    106. {
    107. Node* subR = parent->_right;
    108. Node* subRL = subR->_left;
    109. parent->_right = subRL;
    110. if (subRL)
    111. subRL->_parent = parent;
    112. Node* ppNode = parent->_parent;
    113. subR->_left = parent;
    114. parent->_parent = subR;
    115. if (parent == _root)
    116. {
    117. _root = subR;
    118. _root->_parent = nullptr;
    119. }
    120. else
    121. {
    122. if (parent == ppNode->_left)
    123. {
    124. ppNode->_left = subR;
    125. }
    126. else
    127. {
    128. ppNode->_right = subR;
    129. }
    130. subR->_parent = ppNode;
    131. }
    132. }
    133. private:
    134. Node* _root = nullptr;
    135. };
    136. void TestAVLTree()
    137. {
    138. AVLTree<int, int> t;
    139. t.Insert(make_pair(1, 1));
    140. t.Insert(make_pair(2, 2));
    141. t.Insert(make_pair(3, 3));
    142. }

    阶段二:右单旋 

    右单旋的条件:(60)parent->_bf = -2,(60)subL->_bf = -1

    动的就是parent 60,subL 30,subLR b

    c39add27f71649219e7de83aafcda7b3.png

     

    示例:

     

    代码:

    1. void RotateR(Node* parent)
    2. {
    3. Node* subL = parent->_left;
    4. Node* subLR = subL->_right;
    5. parent->_left = subLR;
    6. if (subLR)
    7. subLR->_parent = parent;
    8. Node* ppNode = parent->_parent;
    9. subL->_right = parent;
    10. parent->_parent = subL;
    11. if (parent == _root)
    12. {
    13. _root = subL;
    14. _root->_parent = nullptr;
    15. }
    16. else
    17. {
    18. if (ppNode->_left == parent)
    19. {
    20. ppNode->_left = subL;
    21. }
    22. else
    23. {
    24. ppNode->_right = subL;
    25. }
    26. subL->_parent = ppNode;
    27. }
    28. subL->_bf = parent->_bf = 0;
    29. }

    三:左右双旋

    1.先左后右

    AVL树的双旋转使用对应的单旋转后还要更新平衡因子

    先左后右双旋的条件:parent->_bf = -2,subL->_bf = 1,不用管subLR是几

    树 h>=1

    相当于是把60的左给30的右,把60的右给90的左,30,90作左右子树,60再做根节点

    90f6a1457b7849bca243f60a922b0027.png

     

    h==0,先左后右 双旋最简单的情况

    66dcaff4d6e84b8cb94d9694273ec385.png

     

     

    361d290a99124248a77039ffafbdfa3d.png

     

    2.先右后左 双旋:

    先右后左双旋的条件:parent->_bf = 2,subR->_bf = -1,不用管subRL是几

    情况1: 

    f60f3f0b18514e119c8ffb3aa8ab6747.png

    情况2:

    a16b942b0d99417683d36fa1953cb72b.png

     

     

    AVL树总代码:

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

     

     

     

     

  • 相关阅读:
    Java 字符流案例_集合与文件内容的相互转化(升级版)
    软件测试学习路线
    【计算机网络微课堂】5.8 TCP的运输连接管理
    常见的ssh功能
    为什么资源管理对现代企业很重要?
    【MySQL基础】MySQL常用的图形化管理工具有那些?
    微信小程序 原生开发 实现弹窗遮罩层 并且在遮罩层内使用scroll-view实现滚动内容(包括图片)
    掌握 Git:代码版本控制的基本步骤(强力推荐的工具)
    Python教程之字典(Dictionary)操作详解
    有哪些不起眼却赚钱的行业?
  • 原文地址:https://blog.csdn.net/zhang_si_hang/article/details/126419169