1. 程式人生 > >平衡搜尋樹-AVLTree

平衡搜尋樹-AVLTree

AVL樹

又稱為高度平衡的二叉搜尋樹。它能保持二叉樹的高度平衡,儘量降低二叉樹的高度,減少樹的平均搜尋長度。

AVL樹的性質

  1. 左子樹和右子樹的高度之差的絕對值不超過1
  2. 樹中的每一個左子樹和右子樹都是AVL樹
  3. 每個節點都有一個平衡因子,任一節點的平衡因子是-1或0或1.(每個節點的平衡因子等於右子樹的高度減去左子樹的高度,即:bf = rightHeigh - leftHeight)

AVL樹的效率

一顆AVL樹有N個節點,其高度可以保持在log2N(表示log以2為底N的對數),插入/刪除/查詢的時間複雜度也是log2N.

更新平衡因子

這裡寫圖片描述

  1. cur在parent左,p bf - -
  2. cur在parent 右,p bf++
    • p == 0;p樹高度不變
    • |p| == 1;高度變了,繼續更新
    • |p| == 2;不再更新,旋轉平衡起來

插入

  1. 右單旋轉—— RotateR
  2. 左單旋轉—— RotateL
  3. 右左雙旋轉— RotateRL
  4. 左右雙旋轉— RotateLR
右單旋轉

這裡寫圖片描述

void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left =
subLR; if(subLR) subLR->_parent = parent; subL->_right = parent; Node* ppNode = parent->_parent ; parent->_parent = subL; if(parent == _root) { _root = subL; _root->_parent = NULL; } else
{ if(ppNode->_left == parent) { ppNode->_left = subL; } else { ppNode->_right = subL; } subL->_parent = ppNode; } parent->_bf = subL->_bf = 0; }
左單旋轉

這裡寫圖片描述

void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        parent->_right = subRL;
        if(subRL)
            subRL->_parent = parent;
        subR->_left = parent;
        Node* ppNode = parent->_parent ;
        parent->_parent = subR;
        if(parent == _root)
        {
            _root = subR;
            _root->_parent = NULL;
        }
        else
        {
            if(ppNode->_right == parent) 
            {
                ppNode->_right = subR;
            }
            else
            {
                ppNode->_left = subR;
            }
            subR->_parent = ppNode;
        }
        parent->_bf = subR->_bf = 0;
    }
右左雙旋轉

這裡寫圖片描述

void RotateRL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;
        RotateR(parent->_right);
        RotateL(parent);
        if(bf == 0)
        {
            subR->_bf = parent->_bf = subRL->_bf = 0;
        }
        else if(bf == 1)
        {
            parent->_bf = -1;
            subR->_bf = 0;
            subRL->_bf = 0;
        }
        else
        {
            parent->_bf = 0;
            subR->_bf = 1;
            subRL->_bf = 0;
        }
    }
左右雙旋轉

左右的圖和右左圖類似

 void RotateLR(Node* parent)   //左右雙旋  
    {  
        Node* subL = parent->_left;  
        Node* subLR = subL->_right;  
        int bf = subLR->_bf;  
        RotateL(subL);  
        RotateR(parent);  

        if (bf == 0)  
            parent->_bf =subLR->_bf= subL->_bf = 0;  
        else if (bf == 1)  
        {  
            parent->_bf = subLR->_bf = 0;  
            subL->_bf = -1;  
        }  
        else if (bf == -1)  
        {  
            parent->_bf = 1;  
            subL->_bf = subLR->_bf = 0;  
        }  
    }  

判斷是不是平衡二叉樹:

程式碼實現:

  • AVLTree.h
  • test.cpp

AVLTree.h

//#pragma once
#include <iostream>
using namespace std;

template<class K,class V>
struct AVLTreeNode
{
    K _key;
    V _value;
    int _bf;
    AVLTreeNode<K,V>* _left;
    AVLTreeNode<K,V>* _right;
    AVLTreeNode<K,V>* _parent;

    AVLTreeNode(const K& key,const V& value)
        :_key(key)
        ,_value(value)
        ,_bf(0)
        ,_left(NULL)
        ,_right(NULL)
        ,_parent(NULL)
    {}
};

template<class K,class V>
class AVLTree
{
    typedef AVLTreeNode<K,V> Node;
public:
    AVLTree()
        :_root(NULL)
    {}

    //插入

    bool Insert(const K& key,const V& value)
    {
        if(_root == NULL)
        {
            _root = new Node(key,value);
            return true;
        }
        Node* cur = _root;
        Node* parent = NULL;
        while(cur)
        {
            if( cur->_key < key)//根 < 插入的節點
            {
                parent = cur;
                cur = cur->_right;
            }
            else if( cur->_key > key)
            {
                parent = cur;
                cur = cur->_left ;
            }
            else
            {
                return false;
            }
        }

        cur = new Node(key,value);
        if(parent->_key < key)
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else if(parent->_key > key)
        {
            parent->_left = cur;
            cur->_parent = parent;
        }

    //更新平衡因子 
    //1.cur在parent左,p bf-- 
    //2.cur在parent 右,p bf++
    //p == 0;p樹高度不變
    //|p| == 1;高度變了,繼續更新
    //|p| == 2;不再更新,旋轉平衡起來

        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 = cur->_parent;
            }
            else if(parent->_bf == -2 || parent->_bf == 2)
            {
                if(parent->_bf == 2)
                {
                    if(cur->_bf == 1)
                    {
                        RotateL(parent);
                    }
                    else //-1
                    {
                        RotateRL(parent);
                    }
                }
                else // -2
                {
                    if(cur->_bf == -1)
                    {
                        RotateR(parent);
                    }
                    else // 1
                    {
                        RotateLR(parent);
                    }
                }
            }
            break;
        }
    }

    void InOrder()
    {
        _InOrder(_root);
        cout<<endl;
    }
    void _InOrder(Node* root)//中序遍歷 左中右
    {
        if(root == NULL)
            return;
        _InOrder(root->_left);
        cout<<root->_key<<" ";
        _InOrder(root->_right);
    }
//右單旋轉
    void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        parent->_left = subLR;
        if(subLR)
            subLR->_parent = parent;
        subL->_right = parent;
        Node* ppNode = parent->_parent ;
        parent->_parent = subL;
        if(parent == _root)
        {
            _root = subL;
            _root->_parent = NULL;
        }
        else
        {
            if(ppNode->_left == parent)
            {
                ppNode->_left = subL;
            }
            else
            {
                ppNode->_right = subL;
            }
            subL->_parent = ppNode;
        }
        parent->_bf = subL->_bf = 0;
    }

 //左單旋轉

    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        parent->_right = subRL;
        if(subRL)
            subRL->_parent = parent;
        subR->_left = parent;
        Node* ppNode = parent->_parent ;
        parent->_parent = subR;
        if(parent == _root)
        {
            _root = subR;
            _root->_parent = NULL;
        }
        else
        {
            if(ppNode->_right == parent) 
            {
                ppNode->_right = subR;
            }
            else
            {
                ppNode->_left = subR;
            }
            subR->_parent = ppNode;
        }
        parent->_bf = subR->_bf = 0;
    }

//右左雙旋轉

    void RotateRL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;
        RotateR(parent->_right);
        RotateL(parent);
        if(bf == 0)
        {
            subR->_bf = parent->_bf = subRL->_bf = 0;
        }
        else if(bf == 1)
        {
            parent->_bf = -1;
            subR->_bf = 0;
            subRL->_bf = 0;
        }
        else
        {
            parent->_bf = 0;
            subR->_bf = 1;
            subRL->_bf = 0;
        }
    }

//左右雙旋轉
     void RotateLR(Node* parent)   //左右雙旋  
    {  
        Node* subL = parent->_left;  
        Node* subLR = subL->_right;  
        int bf = subLR->_bf;  
        RotateL(subL);  
        RotateR(parent);  

        if (bf == 0)  
            parent->_bf =subLR->_bf= subL->_bf = 0;  
        else if (bf == 1)  
        {  
            parent->_bf = subLR->_bf = 0;  
            subL->_bf = -1;  
        }  
        else if (bf == -1)  
        {  
            parent->_bf = 1;  
            subL->_bf = subLR->_bf = 0;  
        }  
    }  

     //判斷是不是平衡搜尋樹
     //1. 遞迴——時間複雜度n^2
     //      (遞迴的次數*每次遞迴的次數)
     //        每個節點的遍歷*高度(也是遍歷整個樹)
     //bool IsBalance()  
     //{  
        // int depth = 0;
  //       return _IsBalance(_root);  
     //} 
     //int MaxDepth(Node* root)  
     //{  
        //if (NULL == root)  
        //  return 0;  
        //int left = MaxDepth(root->_left)+1;  
        //int right = MaxDepth(root->_right) + 1;  
        //return left > right ? left : right;  
     //}  
     //bool _IsBalance(Node* root)
     //{
        // //遞迴的終止條件
        // if(root == NULL)
        // {
        //   return true;
        // }
        // int leftHeight = MaxDepth(root->_left);
        // int rightHeight = MaxDepth(root->_right);
        // return abs(rightHeight-leftHeight) < 2
        //   && _IsBalance(root->_left)
        //   && _IsBalance(root->_right);
     //}
     //2. 優化——時間複雜度O(n)——高度只遍歷一次
      bool IsBalance() 
      {  
         int depth = 0;
         return _IsBalance(_root,depth);  
      } 
    bool _IsBalance(Node* root,int& depth)
    {
        if(root == NULL)
        {
            return true;
        }
        int left = 0;
        int right = 0;
        if(_IsBalance(root->_left,left)&&_IsBalance(root->_right,right))
        {
            if( abs(left-right) > 1 )
                return false;
            depth = (left > right ? left : right)+1;
            return true;
        }
        return false;
    }
    /*  bool _IsBalance(Node* root,int& depth)  
      {  
          if(root == NULL)
          {
              depth = 0;
              return true;
          }
          int leftdepth = 0;
          int rightdepth = 0;
          if(_IsBalance(root->_left,leftdepth) == false)
              return false;
          if(_IsBalance(root->_right,rightdepth) == false)
              return false;
          if(rightdepth - leftdepth != root->_bf)
          {
               cout << root->_key << "平衡因子異常" << endl;  
               return false;  
          }
          depth = leftdepth > rightdepth ? leftdepth+1 : rightdepth+1;
      }  */
private:
    Node* _root;
};

test.cpp

#include "AVLTree.h"

void testAVLTree()
{
    AVLTree<int, int> t;  
    int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    int depth = 0;
    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++)  
    {  
        t.Insert(a[i], i);  
        cout << "isbalance?"<<t.IsBalance() <<"插入"<< a[i] << endl;  
    }  
    t.InOrder();  
    t.IsBalance();  
    AVLTree<int, int> t1;  
    int a1[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };  
    for (size_t i = 0; i < sizeof(a1) / sizeof(a1[0]); i++)  
    {  
        t1.Insert(a1[i], i);  
        cout << "isbalance?" << t1.IsBalance() << "插入" << a1[i] << endl;  
    }  
    t1.InOrder();  
}

int main()
{
    testAVLTree();
    return 0;
}