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。