c++|【C++篇】AVL树

系列文章目录 准备 【c++|【C++篇】AVL树】博主:大大怪先森(记得关注哦!)
编程环境:vs2013
所示代码:码源


文章目录

  • 系列文章目录
  • 准备
  • 前言
  • 一、AVL树的概念
  • 二、AVL的实现
    • 1.插入代码实现
    • 2.旋转图解
  • 三、AVL树的删除(了解)
  • 四、 AVL树性能
  • 总结

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

    如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 ,搜索时间复杂度O(log2 ^n )。
二、AVL的实现 1.插入代码实现 代码如下
#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include templatestruct AVLTreeNode { AVLTreeNode* _left; AVLTreeNode* _right; AVLTreeNode* _parent; pair _kv; int _bf; //平衡因子 balance factor AVLTreeNode(const pair& kv) :_left(nullptr) ,_right(nullptr) ,_parent(nullptr) ,_kv(kv) ,_bf(0) {} }; template class AVLTree { typedef AVLTreeNode Node; public: AVLTree() :_root(nullptr) {} bool Insert(const pair& kv) { if (_root == nullptr) { _root = new Node(kv); return true; }Node* parent = nullptr; Node* cur = _root; 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; }} //找到了插入节点,这里一定要注意如果parent没有左右孩子的时候这里 //插入的时候就需要注意是否插入的位置是左孩子还是右孩子 cur = new Node(kv); if (parent->_kv.first < kv.first) { parent->_right = cur; cur->_parent = parent; } else { parent->_left = cur; cur->_parent = parent; } //插入之后开始控制平衡因子 while (parent) { if (cur == parent->_left)///奶奶滴一个符号,我丢 parent->_bf--; else parent->_bf++; if (parent->_bf == 0) { break; } else if (parent->_bf == 1 || parent->_bf == -1) { //这里就需要向上调整 cur = parent; parent = parent->_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) { //左单旋 RotateL(parent); } else if (parent->_bf == -2 && cur->_bf == 1) { RotateLR(parent); } else if (parent->_bf == 2 && cur->_bf == -1) { //右左双旋 RotateRL(parent); } break; } } return true; } void RotateR(Node* parent) { Node* SubL = parent->_left; Node* SubLR = SubL->_right; parent->_left = SubLR; if (SubLR) { SubLR->_parent = parent; } Node* parentParent = parent->_parent; SubL->_right = parent; parent->_parent = SubL; if (parent == _root) { _root = SubL; _root->_parent = nullptr; } else { if (parentParent->_left == parent) { parentParent->_left = SubL; } else { parentParent->_right = SubL; } SubL->_parent = parentParent; } SubL->_bf = parent->_bf = 0; } void RotateL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; if (subRL) { subRL->_parent = parent; }Node* parentParent = parent->_parent; subR->_left = parent; parent->_parent = subR; if (_root == parent) { _root = subR; subR->_parent = nullptr; } else { if (parentParent->_left == parent) parentParent->_left = subR; else parentParent->_right = subR; subR->_parent = parentParent; }subR->_bf = parent->_bf = 0; } void RotateLR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; int bf = subLR->_bf; RotateL(parent->_left); RotateR(parent); if (bf == 1) { subL->_bf = -1; parent->_bf = 0; subLR->_bf = 0; } else if (bf == -1) { parent->_bf = 1; subL->_bf = 0; subLR->_bf = 0; } else if (bf == 0) { parent->_bf = 0; subL->_bf = 0; subLR->_bf = 0; } else { assert(false); } } void RotateRL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; int bf = subRL->_bf; RotateR(parent->_right); RotateL(parent); if (bf == 1) { subR->_bf = 0; subRL->_bf = 0; parent->_bf = -1; } else if (bf == -1) { subR->_bf = 1; subRL = 0; parent->_bf = 0; } else if (bf == 0) { subR->_bf = 0; subRL = 0; parent->_bf = 0; } else { assert(false); } } void InOrder() { _InOrder(_root); } void _InOrder(Node* root) { if (root == NULL) return; _InOrder(root->_left); cout << root->_kv.first << ":" << root->_kv.second << endl; _InOrder(root->_right); } bool IsBalance() { return _IsBalance(_root); } int Height(Node* root) { if (root == NULL) return 0; int leftHeight = Height(root->_left); int rightHeight = Height(root->_right); return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1; } bool _IsBalance(Node* root) { if (root == NULL) return true; // 对当前树进行检查 int leftHeight = Height(root->_left); int rightHeight = Height(root->_right); if (rightHeight - leftHeight != root->_bf) { cout << root->_kv.first << "现在是:" << root->_bf << endl; cout << root->_kv.first << "应该是:" << rightHeight - leftHeight << endl; return false; }return abs(rightHeight - leftHeight) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right); } private: Node* _root; }; void TestAVLTree() { AVLTree t; //int a[] = { 0, 1, 2, 3, 4, 5}; //int a[] = { 5, 4, 3, 2, 1, 0 }; int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 }; for (auto e : a) { t.Insert(make_pair(e, e)); } t.InOrder(); cout << t.IsBalance() << endl; }

2.旋转图解 c++|【C++篇】AVL树
文章图片

三、AVL树的删除(了解)
因为AVL树也是二叉搜索树,可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不错与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。
具体实现学生们可参考《算法导论》或《数据结构-用面向对象方法与C++描述》殷人昆版
四、 AVL树性能
AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即log2 ^ n 。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合
总结
希望本篇文章能给各位带来帮助,如有不足还请指正!!! 码字不易,各位大大给个收藏点赞吧!!!

各位大大记得点赞,关注,一键三连哦!!!
c++|【C++篇】AVL树
文章图片

    推荐阅读