AVL树(一)(数据结构与程序设计)

AVL树是个坑
第一部分就先实现插入吧

enum Balance_factor {left_higher, equal_height, right_higher};   //宏定义给出走边高一点,右边高一点,一样高,因为只能高一,所以定义这三个就够了
enum Error_code {success, fail, duplicate_error};  //这个。。。。

template<class Entry>
class B_node{
public:
    Entry data;
    B_node<Entry> *left;
    B_node<Entry> *right;
    B_node():left(NULL), right(NULL){}
    B_node(const Entry &d): data(d), left(NULL), right(NULL){}
    virtual void set_balance(Balance_factor b){}   //这个弄成虚函数是因为担心有可能新增加的节点其实它只是一个b_node,而不是AVL_node
    virtual Balance_factor get_balance() const{return equal_height;}  //同上
};

template <class Entry>
class AVL_node: public B_node<Entry>{
public:
    Balance_factor balance;
    AVL_node();
    AVL_node(const Entry &x): B_node<Entry>(x), balance(equal_height){}     //这个balance也要初始化啊,要不然加到后面会崩的,被坑在这里了
    virtual void set_balance(Balance_factor b){balance = b;}
    virtual Balance_factor get_balance() const{return balance;}
};

template<class Entry>
class AVL_tree{
private:
    B_node<Entry> *root;
public:
    AVL_tree():root(NULL){}
    //~AVL_tree();   //留待下节
    Error_code insert(const Entry &new_data);
    //void remove(const Entry &old_data);  //留待下节
    Error_code avl_insert(B_node<Entry> *&sub_root, const Entry &new_data, bool &taller);
    void rotate_left(B_node<Entry> *&node);   //这个左移右移的东东是在添加新节点时由于高度变了,也就是出现左比右高二的情况,这时就得移来移去
    void rotate_right(B_node<Entry> *&node);
    void right_balance(B_node<Entry> *&node);      //这个是右子树崩了,也就是把它左移、
    void left_balance(B_node<Entry> *&node);      //这个是左子树崩了,也就是把它右移、
};

实现insert

template<class Entry>
Error_code AVL_tree<Entry>::insert(const Entry &new_data){
    bool taller;     //taller用来判断高度是否增加,传成引用是为了能够改了高度后递归地改变父节点的balance
    return avl_insert(root, new_data, taller);
}

template<class Entry>
Error_code AVL_tree<Entry>::avl_insert(B_node<Entry> *&sub_root, const Entry &new_data, bool &taller){
    Error_code result = success;
    if(sub_root == NULL){
        sub_root = new AVL_node<Entry> (new_data);  //碰到空了就把它粘进去 
        taller = true;       //这个设成true不就是说这条递归链高一了嘛
    }
    else if(sub_root->data == new_data){
        result = duplicate_error;   //重复错误
        taller = false;      //没塞进去,所以高度也没变
    }
    else if(sub_root->data > new_data){
        result = avl_insert(sub_root->left, new_data, taller);   //这步的目的就是为了找到塞的地方,塞了之后它的taller不就设成true了吗,
        //然后它就递归着往回然后根据下面的if来改变父节点的balance设置要把这颗子树重balance一下
        //(递归是我最头疼的东西,所以有递归我会着重抓出来,方便以后自己理解)
        if(taller == true){
            switch(sub_root->get_balance()){
            case left_higher:    //看哈,根据这条为例,sub_root->data > new_data,那就是往左塞,因为前面的result = avl_insert(sub_root->left, new_data, taller); 这一句已经把节点塞进去,所以这里就是给递归后用的,taller也变成true了,如果此时父节点是left_higher,也就是这个case,那么它不就会变成高二了吗,此时就要balance一下。
                left_balance(sub_root);
                taller = false;   //这里设成false了是因为它上面已经没必要改了,left_balance函数里就会调整
                break;
            case right_higher:
                sub_root->set_balance(equal_height);
                taller = false;   //这里看它都设成equal_height了,那就说明没加前right高了一,然后这时在左边塞了一,所以这个节点平衡,所以对上面的父节点就不会有影响了。
                break;
            case equal_height:
                sub_root->set_balance(left_higher);
                break;
            }
        }
    }
    else{  //往右塞就自己拿来练手吧
        。
        。
        。
            }
        }
    }
    return result;
}

至于rotate_left,rotate_right,还有left_balance, right_balance
rotate分两种情况,以right_rotate为例,
第一种:
这里写图片描述
第二种
这里写图片描述

rotate代码实现简单,略过
然后是right_balance代码如下

template<class Entry>
void AVL_tree<Entry>::right_balance(B_node<Entry> *&node){
    B_node<Entry> *&right_node = node->right;
    B_node<Entry> *&sub_tree = right_node->left;   
switch(right_node->get_balance()){  //要分是左移的还是double_rotation上的情况,没有equal_height的情况,因为如果能够equal_height那也不用balance了
    case left_higher:   //左高右移
        switch(sub_tree->get_balance()){
        case left_higher:
            node->set_balance(equal_height);   //这个根据sub_tree的情况设置balance我是自己画图自己慢慢捣鼓的,也简单
            right_node->set_balance(right_higher);
            break;
        case right_higher:
            node->set_balance(left_higher);
            right_node->set_balance(equal_height);
            break;
        case equal_height:
            node->set_balance(equal_height);
            right_node->set_balance(equal_height);
            break;
        }
        sub_tree->set_balance(equal_height);
        rotate_right(right_node);   
        rotate_left(node);    //这两行就是double_rotation了
        break;
    case right_higher:
        node->set_balance(equal_height);
        right_node->set_balance(equal_height);
        rotate_left(node);   //这个情况就rotate_left就行
        break;
    }
}

rotate_left函数很简单,然后left_balance函数就给大家自己练手,自己画图出来把它分情况设置balance。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值