• 平衡搜索树(一) AVL树


    AVL树

    AVL树又称为高度平衡的二叉搜索树,是1962年有俄罗斯的数学家G.M.Adel'son-Vel'skii和E.M.Landis提出来的。它能保持二叉树的高度 平衡,尽量降低二叉树的高度,减少树的平均搜索长度AVL树的性质

    1. 左子树和右子树的高度之差的绝对值不超过1

    2. 树中的每个左子树和右子树都是AVL树

    3. 每个节点都有一个平衡因子(balance factor--bf),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子 树的高度 )
    AVL树的效率

    一棵AVL树有N个节点,其高度可以保持在log2N,插入/删除/查找的时间复杂度也是log2N。

    当出现不平衡的情况时的四种情况:

    1.只需要右旋(汉子笔画为一“”),无论在黄(son)的左边插入还是右边插入,红(grandparent)的平衡因子,绿(parent)的平衡因子总能保持为0;

    2.只需要左旋(汉子笔画为一“捺”)与情况1类似,此处就不再累赘;

     

    3.左右旋(汉字笔画为一“”,一“”)

    (1)绿的平衡因子为 0。有且只有一种可能;

    (2)绿的平衡因子为-1。在绿(son)的左边插入,红(grandparent)的平衡因子为1,黄(parent)的平衡因子为0,绿(son)的平衡因子为0;

    (3)绿的平衡因子为1。在绿(son)的右边插入,红(grandparent)的平衡因子为0,黄(parent)的平衡因子为-1,绿(son)的平衡因子为0;

    4.右左旋(汉字笔画为一“捺”,一“撇”),情况与左右旋类似;

    Now   图画完了~~  大体思想了解了   闲话就不多叙述了--直接上代码

    //AVLTree 的节点类

     1 template<class K,class V>
     2 struct AVLTreeNode
     3 {
     4     typedef AVLTreeNode<K, V> Node;
     5     AVLTreeNode(const K& key, const V& value)
     6         :_left(NULL), _right(NULL), _parent(NULL)
     7         , _balance(0), _key(key), _value(value)
     8     {}
     9     
    10     Node * _left;
    11     Node * _right;
    12     Node * _parent;
    13     int _balance;
    14     K _key;
    15     V _value;
    16 };

    //AVLTree    (这个就是AVLTree  的类)

     1 template<class K,class V>
     2 class AVLTree
     3 {
     4     typedef AVLTreeNode<K, V> Node;
     5 public:
     6     AVLTree()
     7         :_root(NULL)
     8     {}
     9 public:
    10     //增加节点
    11     bool _Push(const K& key, const V& value);    
    12     void _LeftSpin(Node *& parent);
    13     void _RightSpin(Node * & parent);
    14     void _LeftRightSpin(Node *& _RightSpinparent);
    15     void _RightLeftSpin(Node *& parent);
    16     
    17     //查找结点
    18     Node* _Find(const K& key);
    19 
    20     //修改节点
    21     bool _Change(const K& key,const V& value);
    22 
    23     //检测
    24     void _LevelOrder();
    25     void _InOrder(){ InOrder(_root); }
    26     int _Depth(){ Depth(_root); }
    27     void InOrder(Node * root);
    28     int Depth(Node * root);
    29 protected:
    30     Node * _root;
    31 };

    //AVLTree的构建   

     1 //增加节点
     2 template<class K,class V>
     3 bool AVLTree<K, V>::_Push(const K& key, const V& value)
     4 {
     5     if (_root == NULL)
     6     {
     7         _root = new Node(key, value);
     8         return true;
     9     }
    10     else           //如果要根节点不为空
    11     {
    12         Node * insert = new Node(key, value);
    13         Node * cur = _root;
    14         Node * parent = NULL;
    15         while (cur)          //找插入的位置
    16         {
    17             parent = cur;
    18             if (key > cur->_key)
    19             {
    20                 cur = cur->_right;
    21             }
    22             else if (key < cur->_key)
    23             {
    24                 cur = cur->_left;
    25             }
    26             else
    27             {
    28                 return false;
    29             }
    30         }
    31         if (key > parent->_key)      //将该节点插入到parent的右边
    32         {
    33             parent->_right = insert;
    34             insert->_parent = parent;
    35         }
    36         else                        //将该节点插入到parent的左边
    37         {
    38             parent->_left = insert;
    39             insert->_parent = parent;
    40         }
    41         cur = insert;               //cur指向新插入的节点
    42 while (parent) //向上调节平衡因子 43 { 44 if (cur->_key > parent->_key) 45 { 46 parent->_balance++; 47 } 48 else 49 { 50 parent->_balance--; 51 } 52 if (parent->_balance == 0 || parent->_balance == 2 || parent->_balance == -2) //当_balance == 0 说明已经平衡了。_balance == 2 || _balance == -2 说明需要调整了
    53 { 54 break; 55 } 56 cur = parent; 57 parent = cur->_parent; 58 } 59 60 if (parent && (parent->_balance == 2 || parent->_balance == -2)) //如果_balance == 2 || _balance == -2 61 { 62 if (parent->_balance == 2) 63 { 64 if (cur->_balance == 1) 65 { 66 _LeftSpin(parent); //上面的情况2 67 } 68 else 69 { 70 _RightLeftSpin(parent); //上面的情况472 } 73 } 74 else if(parent->_balance == -2) 75 { 76 if (cur->_balance == -1) 77 { 78 _RightSpin(parent);     //上面的情况1
    79 } 80 else 81 { 82 _LeftRightSpin(parent); //上面的情况384 } 85 } 87 } 88 return true; 89 } 90 }

    //左旋(按照上面的来敲带码,其实是很简单滴)

     1 template<class K, class V>
     2 void AVLTree<K, V>::_LeftSpin(Node *& parent)
     3 {
     4     Node* son = parent->_right;
     5     Node* grandparent = parent->_parent;
     6 
     7     parent->_right = son->_left;
     8     if (son->_left)
     9     {
    10         son->_left->_parent = parent;
    11     }
    12     son->_left = parent;
    13     parent->_parent = son;
    14 
    15     son->_parent = grandparent;
    16     if (grandparent)
    17     {
    18         if (parent->_key > grandparent->_key)
    19         {
    20             grandparent->_right = son;
    21         }
    22         else
    23         {
    24             grandparent->_left = son;      
    25         }
    26     }
    27 
    28     parent->_balance = 0;       //将平衡因子置为零
    29     son->_balance = 0;
    30 
    31     if (_root == parent)
    32     {
    33         _root = son;
    34     }
    35     parent = son;
    36 }

    //左右旋

    template<class K, class V>
    void AVLTree<K, V>::_LeftRightSpin(Node *& parent)
    { Node
    * son = parent->_left; bool left = false; bool right = false; if (son->_right->_balance == -1) //如图,如果son 的 balance == -1 调整好后 grandparent 的 平衡因子为 1;即 (当前parent->right == 1);
        {
            left = true;
        }
        else if (son->_right->_balance == 1)      //如图,如果 son 的 balance == 1  调整好后  parent 的 平衡因子为 -1;即(当前parent->left == -1);
        {
            right = true;
        }
        _LeftSpin(son);   //(这里有一个坑:参数传的是引用,所以实参不能传(grandparent->_left)否则就会有神奇的事情发生^_^  ~~ 这里要小心再小心!!!前车之鉴呀大兄弟)
      _RightSpin(parent); if (left) { parent->_right->_balance = 1; } else if (right) { parent->_left->_balance = -1; } }
     
  • 相关阅读:
    MySQL
    LeetCode
    数据结构
    我的编程幻想曲,更新中
    快速排序
    C与C++的区别
    必须要使用列表初始化的几种情况
    析构中delete this
    指向自身类型的成员指针的初始化,this不属于类对象的一部分
    构造函数
  • 原文地址:https://www.cnblogs.com/shihaokiss/p/5438387.html
Copyright © 2020-2023  润新知