平衡二叉树是这样一棵树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。查找、插入和删除在平均和最坏情况下都是O(log n)。可以用于数据库设计,内存分配算法等。
/* 平衡二叉查找树 written by huals 2012.10.13 */ #include <stdio.h> #include <stdlib.h> typedef struct BSTreeNode{ int value; struct BSTreeNode *left; struct BSTreeNode *right; struct BSTreeNode *parent; //到叶子节点最长路径(本节点不算) int len; } BSTreeNode; typedef struct BSTree{ BSTreeNode *root; int node_number; } BSTree; void BSTree_init(BSTree *tree); void BSTreeNode_init(BSTreeNode *z,int value); void Insert_BSTree(BSTree *T,BSTreeNode *z); void Left_rotate(BSTree *T,BSTreeNode *z); void Right_rotate(BSTree *T,BSTreeNode *z); void Delete_node(BSTree *T,BSTreeNode *z); BSTreeNode* Next_node(BSTree *T,BSTreeNode *z); BSTreeNode* Pre_node(BSTree *T,BSTreeNode *z); BSTreeNode* Search_node(BSTree *T,int value); void Modify_len(BSTree *T,BSTreeNode *x); void Balance_tree(BSTree *T,BSTreeNode *y); void Print_tree(BSTree *T); void Print_value(BSTreeNode *z); void Print_info_tree(BSTree *T); int main(void){ BSTree *tree; int i,j; tree=(BSTree *)malloc(sizeof(BSTree)); BSTree_init(tree); BSTreeNode *node=NULL; for(j=1;j<=10;j++){ node=(BSTreeNode *)malloc(sizeof(BSTreeNode)); BSTreeNode_init(node,j); Insert_BSTree(tree,node); Print_tree(tree); } //删除第十个节点,输出 //Delete_node(tree,Search_node(tree,4)); Print_info_tree(tree); Print_tree(tree); } //树初始化 void BSTree_init(BSTree *tree){ tree->root=NULL; tree->node_number=0; } //节点初始化 void BSTreeNode_init(BSTreeNode *z,int value){ z->value=value; z->parent=NULL; z->left=NULL; z->right=NULL; z->len=0; } //插入节点,ok void Insert_BSTree(BSTree *T,BSTreeNode *z){ BSTreeNode *y=T->root;BSTreeNode *x=NULL; int llen,rlen,flag; while(y!=NULL){ x=y; if(z->value<=y->value) y=y->left; else y=y->right; } z->parent=x; if(x==NULL) T->root=z; else{ if(z->value<=x->value) x->left=z; else x->right=z; } //更新插入节点到根节点的len值 y=z; while(y->parent!=NULL && y->len+1>y->parent->len){ y->parent->len=y->len+1; y=y->parent; } //调整二叉树使平衡 Balance_tree(T,z); T->node_number++; } //左旋 void Left_rotate(BSTree *T,BSTreeNode *z){ BSTreeNode *x=z->right; int llen,rlen; z->right=x->left; if(x->left!=NULL) (x->left)->parent=z; x->parent=z->parent; if(z->parent==NULL) T->root=x; else{ if((z->parent)->right==z) (z->parent)->right=x; else (z->parent)->left=x; } z->parent=x; x->left=z; //手动更新调整变换的关键点的len llen=(z->left==NULL?0:z->left->len+1); rlen=(z->right==NULL?0:z->right->len+1); z->len=(llen>=rlen?llen:rlen); llen=z->len+1; rlen=(x->right==NULL?0:x->right->len+1); x->len=(llen>=rlen?llen:rlen); //调试用:输出调整节点的值 //printf("z is %d,z len is %d\n",z->value,z->len); //更新因旋转后造成len的变化 Modify_len(T,x); } //右旋 void Right_rotate(BSTree *T,BSTreeNode *z){ BSTreeNode *x=z->left; int llen,rlen; z->left=x->right; if(x->right!=NULL) x->right->parent=z; x->parent=z->parent; if(z->parent==NULL) T->root=x; else{ if(z->parent->left==z) z->parent->left=x; else z->parent->right=x; } x->right=z; z->parent=x; //更新len llen=(z->left==NULL?0:z->left->len); rlen=(z->right==NULL?0:z->right->len); z->len=(llen>=rlen?llen+1:rlen+1); llen=z->len+1; rlen=(x->left==NULL?0:x->left->len+1); x->len=(llen>=rlen?llen:rlen); Modify_len(T,z); } //搜索后继节点 BSTreeNode* Next_node(BSTree *T,BSTreeNode *z){ BSTreeNode *y=NULL; BSTreeNode *x=z->right; while(x!=NULL){ y=x; x=x->left; } if(y==NULL){ x=z; while(x->parent!=NULL &&(x->parent)->right==x) x=x->parent; y=x->parent; } return y; } //搜索前仆节点 BSTreeNode* Pre_node(BSTree *T,BSTreeNode *z){ BSTreeNode *y=NULL; BSTreeNode *x=z->left; while(x!=NULL){ y=x; x=x->right; } if(y==NULL){ x=z; while(x->parent!=NULL && (x->parent)->left==x) x=x->parent; y=x->parent; } return y; } //搜索指定关键字节点,返回节点指针 BSTreeNode* Search_node(BSTree *T,int value){ BSTreeNode *x=T->root; while(x!=NULL){ if(value==x->value) return x; else if(value<x->value) x=x->left; else x=x->right; } return x; } //输出树的节点及其len值 void Print_tree(BSTree *T){ BSTreeNode *root=T->root; if(root==NULL) printf("The tree is NULL.\n"); else Print_value(root); } //输出树的信息:根节点及节点数目 void Print_info_tree(BSTree *T){ BSTreeNode *root=T->root; if(root==NULL) printf("The tree is NULL.\n"); else printf("the root node is %d, node number is %d\n",root->value,T->node_number); } //递归输出节点值及len值 void Print_value(BSTreeNode *z){ if(z->left!=NULL) Print_value(z->left); printf("value:%d len:%d\n",z->value,z->len); if(z->right!=NULL) Print_value(z->right); } //删除节点 void Delete_node(BSTree *T,BSTreeNode *z){ BSTreeNode *x,*y; int llen,rlen; x=NULL;y=NULL; if(z->left==NULL || z->right==NULL) y=z; else y=Next_node(T,z); if(y->left!=NULL) x=y->left; else x=y->right; if(x!=NULL) x->parent=y->parent; if(y->parent==NULL) T->root=x; else{ if(y->parent->left==y) y->parent->left=x; else y->parent->right=x; } if(y!=z){ z->value=y->value; //z->len=y->len; } x=y->parent; if(x!=NULL){ llen=(x->left==NULL?0:x->left->len+1); rlen=(x->right==NULL?0:x->right->len+1); x->len=(llen>=rlen?llen:rlen); Modify_len(T,x); Balance_tree(T,x); T->node_number--; } } /* 旋转节点和删除节点时会造成节点len值动荡,而x则是动荡的那一支,x本身len值正确,只是x父节点,祖先节点未知,需要调整 ok */ void Modify_len(BSTree *T,BSTreeNode *x){ int llen,rlen; BSTreeNode *z; llen=x->len+1; if(x->parent==NULL) return; z=(x->parent->left==x?x->parent->right:x->parent->left); rlen=(z==NULL?0:z->len+1); while(x->parent->len!=rlen){ x->parent->len=llen; x=x->parent; if(x->parent==NULL) return; llen=x->len+1; z=(x->parent->left==x?x->parent->right:x->parent->left); rlen=(z==NULL?0:z->len+1); } } //沿着y想根节点方向搜索不平衡节点,并通过旋转调整 void Balance_tree(BSTree *T,BSTreeNode *y){ int flag=0; int llen,rlen; BSTreeNode *x=NULL; while(y!=NULL && !flag){ llen=(y->left==NULL?0:(y->left)->len+1); rlen=(y->right==NULL?0:(y->right)->len+1); //判断是左旋还是右旋 switch(llen-rlen){ case 2:flag=1;break; case -2:flag=2;break; default :flag=0;break; } y=y->parent; } //旋转时需要判断是否需要两次旋转 if(flag==1){ if(y==NULL) y=T->root; else y=y->left; x=y->left; llen=(x->left==NULL?0:(x->left)->len+1); rlen=(x->right==NULL?0:(x->right)->len+1); if(llen>rlen) Right_rotate(T,y); else{ Left_rotate(T,x); Right_rotate(T,y); } } if(flag==2){ if(y==NULL) y=T->root; else y=y->right; x=y->right; llen=(x->left==NULL?0:(x->left)->len+1); rlen=(x->right==NULL?0:(x->right)->len+1); if(rlen>llen){ Left_rotate(T,y); } else{ Right_rotate(T,x); Left_rotate(T,y); } } }