最近在学计算几何,经常要用到BBST去储存一些数据,正是因为BBST查找效率极高O(logn)并且占用的空间仍是线性的,而其构造的时间需要O(nlogn),是可以接受的。所以在这里总结了BBST插入、删除、查找的功能到一个头文件中:
具体实现的原理可见https://blog.csdn.net/derbi123123/article/details/104204220
头文件:
#include <math.h>
#include <iostream>
using namespace std;
#define ElementType int//这里只需要改变ElementType的类型,下面的数据类型都是ElementType
typedef struct node *AVL;
struct node{
ElementType data;
int height;//节点高度(根节点最高,叶子结点最低)
AVL left;
AVL right;
};
//创建平衡二叉树:
AVL BuildBBST(ElementType data)
{
AVL Root=new node;
Root->data=data;
Root->height=1;
Root->left=NULL;
Root->right=NULL;
return Root;
}
//获得节点的高度:
int GetHeight(AVL tree)
{
if(!tree) return 0;
return tree->height;
}
//得到节点的平衡因子:
int GetBT(AVL tree)
{
int BT=GetHeight(tree->left)-GetHeight(tree->right);//不用绝对值是因为方便判断用哪种方式调整
return BT;
}
//右单旋:
AVL RR(AVL A)
{
AVL B=A->right;
A->right=B->left;
B->left=A;
//更新节点高度:
A->height=max(GetHeight(A->left),GetHeight(A->right))+1;
B->height=max(GetHeight(B->right),A->height)+1;
return B;
}
//左单旋:
AVL LL(AVL A)
{
AVL B=A->left;
A->left=B->right;
B->right=A;
//更新节点高度:
A->height=max(GetHeight(A->left),GetHeight(A->right))+1;
B->height=max(GetHeight(B->left),A->height)+1;
return B;
}
//左—右双旋:
AVL LR(AVL A)
{
A->left=RR(A->left);//旋转B、C、CR/CL
return LL(A);//旋转A、C、CR/CL
}
//右—左单旋:
AVL RL(AVL A)
{
A->right=LL(A->right);//旋转B、C、CR/CL
return RR(A);//旋转A、C、CR/CL
}
//插入新节点
AVL Insert(AVL tree,ElementType X)
{
if(!tree){
tree=new node;
tree->data=X;
tree->left=tree->right=NULL;
}else if(X<tree->data){
tree->left=Insert(tree->left,X);
if(GetBT(tree)==2){//平衡因子超过1,自己想为什么是==2而不是>=2
if(tree->left->data>X){//左单旋
tree=LL(tree);
}else{//左右单旋
tree=LR(tree);
}
}
}else{
tree->right=Insert(tree->right,X);
if(GetBT(tree)==-2){//平衡因子超过1,自己想为什么是==-2而不是<=-2
if(tree->right->data<X){//右单旋
tree=RR(tree);
}else{//右左单旋
tree=RL(tree);
}
}
}
tree->height=max(GetHeight(tree->left),GetHeight(tree->right))+1;
return tree;
}
//删除节点
AVL Delete(ElementType X, AVL T) { //递归删除,返回根结点
if(T == NULL) {
printf("find null\n");
} else if (X < T->data) {
T->left = Delete(X, T->left); //递归删除左子树,返回根结点(当前结点的右子树结点高度比较大)
if(GetBT(T)== 2) {
AVL p = T->right;
if(GetHeight(p->left) > GetHeight(p->right)) { //当前结点的右子树结点的左子树结点高度比较大,对右边的结点双旋
T = RR(T);
} else { //当前结点的右子树结点的右子树结点高度比较大,对右边的结点单旋
T = RR(T);
}
}
} else if (X > T->data) { //递归删除右子树,返回根结点(当前结点的左子树结点高度比较大)
T->right = Delete(X, T->right);
if(GetBT(T)== -2) {
AVL p = T->left;
if(GetHeight(p->left) < GetHeight(p->right)) { //当前结点的左子树结点的右子树结点高度比较大,对左边的结点双旋
T = LR(T);
} else { //当前结点的左子树结点的左子树结点高度比较大,对左边的结点单旋
T = LL(T);
}
}
} else {
if(T->left != NULL && T->right != NULL) { //待删除的结点有两个孩子结点
if(GetHeight(T->left) > GetHeight(T->right)) { //当前结点的左子树结点高度比较大
AVL p = T->left;
while(p->right != NULL) { //寻找当前结点的前驱结点,用于删除
p = p->right;
}
T->data = p->data;
T->left = Delete(p->data, T->left);
} else { //当前结点的右子树结点高度比较大
AVL p = T->right;
while(p->left != NULL) { //寻找当前结点的后继结点,用于删除
p = p->left;
}
T->data = p->data;
T->right = Delete(p->data, T->right);
}
} else if(T->left == NULL && T->right == NULL){ //待删除的结点无孩子结点
T = NULL;
} else if(T->right == NULL) { //待删除的结点只有左孩子结点
AVL p = T;
T = T->left;
free(p);
} else { //待删除的结点只有右孩子结点
AVL p = T;
T = T->right;
free(p);
}
}
if(T != NULL) {
T->height = max(GetHeight(T->left), GetHeight(T->right)) + 1; //更新根结点高度,左右子节点高度的最大值加1
}
return T;
}
//遍历BBST(其实也只能前中后序遍历选一种,我看前序遍历还比较正常一些)
void TaveralBBST(AVL tree)
{
if(tree){
cout<<tree->data<<" ";
TaveralBBST(tree->left);
TaveralBBST(tree->right);
}
}
//查找元素:如果存在那就返回对应节点,不存在返回小于查找元素的最大值
AVL Find(ElementType X,AVL T)
{
if(T->data==X){
return T;
}else if(T->data<X){
Find(X,T->right);
}else if(T->data>X){
Find(X,T->left);
}else{
return NULL;
}
}
测试用的程序:
#include <conio.h>
#include "BBST.h"
#include <iostream>
#define NUM 10
using namespace std;
int main()
{
//先创建只有根节点的BBST
AVL root;
ElementType data;
cin>>data;
root=BuildBBST(data);
//向BBST中加入元素
node bbst[NUM];
for(int i=0;i<NUM;i++){
cin>>bbst[i].data;
root=Insert(root,bbst[i].data);
}
//输出BBST的高度
cout<<root->height<<endl;
//前序遍历输出所有节点
TaveralBBST(root);
cout<<"\n";
//删除根节点
root=Delete(root->data,root);
//输出新的根节点,前序遍历输出所有节点
cout<<root->data<<endl;
TaveralBBST(root);
//查找节点
ElementType searchData;
cin>>searchData;
AVL child=Find(searchData,root);
if(!child)
cout<<"找不到您要找的节点"<<endl;
else
cout<<child->data;
getch();
return 0;
}
实例: