平衡二叉树看起来还是挺复杂的,甚至觉得很不可思议,刚开始让我都懵逼了一下。不过后来仔细想想二叉树旋转平衡的原理,感觉还是挺简单的。代码我是在上一篇博文BST的基础上修改,可以看作是BST衍生的分支。我主要实现的还是插入、查找、删除这3个主要方法,从数据结构上来说,Node节点仅仅多了记录高度height(包含自身)这一个字段,如果不考虑删除方法的话,其实连这一个字段都可以不用添加,可以用轻微左倾,如果再轻微左倾上插入左节点,abs(平衡因子)就会大于1,此时作为平衡检测的条件点。当然,我代码中直接加入了height字段,只需用abs(左子-右子)判断平衡因子是否大于1即可作为平衡检测的条件,不平衡则调用cw(顺时针)、ccw(逆时针)旋转使其平衡即可。旋转又分为几种情况,具体我就不再阐述,看代码即可。删除和BST有一点不同,就是需要再递归返回的时候刷新下高度,并且还要做平衡检测,若不平衡则需再次平衡,所以还不能像BST直接调search找节点来删除,必须在内部实现,递归返回判断是否删除了节点,若删除,则刷新依次从下到上走过节点的高度,并处理平衡。还有就是我对于有左子右子要删除的节点,我用的是后继删除,在寻找最左时用stack LIFO去处理走过的节点,网上很多版本都有BUG,我这个测试是绝对没BUG的
#include<iostream>
#include<ctime>
#include<stack>
using namespace std;
struct Node{
int data;
int height;
Node* left;
Node* right;
};
void InOrderTranversal(Node* root){
if(root==0){
return;
}
InOrderTranversal(root->left);
cout<<root->data<<':'<<root->height<<endl;
InOrderTranversal(root->right);
}
void release(Node* root){
if(root==0){
return;
}
release(root->left);
release(root->right);
delete root;
}
void search(Node*& root,int key,Node**& _result){
if(root==0){
_result=0;
return;
}
if(key<root->data){
search(root->left,key,_result);
}
else if(key==root->data){
_result=&root;//put purpoes's addr to result for changing the purpoes pointer point another addr by _delete
return;
}
else{
search(root->right,key,_result);
}
}
int getBalanceFactor(Node* root){
int val;
if(root->left!=0&&root->right!=0){
val=root->left->height-root->right->height;
}
else if(root->left!=0){
val=root->left->height;
}
else if(root->right!=0){
val=-root->right->height;
}
return val;
}
void calculateHeight(Node* root){
if(root->left!=0&&root->right!=0){
root->height=root->left->height>root->right->height?root->left->height+1:root->right->height+1;
}
else if(root->left!=0){
root->height=root->left->height+1;
}
else if(root->right!=0){
root->height=root->right->height+1;
}
else{
root->height=1;
}
}
void cwSpin(Node*& root){
if(root->left->left==0){
Node* mid=root->left;
root->left=root->left->right;
root->left->left=mid;
mid->right=0;
calculateHeight(root->left->left);
calculateHeight(root->left);
}
Node* ori_root=root;
root=root->left;
Node* beta=root->right;
root->right=ori_root;
if(beta!=0){
ori_root->left=beta;
}
else{
ori_root->left=0;
}
calculateHeight(ori_root);
}
/* ccwSpin:
1
alpha 2
beta 3
|
|
|
¡ý
2
1 3
alpha beta
*/
void ccwSpin(Node*& root){
if(root->right->right==0){
Node* mid=root->right;
root->right=root->right->left;
root->right->right=mid;
mid->left=0;
calculateHeight(root->right->right);
calculateHeight(root->right);
}
//alpha doesn't need to move
Node* ori_root=root;
root=root->right;
Node* beta=root->left;
root->left=ori_root;
if(beta!=0){
ori_root->right=beta;
}
else{
ori_root->right=0;
}
calculateHeight(ori_root);
}
bool insert(Node*& root,int value){
if(root==0){
root=new Node;
root->left=0;
root->right=0;
root->data=value;
root->height=1;
return true;
}
if(value>root->data){
if(!insert(root->right,value)){
return false;
}
else{
int bf=getBalanceFactor(root);
if(bf==-2){
cout<<"right need balance!"<<endl;
ccwSpin(root);
}
}
}
else if(value==root->data){
return false;
}
else{
if(!insert(root->left,value)){
return false;
}
else{
int bf=getBalanceFactor(root);
if(bf==2){
cout<<"left need balance!"<<endl;
cwSpin(root);
}
}
}
calculateHeight(root);
return true;
}
bool _delete(Node*& root,int key){
if(root==0){
return false;
}
if(key<root->data){
if(_delete(root->left,key)){
calculateHeight(root);
int bf=getBalanceFactor(root);
if(bf==2){
cwSpin(root);
}
if(bf==-2){
ccwSpin(root);
}
calculateHeight(root);
return true;
}
else{
return false;
}
}
else if(key==root->data){
Node* temp=root;
if(root->left==0&&root->right==0){//leaf node can remove now
root=0;
delete temp;
}
else if(root->left==0){//if has no left,make parent link to right and remove itself
root=root->right;
delete temp;
}
else if(root->right==0){
root=root->left;
delete temp;
}
else{
//it must have left and right
//my method is subsequent move,walk to end of right's left
//s init to right
//s_prent init to root
Node* s=root->right;
Node* s_parent=root;
stack<Node**> _stack;
_stack.push(&root);
bool first=true;
while(s->left!=0){
if(first){
_stack.push(&s_parent->right);
}
else{
_stack.push(&s_parent->left);
}
s_parent=s;
s=s->left;
first=false;
}
temp->data=s->data;
if(s->right!=0){//if end of right's left has right, it should replace end of right's left
if(s_parent==root){//if s_parent does not change,s_parent has had left tree,so it should put s'right to s_parent's right
s_parent->right=s->right;
}
else{
s_parent->left=s->right;
}
}
else{
if(s_parent==root){
s_parent->right=0;
}
else{
s_parent->left=0;
}
}
while(_stack.size()>0){
calculateHeight(*_stack.top());
int bf=getBalanceFactor(*_stack.top());
if(bf==2){
cwSpin(*_stack.top());
}
if(bf==-2){
ccwSpin(*_stack.top());
}
calculateHeight(*_stack.top());
_stack.pop();
}
delete s;
}
return true;
}
else{
if(_delete(root->right,key)){
calculateHeight(root);
int bf=getBalanceFactor(root);
if(bf==2){
cwSpin(root);
}
if(bf==-2){
ccwSpin(root);
}
calculateHeight(root);
return true;
}
else{
return false;
}
}
}
int main(){
srand(time(NULL));
Node* root=new Node;
root->left=0;
root->right=0;
root->data=10;
for(int i=0;i<100;i++){
insert(root,rand()%100);
}
InOrderTranversal(root);
Node** _result;
int value;
cout<<"please cin the value you want to find:";
cin>>value;
search(root,value,_result);
if(_result==0){
cout<<"can't find purpoes!"<<endl;
}
else{
cout<<"the result is:"<<(*_result)->data<<endl;
}
cout<<"please cin the value you want to delete:";
cin>>value;
if(_delete(root,value)){
InOrderTranversal(root);
cout<<"delete succeed!"<<endl;
}
else{
cout<<"delete failed!"<<endl;
}
release(root);
return 0;
}