欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

数据结构学习-AVL平衡树

程序员文章站 2022-04-22 23:21:56
环境:C++ 11 + win10 IDE:Clion 2018.3 AVL平衡树是在BST二叉查找树的基础上添加了平衡机制。 我们把平衡的BST认为是任一节点的左子树和右子树的高度差为-1,0,1中的一种情况,即不存在相差两层及以上。 所谓平衡机制就是BST在理想情况下搜索复杂度是o(logn) ......

环境:c++ 11 + win10

ide:clion 2018.3

avl平衡树是在bst二叉查找树的基础上添加了平衡机制。

我们把平衡的bst认为是任一节点的左子树和右子树的高度差为-1,0,1中的一种情况,即不存在相差两层及以上。

所谓平衡机制就是bst在理想情况下搜索复杂度是o(logn)

但是如果在(存在某一节点,该节点的左子树的高度与右子树的高度差>1)这种状况下,复杂度会超过o(logn)

举个极端的例子如加入1,2,3,4,bst就退化为一个线性的链表,复杂度变成了o(n)

为了避免这种情况,我们在bst中引入平衡操作(旋转操作),使得bst始终不存在左右子树超过1高度差的节点。

数据结构学习-AVL平衡树

本次代码基于我的另一篇博客的基础之上,有需要可以翻看 https://www.cnblogs.com/cyrio/p/10118132.html

平衡机制主要通过反转完成,经过归纳,可能出现以下四种不平衡的情况:ll、lr、rl、rr

l=left     r=right

我们将不平衡点设为x点,以lr为例,第一个l表示x点的左子树比右子树层数多(>1),第二个r表示多出的那部分在x点的左子树的右子树。(不管他是在x的左子树的右子树的左右哪边,都称为lr)

 

如图:

数据结构学习-AVL平衡树

数据结构学习-AVL平衡树

 

 接下来我们以ll、lr、rr、rl四种情况讨论。

1、ll:

数据结构学习-AVL平衡树

通俗的讲就是把k2从k1那扯下来,然后把y移到k2的左子树,最后把k2移到k1的右子树。

2、rr:

数据结构学习-AVL平衡树

与ll同理,把k1先扯下来,再把y接到k1的右侧,再把k1作为左子树接到k2。

 3、lr:

数据结构学习-AVL平衡树

lr需要先做一次rr再做一次ll:

先把k1从k2那扯下来,让k2和k3连,然后把b作为k1的右子树,再把k1连到k2的左子树上。

然后再做ll,把k3从k2上面扯下来,让c作为k3的左子树,再把k3连到k2的右子树。

4、rl:

数据结构学习-AVL平衡树

先ll再rr,与lr同理。

以上是主要思想的分析,除了旋转操作,我们还需要添加新的方法:

1、求树的高度:height方法

2、求某节点的左子树和右子树的高度差 :diff方法      

3、一个对整个树进行判断,对里面的x节点进行对应操作:balance方法

同时avl中的insert(插入某一节点)的方法与bst中也略有不同,需要注意的是avl种的__insert(ps:带"__"的表示私有内部接口)的参数中第一个为bstnode<t> * & root (需要&引用

具体代码如下:(此代码为完整代码,可以直接复制进自己的项目查看效果)

mybst.h

#ifndef test1_mybst_h
#define test1_mybst_h

#include <iomanip>
#include "bstnode.h"
#include <vector>
#include <deque>
#include <iostream>
#include <algorithm>
using namespace std;

template <typename t>
class mybst{
private:
    bstnode<t> * root = nullptr;
    bstnode<t> * __search(bstnode<t> * root , const t &key){
        if (nullptr == root)
            return nullptr;
        if (key == root->data)
            return root;
        else if (key < root->data)
            return __search(root->left, key);
        else
            return __search(root->right, key);
    } //查找关键字是否存在
    bstnode<t> * __treemin(bstnode<t> * root , bstnode<t> * &parent){
        bstnode<t> * curr = root;
        while(curr->left!= nullptr){
            parent = curr;
            curr = curr->left;
        }
        return  curr;
    } //返回最小节点(一路向左)
    bstnode<t> * __insert(bstnode<t> * &root, const t &key){
        if (nullptr == root)
        {
            root = new bstnode<t>(key);
            return root;
        }//递归返回条件
        else if (key < root->data)
        {
            root->left = __insert(root->left,key);//递归左子树
            //balance operation
            root = __balance(root);//平衡操作包含了四种旋转
        }
        else if (key>root->data)
        {
            root->right = __insert(root->right,key);//递归右子树
            //balance operation
            root = __balance(root);//平衡操作包含了四种旋转
        }
        return root;
    } //插入指定值
    bool __delete(const t &key){
        bool found = false;//存储有没有找到key的变量
        if(isempty()){
            cerr<<"bst为空"<<endl;
            return false;
        }
        bstnode<t> * curr = root;
        bstnode<t> * parrent = nullptr;
        while(curr!= nullptr) {
            if (key == curr->data) {
                found = true;
                break;
            } else {
                parrent = curr;
                if (key < curr->data) curr = curr->left;
                else curr = curr->right;
            }
        }
        if(!found){
            cerr<<"未找到key!"<<endl;
            return false;
        }
        if (parrent == nullptr){//删除根节点
            root = nullptr;
            delete(curr);
            return true;
        }
        /*
         删除的节点有三种可能:
         1、叶子结点
         2、一个孩子的节点
         3、两个孩子的节点
         */
        if (__isleaf(curr)){ //删除的点是叶子结点
            if(parrent->left==curr) parrent->left= nullptr;
            else parrent->right= nullptr;
            delete(curr);
            return true;
        }
        else if(__isnodewithtwochild(curr)){ //是两个孩子的节点
            //以当前右子树中的最小值取代他
            bstnode<t> * parrent = curr;
            bstnode<t> * tmp = __treemin(curr->right,parrent);
            curr->data = tmp->data;
            if(parrent->right==tmp)
                parrent->right== nullptr;
            else parrent->left== nullptr;
            delete(tmp);
            return true;
        }
        else{ //只有一个孩子的节点
            if(curr->left!= nullptr){
                if(curr->left == curr){
                    parrent->left=curr->left;
                    delete(curr);
                    return true;
                }
                else{
                    parrent->right=curr->right;
                    delete(curr);
                    return true;
                }
            }
            if(curr->right!= nullptr){
                if(curr->left == curr){
                    parrent->left=curr->left;
                    delete(curr);
                    return true;
                }
                else{
                    parrent->right=curr->right;
                    delete(curr);
                    return true;
                }
            }
        }
        return false;
    } //删除指定值
    bool __isleaf(bstnode<t> * const & root){
        if(root->left== nullptr && root->right== nullptr) return true;
        else return false;
    }//判断是否是叶子节点
    bool __isnodewithtwochild(bstnode<t> * const & root){
        if(root->left!= nullptr && root->right!= nullptr) return true;
        else return false;
    }//判断是否有两个孩子
    void __inordertraversal(bstnode<t> *root,std::vector<int>&result){
        if(nullptr == root) return;
        __inordertraversal(root->left,result);
        cout<<root->data<<" ";
        result.push_back(root->data);
        __inordertraversal(root->right,result);
    }//中序遍历
    void __preordertraversal(bstnode<t> *root,std::vector<int>&result){
        if(nullptr == root) return;
        cout<<root->data<<" ";
        result.push_back(root->data);
        __inordertraversal(root->left,result);
        __inordertraversal(root->right,result);
    }//前序遍历
    void __postordertraversal(bstnode<t> *root,std::vector<int>&result){
        if(nullptr == root) return;
        __inordertraversal(root->left,result);
        __inordertraversal(root->right,result);
        cout<<root->data<<" ";
        result.push_back(root->data);
    }//后序遍历
    void __deleteallnodes(bstnode<t> *root){
        if (root == nullptr) return;
        __deleteallnodes(root->left);
        __deleteallnodes(root->right);
        __delete(root->data);
    }//删除所有节点
    void __bftraversal(vector<t>&result) {
        deque<bstnode<t> *> tqueue;
        bstnode<t> *pointer = root;
        if (pointer != nullptr) {
            tqueue.push_back(pointer);
        }
        while (!tqueue.empty()) {
            pointer = tqueue.front();
            tqueue.pop_front();
            cout << pointer->data << " ";
            result.push_back(pointer->data);
            if (pointer->left != nullptr) tqueue.push_back(pointer->left);
            if (pointer->right != nullptr) tqueue.push_back(pointer->right);
        }
    } //广度搜索来进行周游
    void __graph(int indent,bstnode<t>* root){
        if(root != 0){
            __graph(indent + 8, root->right);
            cout<<setw(indent)<<" "<<root->data<<endl;
            __graph(indent + 8, root->left);
        }
    } //横着画图的内部接口
    bstnode<t> * __getroot(){
        return root;
    } //返回根节点的内部接口
    //以下为avl平衡树新加的方法
    int __height(const bstnode<t>* root){
        if(root == nullptr){
            return 0;
        }
        return max(__height(root->left),__height(root->right))+1;
    } //求树的高度
    int __diff(const bstnode<t>* root){
        return __height(root->left)-__height(root->right);
    } //求节点的高度差(平衡因子)
    bstnode<t> * __ll__rotation(bstnode<t> * root){
        bstnode<t> * tmp;
        tmp = root->left;
        root->left = tmp->right;
        tmp->right = root;
        return tmp;
    } //单旋转-左左
    bstnode<t> * __rr__rotation(bstnode<t> * root){
        bstnode<t> * tmp;
        tmp = root->right;
        root->right = tmp->left;
        tmp->left = root;
        return tmp;
    } //单旋转-右右
    bstnode<t> * __lr__rotation(bstnode<t> * root){
        bstnode<t> * tmp;
        tmp = root->left;
        root->left = __rr__rotation(tmp);
        return __ll__rotation(root);
    } //双旋转-左右型,先右后左转(注意此处相反)
    bstnode<t> * __rl__rotation(bstnode<t> * root){
        bstnode<t> * tmp;
        tmp = root->right;
        root->right = __ll__rotation(tmp);
        return __rr__rotation(root);
    } //双旋转-右左型,先左后右转
    bstnode<t> * __balance(bstnode<t> * root){
        int balancefactor = __diff(root);//__diff用来计算平衡因子(左右子树高度差)
        if (balancefactor > 1)//左子树高于右子树
        {
            if (__diff(root->left) > 0)//左左外侧
                root=__ll__rotation(root);
            else//左右内侧
                root=__lr__rotation(root);
        }
        else if (balancefactor < -1)//右子树高于左子树
        {
            if (__diff(root->right) > 0)//右左内侧
                root=__rl__rotation(root);
            else//右右外侧
                root=__rr__rotation(root);
        }
        return root;
    } //平衡的内部操作
public:
    mybst(){
        root = nullptr;
    } //默认构造
    mybst(vector<t> arr){
        root = nullptr;
        for(int i =0;i<(t)arr.size();i++){
            insert(arr[i]);
        }
    }
    mybst(t * arr,int len){
        root = nullptr;
        for(int i =0;i<len;i++){
            __insert(*(arr+i));
        }
    }
    ~mybst(){
        bstnode<t> * curr = root;
        __deleteallnodes(curr);
    }//析构
    bool isempty() const{
        return root == nullptr;
    }//判断树空
    bool search(const t &key){
        bstnode<t> * temp = __search(root, key);
        return (temp == nullptr) ? false : true;
    }//查找关键字是否存在的对外接口
    bool insert(const t &key){
        return __insert(root,key);
    }//插入节点的外部接口
    bool delete(const t &key){
        return __delete(key);
    }//删除节点的外部接口
    void inordertraversal(vector<t>&result){
        __inordertraversal(root, result);
    }//中序遍历的外部接口
    void preordertraversal(vector<t>&result){
        __preordertraversal(root, result);
    }//前序遍历的外部接口
    void postordertraversal(vector<t>&result){
        __postordertraversal(root, result);
    }//后序遍历的外部接口
    void bftraversal(vector<t>&result){
        return __bftraversal(result);
    } //广度搜索外部接口
    void graph(int indent,bstnode<t>* root){
        return __graph(indent,root);
    } //横着画图的外部接口
    bstnode<t> * getroot(){
        return __getroot();
    } //返回根节点的外部接口
};

#endif //test1_mybst_h

bstnode.h

#ifndef test1_bstnode_h
#define test1_bstnode_h
template <typename t>
class bstnode{
public:
    t data;
    bstnode* left;
    bstnode* right;
    bstnode(){
        data = 0;
        left = nullptr;
        right = nullptr;
    }
    bstnode(t val){
        data = val;
        left = nullptr;
        right = nullptr;
    }
};
#endif //test1_bstnode_h

main.cpp

#include <iostream>
#include <vector>
#include "mybst.h"
#include "bstnode.h"
using namespace std;
int main() {
    vector<int> in = {7,6,5,13,17,22,10,3,2,1};
    mybst<int> bst(in);
    bst.delete(5);
    bst.insert(4);
    bool found = bst.search(4);
    if(!found)
        cout<<"not found!"<<endl;
    else
        cout<<"found!"<<endl;
    vector<int> result;
    cout<<"inordertravelsal:  ";
    bst.inordertraversal(result);
    cout<<endl<<"preordertravelsal:  ";
    bst.preordertraversal(result);
    cout<<endl<<"postordertraversal:  ";
    bst.postordertraversal(result);
    cout<<endl<<"bftraversal:  ";
    bst.bftraversal(result);
    cout<<endl<<"graph:"<<endl;
    bstnode<int>* pointer = bst.getroot();
    bst.graph(0,pointer);
    return 0;
}

 

参考:https://blog.csdn.net/zhangxiao93/article/details/51459743