数据结构——AVL树(平衡二叉树)的详细实现

github地址:https://github.com/lining91/AVLTree

AVL树的介绍:
AVL树的必要条件:
1、必须是二叉查找树
2、每个节点的左子树和右子树的高度差至多为1。
《数据结构——AVL树(平衡二叉树)的详细实现》
图一:非平衡二叉树

《数据结构——AVL树(平衡二叉树)的详细实现》
图二:平衡二叉树

图一:非平衡二叉树中节点26的左子树高度为2,右子树高度为0,左右子树差为2。所以是非平衡二叉树。

AVL树的查找、插入、删除操作在平均和最坏的情况下都是O(logn)。
不平衡的二叉查找树在查找时效率比较低。如果需要查找的数据集合本身没有顺序,在频繁的查找的同时也经常的插入和删除的时候,AVL树是不错的选择。

相关概念:
1、平衡因子
将二叉树上节点的左子树减去右子树高度的值,称为该节点的平衡因子BF。
对于平衡二叉树,BF取值范围为[-1, 1]。对于不在此范围的树需要进行调整。
2、最小不平衡子树
距离插入节点最近的,且平衡因子的绝对值大于1的节点为根的子树。

插入新节点倒是失衡调整:
1、左单旋转
向右子树插入右孩子导致AVL失衡时,需要围绕最小失衡子树的根节点进行左单旋转。
对应接口是LeftRotaion。
2、右单旋转
向左子树插入左孩子导致AVL失衡时,需要围绕最小失衡子树的根节点进行右单旋转。
对应接口是RightRotation。
3、先左旋后右旋
在左子树上插入右孩子导致AVL树失衡时,需要进行先左旋后右旋。
对应接口是LeftRightRotation。
4、先右旋后左旋
在右子树上插入左孩子导致AVL树失衡时,需要进行先右旋后左旋。
对应接口是RightLeftRotation。

删除节点:
1、删除右子树的节点
删除右子树的节点导致AVL树失衡,相当于在左子树插入新节点导致AVL树失衡,应进行右单旋转或先右旋后左旋。
2、删除左子树的节点
删除左子树的节点导致AVL树失衡,相当于在右子树插入新节点导致AVL树失衡,应进行左单旋转或者先左旋后右旋。

查找元素:
可以使用递归和非递归两种方法查询对应的元素。

遍历:
分为先序遍历、中序遍历、后序遍历。

代码如下:

#include <iostream>
using namespace std;


struct AVLTreeNode{
public:
    int key;                        // 关键字(键值)
    int nHeight;                    // 高度
    AVLTreeNode *pLeftChild;        // 左孩子节点
    AVLTreeNode *pRightChild;       // 右孩子节点

    AVLTreeNode( int value, AVLTreeNode *l, AVLTreeNode *r ) : key(value), nHeight(0),pLeftChild(l),pRightChild(r) 
    {
    }
};

class AVLTree
{
public:
    AVLTree();          
    ~AVLTree();

    void Preorder();        // 前序遍历
    void Inorder();         // 中序遍历
    void Postorder();       // 后序遍历

    void Insert( int key ); // 插入指定值的节点
    void Delete( int key );         // 删除指定值的节点

    void Destroy();         // 销毁AVL树

    const int GetMiniNum();         // 返回AVL树中的最小值
    const int GetMaxNum();          // 返回AVL树中的最大值
    const int GetHeight();          // 获取AVL树的高度

    AVLTreeNode* SearchRecurse( int key );      // 查找指定值(使用递归进行)
    AVLTreeNode* Search( int key );         // 查找指定值(使用迭代器进行)
private:
    void Preorder( AVLTreeNode* pNode ) const;      // 前序遍历
    void Inorder( AVLTreeNode* pNode ) const;       // 中序遍历
    void Postorder( AVLTreeNode* pNode ) const; // 后序遍历


    AVLTreeNode* Delete( AVLTreeNode* &pNode, int key );    // 删除AVL树中节点pDel,并返回被删除的节点

    void Destroy( AVLTreeNode* &pNode);

    AVLTreeNode* GetMiniNum( AVLTreeNode* pNode ) const;
    AVLTreeNode* GetMaxNum( AVLTreeNode* pNode ) const;
    int GetHeight( AVLTreeNode* pNode );

    AVLTreeNode* SearchRecurse( AVLTreeNode* pNode, int key ) const;
    AVLTreeNode* Search( AVLTreeNode* pNode, int key ) const;


    AVLTreeNode* LeftRotaion( AVLTreeNode* pNode );             // 左旋操作(单旋),返回旋转后的根节点
    AVLTreeNode* RightRotation( AVLTreeNode* pNode );               // 右旋操作(单旋),返回旋转后的根节点
    AVLTreeNode* LeftRightRotation( AVLTreeNode* pNode );           // 先左旋操作,后右旋操作(双旋),返回旋转后的根节点
    AVLTreeNode* RightLeftRotation( AVLTreeNode* pNode );           // 先右旋操作,后左旋操作(双旋),返回旋转后的根节点

    AVLTreeNode* Insert( AVLTreeNode* &pNode, int key );

private:
    AVLTreeNode* pRoot;
};


AVLTree::AVLTree( ) : pRoot( NULL )
{}

AVLTree::~AVLTree( )
{
    Destroy( pRoot );
}

void AVLTree::Preorder()
{
    Preorder( pRoot );
}

void AVLTree::Preorder( AVLTreeNode* pNode ) const
{
    if ( pNode != NULL )
    {
        cout << " " << pNode->key << " " ;
        Preorder( pNode->pLeftChild );
        Preorder( pNode->pRightChild );
    }
}

void AVLTree::Inorder()
{
    Inorder( pRoot );
}

void AVLTree::Inorder( AVLTreeNode* pNode ) const
{
    if ( pNode != NULL )
    {
        Inorder( pNode->pLeftChild );
        cout << " " << pNode->key << " " ;
        Inorder( pNode->pRightChild );
    }
}

void AVLTree::Postorder()
{
    Postorder( pRoot );
}

void AVLTree::Postorder( AVLTreeNode* pNode ) const
{
    if ( pNode != NULL )
    {
        Postorder( pNode->pLeftChild );
        Postorder( pNode->pRightChild );
        cout << " " << pNode->key << " " ;
    }
}

void AVLTree::Destroy()
{
    Destroy( pRoot );
}

void AVLTree::Destroy( AVLTreeNode* &pNode)
{
    if ( pNode == NULL )
        return;

    Destroy( pNode->pLeftChild );
    Destroy( pNode->pRightChild );
    delete pNode;
    pNode = NULL;
}

void AVLTree::Insert( int key )
{

    Insert( pRoot, key );
}

AVLTreeNode* AVLTree::Insert( AVLTreeNode* &pNode, int key )
{
    if ( pNode == NULL )
        pNode = new AVLTreeNode( key, NULL, NULL );
    else if ( pNode->key > key )                                // 插入值比当前节点的值小,插入到当前节点的左子树
    {
        pNode->pLeftChild = Insert( pNode->pLeftChild, key );
        if ( GetHeight( pNode->pLeftChild) - GetHeight( pNode->pRightChild ) == 2 )
        {
            if ( key < pNode->pLeftChild->key )                 // 插入到左子树的左孩子节点上,进行右旋
                pNode = RightRotation( pNode );
            else if ( key > pNode->pLeftChild->key )            // 插入到左子树的左孩子节点上,进行先左旋后右旋
                pNode = LeftRightRotation( pNode );
        }
    }
    else if ( pNode->key < key )                                // 插入值比当前节点的值大,插入到当前节点的右子树
    {
        pNode->pRightChild = Insert( pNode->pRightChild, key );
        if ( GetHeight( pNode->pRightChild ) - GetHeight( pNode->pLeftChild ) == 2 )
        {
            if ( key > pNode->pRightChild->key )                // 插入到右子树的右节点上,进行左旋
                pNode = LeftRotaion( pNode );
            else if ( key < pNode->pRightChild->key )
                pNode = LeftRightRotation( pNode );
        }
    }

    pNode->nHeight = max( GetHeight( pNode->pLeftChild ), GetHeight( pNode->pRightChild ) ) + 1;
    return pNode;
}

void AVLTree::Delete( int key )
{
    pRoot = Delete( pRoot, key );
}

AVLTreeNode* AVLTree::Delete( AVLTreeNode* &pNode, int key )
{
    if ( pNode == NULL )
        return NULL;

    if ( key == pNode->key )                                    // 找到要删除的节点
    {
        if ( pNode->pLeftChild != NULL && pNode->pRightChild != NULL )
        {
            // 左子树比右子树高,在左子树上选择节点进行替换
            if ( GetHeight( pNode->pLeftChild ) > GetHeight( pNode->pRightChild ) )
            {
                // 使用左子树的最大节点来代替被删节点,而删除该最大节点
                AVLTreeNode* pNodeTemp = GetMaxNum( pNode->pLeftChild );                // 左子树最大节点
                pNode->key = pNodeTemp->key;
                pNode->pLeftChild = Delete( pNode->pLeftChild, pNodeTemp->key );        // 递归地删除最大节点
            }
            else
            {
                // 使用最小节点来代替被删节点,而删除该最小节点
                AVLTreeNode* pNodeTemp = GetMiniNum( pNode->pRightChild );              // 右子树的最小节点
                pNode->key = pNodeTemp->key;
                pNode->pRightChild = Delete( pNode->pRightChild, pNodeTemp->key );      // 递归地删除最小节点
            }

        }
        else
        {
            AVLTreeNode* pNodeTemp = pNode;
            if ( pNode->pLeftChild != NULL )
                pNode = pNode->pLeftChild;

            if ( pNode->pRightChild != NULL )
                pNode = pNode->pRightChild;

            delete pNodeTemp;
            pNodeTemp = NULL;
            return pNode;

        }
    }
    else if ( key > pNode->key )                            // 要删除的节点比当前结点大,则在右子树进行查找
    {
        pNode->pRightChild = Delete( pNode->pRightChild, key );
        if ( GetHeight( pNode->pLeftChild ) - GetHeight( pNode->pRightChild ) == 2 )
        {
            if ( GetHeight( pNode->pLeftChild->pRightChild ) > GetHeight( pNode->pLeftChild->pLeftChild ) )
                pNode = LeftRightRotation( pNode );
            else
                pNode = RightRotation( pNode );
        }

    }
    else                                                    // 要删除的节点比当前结点小,则在左子树进行查找
    {
        pNode->pLeftChild = Delete( pNode->pLeftChild, key );
        if ( GetHeight( pNode->pLeftChild->pRightChild ) > GetHeight( pNode->pLeftChild->pLeftChild ) )
            pNode = RightLeftRotation( pNode );
        else
            pNode = LeftRotaion( pNode );
    }

    return pNode;
}

const int AVLTree::GetMiniNum()
{
    AVLTreeNode* pFindNode = GetMiniNum( pRoot );
    if ( pFindNode == NULL )
        return 0;

    return pFindNode->key;
}

AVLTreeNode* AVLTree::GetMiniNum( AVLTreeNode* pNode ) const
{
    if ( pNode == NULL )
        return NULL;

    while ( pNode->pLeftChild != NULL )
        pNode = pNode->pLeftChild;

    return pNode;
}

const int AVLTree::GetMaxNum()
{
    AVLTreeNode* pFindNode = GetMaxNum( pRoot );
    if ( pFindNode == NULL )
        return 0;

    return pFindNode->key;
}

AVLTreeNode* AVLTree::GetMaxNum( AVLTreeNode* pNode ) const
{
    if ( pNode == NULL )
        return NULL;

    while ( pNode->pRightChild != NULL )
        pNode = pNode->pRightChild;

    return pNode;
}

const int AVLTree::GetHeight()
{
    return GetHeight( pRoot );
}

int AVLTree::GetHeight( AVLTreeNode* pNode )
{
    if ( pNode == NULL )
        return 0;

    return pNode->nHeight;
}

AVLTreeNode* AVLTree::SearchRecurse( int key )
{
    return SearchRecurse( pRoot, key );
}

AVLTreeNode* AVLTree::SearchRecurse( AVLTreeNode* pNode, int key ) const
{
    if ( pNode == NULL )
        return NULL;

    if ( key == pNode->key )
        return pNode;

    if ( key > pNode->key )
        return SearchRecurse( pNode->pRightChild, key);
    else
        return SearchRecurse( pNode->pLeftChild, key);
}

AVLTreeNode* AVLTree::Search( int key )
{
    return Search( pRoot, key );
}

AVLTreeNode* AVLTree::Search( AVLTreeNode* pNode, int key ) const
{
    while ( pNode != NULL )
    {
        if ( key == pNode->key )
            return pNode;
        if ( key > pNode->key )
            pNode = pNode->pRightChild;
        else
            pNode = pNode->pLeftChild;
    }
    return NULL;
}

AVLTreeNode* AVLTree::LeftRotaion( AVLTreeNode* pNode )
{
    AVLTreeNode* pRChlid = pNode->pRightChild;
    pNode->pRightChild = pRChlid->pLeftChild;
    pRChlid->pLeftChild = pNode;

    pNode->nHeight = max( GetHeight( pNode->pLeftChild ), GetHeight( pNode->pRightChild ) ) + 1 ;
    pRChlid->nHeight = max( GetHeight( pRChlid->pLeftChild ), GetHeight( pRChlid->pRightChild ) ) + 1 ;

    return pRChlid;
}

AVLTreeNode* AVLTree::RightRotation( AVLTreeNode* pNode )
{
    AVLTreeNode* pLChild = pNode->pLeftChild;
    pNode->pLeftChild = pLChild->pRightChild;
    pLChild->pRightChild = pNode;

    pNode->nHeight = max( GetHeight( pNode->pLeftChild ), GetHeight( pNode->pRightChild ) ) + 1 ;
    pLChild->nHeight = max( GetHeight( pLChild->pLeftChild ), GetHeight( pLChild->pRightChild ) ) + 1 ;
    return pLChild;
}

AVLTreeNode* AVLTree::LeftRightRotation( AVLTreeNode* pNode )
{
    pNode->pRightChild = RightRotation( pNode->pRightChild );
    return LeftRotaion( pNode );
}

AVLTreeNode* AVLTree::RightLeftRotation( AVLTreeNode* pNode )
{
    pNode->pLeftChild = LeftRotaion( pNode->pLeftChild );
    return RightRotation( pNode );
}

void main( )
{
    AVLTree* pTree = new AVLTree( );
    for ( int nIdx = 0; nIdx < 10; nIdx++ )
    {
        pTree->Insert( nIdx );
    }

    cout << " 树的高度为:" << pTree->GetHeight( ) << endl;

    cout << " 前序遍历:" ;
    pTree->Preorder( );
    cout << endl;

    cout << " 中序遍历:" ;
    pTree->Inorder( );
    cout << endl;

    cout << " 后序遍历:" ;
    pTree->Postorder( );
    cout << endl;

    int nDeleteKey = 8;
    AVLTreeNode* pFindNode = pTree->SearchRecurse( nDeleteKey );
    if ( pFindNode == NULL )
        cout << " 无元素" << nDeleteKey << endl;
    else
    {
        cout << " 删除元素" << nDeleteKey << endl;
        pTree->Delete( nDeleteKey );
        cout << " 前序遍历:" ;
        pTree->Preorder( );
    }

    cout << endl;

    system( "pause");
    return;
}

运行结果如下:
《数据结构——AVL树(平衡二叉树)的详细实现》

    原文作者:AVL树
    原文地址: https://blog.csdn.net/lining0420/article/details/76299154
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞