平衡二叉树

二叉排序树

有关二叉排序树的概念与操作,移步Hear

平衡二叉树概念

  • 特殊类型的二叉排序树。二叉排序树的查找性能取决于二叉树的结构。树的高度越小,查找速度越快。
    注意:如果连二叉排序树都不是,那肯定不是平衡二叉树。
  • 如果非空,左子树与右子树深度之差的绝对值不超过1.
  • 左子树与右子树也是平衡二叉树。

结点定义

它基本和二叉排序树差不多,就是多了个记录结点高度(用来计算平衡因子)的字段。

typedef int KeyType;
typedef int OtherInfo;

   //----------二叉排序树存储表示-----------
typedef struct{						
	KeyType key;										//关键字项 
	OtherInfo info;										//其他数据信息 
													
}ElemType;

typedef struct BSTNode {
	ElemType data;						//每个结点的数据域包括关键字项和其他信息 
	struct BSTNode *lchild;
	struct BSTNode *rchild;							    
	int nHeight;   						/*树的高度,可以计算平衡因子*/                                                                                                                                                                                                                                                       
} BSTNode,*BSTree;

平衡二叉树的操作

  • 查找

  • 插入

  • 创建

  • 删除

    以上操作和二叉排序树一样,主要区别在于插入过程中如果发现插入破坏了平衡需要调整。下面重点说一说怎么调整(旋转)。

平衡二叉树的平衡调整方法

  • LL型

    指插入以A为根的左子树的左子树上破坏了平衡。
    在这里插入图片描述
    插入7或10之后53的平衡因子变为2,高了,怎么降低?那就是把高的转下来(顺时针)。主要就是 根和图中三角形那 发生了变化。三角形那可以为空。

    static BSTree SingleRotateWithLeft(BSTree pNode)	//LL型 
    {
        BSTNode *pNode1;
    
        pNode1 = pNode->lchild;				//图中9
        pNode->lchild = pNode1->rchild;
        pNode1->rchild = pNode;
    
        /*结点的位置变了, 要更新结点的高度值*/
        pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
        pNode1->nHeight = Max(Height(pNode1->lchild), pNode->nHeight) + 1;
    
        return pNode1;
    }
    
    • RR型

    指插入以A为根的右子树的右子树上破坏了平衡。
    在这里插入图片描述
    插入58或70之后17的平衡因子变为-2,高了,怎么降低?那就是把高的转下来(逆时针)。主要就是 根和图中三角形那 发生了变化。三角形那可以为空。

    static BSTree SingleRotateWithRight(BSTree pNode)			//RR型
    {
        BSTNode *pNode1;
    
        pNode1 = pNode->rchild;		//图中53
        pNode->rchild = pNode1->lchild;
        pNode1->lchild = pNode;
    
        /*结点的位置变了, 要更新结点的高度值*/
        pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
        pNode1->nHeight = Max(Height(pNode1->rchild), pNode->nHeight) + 1;
    
        return pNode1;
    }
    

    返回顶部

    • LR型

    指插入以A为根的左子树的右子树上破坏了平衡。
    在这里插入图片描述
    插入25或35之后53的平衡因子为2,需要旋转,一步不能解决,那就转两次。
    先把53的左子树进行RR型旋转,得到中间图,再把中间图进行LL型旋转即可。

    static BSTree DoubleRotateWithLeft(BSTree pNode)		//LR型
    {
        pNode->lchild = SingleRotateWithRight(pNode->lchild);
    
        return SingleRotateWithLeft(pNode);
    }
    
    • RL型

    指插入以A为根的右子树的左子树中破坏了平衡。
    在这里插入图片描述
    插入55或59之后53的平衡因子为-2,需要旋转,一步不能解决,那就转两次。
    先把53的右子树进行LL型旋转,得到中间图,再把中间图进行RR型旋转即可。

    static BSTree DoubleRotateWithRight(BSTree pNode)
    {
        pNode->rchild = SingleRotateWithLeft(pNode->rchild);	//RL型
    
        return SingleRotateWithRight(pNode);
    }
    

返回顶部

总的代码:

#include <iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;

#define Max(a,b) ((a)>(b)?(a):(b))

typedef int KeyType;
typedef int OtherInfo;

   //----------二叉排序树存储表示-----------
typedef struct{						
	KeyType key;										//关键字项 
	OtherInfo info;										//其他数据信息 
													
}ElemType;

typedef struct BSTNode {
	ElemType data;						//每个结点的数据域包括关键字项和其他信息 
	struct BSTNode *lchild;
	struct BSTNode *rchild;							    
	int nHeight;   						/*树的高度,可以计算平衡因子*/                                                                                                                                                                                                                                                       
} BSTNode,*BSTree;


void InsertBST(BSTree &T,ElemType e);	/*插入操作*/
BSTree SearchBST(BSTree T,KeyType key);	/*查找操作*/
bool delete_BSTree(BSTree &T,int key);	/*删除操作*/

/*打印操作*/
void PreOrder(BSTree T);				//递归先序遍历 
void InOrder(BSTree T);					//递归中序遍历 

static int Height(BSTree pNode);

/*旋转操作*/
static BSTree SingleRotateWithLeft(BSTree pNode);
static BSTree SingleRotateWithRight(BSTree pNode);
static BSTree DoubleRotateWithLeft(BSTree pNode);
static BSTree DoubleRotateWithRight(BSTree pNode);

void PreOrder(BSTree T){//递归先序遍历 
	if(T!=NULL){
		cout<<T->data.key<<" ";
		PreOrder(T->lchild);
		PreOrder(T->rchild);
	}
}

void InOrder(BSTree T){//递归中序遍历 
	if(T!=NULL){
		InOrder(T->lchild);
		cout<<T->data.key<<" ";
		InOrder(T->rchild);
	}
}

BSTree SearchBST(BSTree T,KeyType key) {
 	if ((!T) || key == T->data.key)
        return T;
    else if (key < T->data.key)
        return SearchBST(T->lchild, key);
    else return SearchBST(T->rchild, key);
}

/*得到节点的高度以计算平衡因子*/
static int Height(BSTree pNode)
{
    if (NULL == pNode)
        return 0;
    return pNode->nHeight;
}

void InsertBST(BSTree &T,ElemType e)
{
	if(!T){										//找到插入位置 
		BSTree S=new BSTNode;					//新节点保存数据 
		S->data=e;
		S->nHeight = 0;
		S->lchild=S->rchild=NULL;
		T=S;									//把新结点放到已找到的插入位置 
	}
    else if(e.key < T->data.key){
    	InsertBST(T->lchild,e); 
 
    	if (Height(T->lchild) - Height(T->rchild) == 2)    /*AVL树不平衡*/
        {
        	cout<<"因为"<<T->data.key<<"左孩子高度"<<Height(T->lchild);
	        cout<<"大于右孩子高度"<<Height(T->rchild)<<endl;
            if (e.key < T->lchild->data.key)         
            {  	             /*插入到了左子树左边, 做单旋转*/  
	            cout<<"发生LL型旋转"<<endl;
                T = SingleRotateWithLeft(T);
            }
            else           
            {   			/*插入到了左子树右边, 做双旋转*/
            	cout<<"发生LR型旋转"<<endl;
                T = DoubleRotateWithLeft(T);
            }
        }
	}		
  	else if(e.key > T->data.key) {
  		
  		InsertBST(T->rchild,e); 
        if (Height(T->rchild) - Height(T->lchild) == 2)    /*AVL树不平衡*/
        {
        	cout<<"因为"<<T->data.key<<"左孩子高度"<<Height(T->lchild);
	        cout<<"小于右孩子高度"<<Height(T->rchild)<<endl;
            if (e.key > T->rchild->data.key)
            {	/*插入到了右子树右边, 做单旋转*/
            	cout<<"发生RL旋转"<<endl;
                T = SingleRotateWithRight(T);
            }
            else 
            {	/*插入到了右子树左边, 做双旋转*/
            	cout<<"发生RR旋转"<<endl;
                T = DoubleRotateWithRight(T);
            }
        }
	} 		
  	else{
  		cout<<"已有此值~"<<endl;
  		return;
	}
	T->nHeight = Max(Height(T->lchild), Height(T->rchild)) + 1;
}

void delete_Node1(BSTree &p)	
{ 
	BSTree q,s;
	if(!p->lchild)	//由于这个if在前面,所以左右子树均为空的情况会在这里处理 
	{	//如果左子树为空,则只需重接其右子树
		q = p;
		p = p->rchild ;
		free(q);
	}
	else if(!p->rchild)
	{	//如果右子树为空,则只需重接其左子树
		q = p;
		p = p->lchild;
		free(q);
	}
	else
	{	//如果左右子树都不为空,这里采取修改左子树的方法,也可以修改右子树,方法类似
		s = p->lchild;		//取待删节点的左孩子结点
 
		while(s->rchild)	//找到中序遍历时会得到的直接前驱 
			s = s->rchild;
		s->rchild = p->rchild;	//将p的右子树接为s的右子树
		q = p;
		p = p->lchild;		//将p的左子树直接接到其父节点的左子树上
		free(q);
	}
}
 
void delete_Node2(BSTree &p)
{
	BSTree q,s;		
	if(!p->lchild)		//由于这个if在前面,所以左右子树均为空的情况会在这里处理 
	{	//如果左子树为空,则只需重接其右子树
		q = p;
		p = p->rchild ;
		free(q);
	}
	else if(!p->rchild)
	{	//如果右子树为空,则只需重接其左子树
		q = p;
		p = p->lchild;
		free(q);
	}
	else
	{	//如果左右子树都不为空,采取修改左子树的方法,也可以修改右子树,方法类似
		q = p;
		s = p->lchild;		//取待删节点的左节点
		while(s->rchild)		
		{		//找到中序遍历时会得到的直接前驱 
			q = s;
			s = s->rchild;
		}
		//用s来替换待删节点p
		p->data = s->data;  
		//根据情况,将s的左子树重接到q上
		if(p != q)
			q->rchild = s->lchild;
		else
			q->lchild =s->lchild;
		free(s);
	}
}

bool delete_BSTree(BSTree &T,int key)
{
	//不存在关键字为key的节点
	if(!T)
		return false;
	else
	{	
		if(SearchBST(T,key))      //查找到关键字为key的节点
		{
			//delete_Node1(T);
			delete_Node2(T);
			return true;			
		}
		else  
		{
			cout<<"查无此值~"<<endl; 
			return false;			
		}                 
	}
}

void CreateBST(BSTree &T) {					
			
	T=NULL;
	ElemType e; 
	cout << "请输入值:0结束"<<endl;			
	cin >> e.key;
	
	while (e.key!=0) {
		InsertBST(T,e);	
		cout << "请继续输入"<<endl;		
		cin>>e.key;	
	}
}

void destroy_BSTree(BSTree pTree)	//递归销毁二叉排序树
{
	if(pTree)
	{
		if(pTree->lchild)
			destroy_BSTree(pTree->lchild);
		if(pTree->rchild)
			destroy_BSTree(pTree->rchild);
		free(pTree);
		pTree = NULL;
	}
}

static BSTree SingleRotateWithLeft(BSTree pNode)	//LL型 
{
    BSTNode *pNode1;

    pNode1 = pNode->lchild;
    pNode->lchild = pNode1->rchild;
    pNode1->rchild = pNode;

    /*结点的位置变了, 要更新结点的高度值*/
    pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
    pNode1->nHeight = Max(Height(pNode1->lchild), pNode->nHeight) + 1;

    return pNode1;
}
 
static BSTree SingleRotateWithRight(BSTree pNode)			//RR型
{
    BSTNode *pNode1;

    pNode1 = pNode->rchild;
    pNode->rchild = pNode1->lchild;
    pNode1->lchild = pNode;

    /*结点的位置变了, 要更新结点的高度值*/
    pNode->nHeight = Max(Height(pNode->lchild), Height(pNode->rchild)) + 1;
    pNode1->nHeight = Max(Height(pNode1->rchild), pNode->nHeight) + 1;

    return pNode1;
}

static BSTree DoubleRotateWithLeft(BSTree pNode)		//LR型
{
    pNode->lchild = SingleRotateWithRight(pNode->lchild);

    return SingleRotateWithLeft(pNode);
}

static BSTree DoubleRotateWithRight(BSTree pNode)
{
    pNode->rchild = SingleRotateWithLeft(pNode->rchild);	//RL型

    return SingleRotateWithRight(pNode);
}

//int main(){
//	BSTree T;
//	CreateBST(T);
//	cout<<"删除前"<<endl;
//	cout<<"先序遍历:";
//	PreOrder(T); 
//	cout<<endl<<"中序遍历:";
//	InOrder(T);
//	cout<<"请输入删除的关键字"<<endl;
//	int i;
//	cin>>i;				
//	while (i!=0) {
//		delete_BSTree(T,i);
//		InOrder(T);
//		cout << "请继续输入"<<endl;		
//		cin>>i;	
//	}
//	cout<<"删除后"<<endl;
//	InOrder(T);
//	return 0;
//}

int main()
{
    int i;
    ElemType e;
    BSTree T = NULL;

    srand((unsigned int)time(NULL));
    
    for (i = 0; i < 10; ++i)
    {
        e.key = rand()%100+1;
        printf("%d\n", e.key);
        InsertBST(T,e);
    }

    cout<<"先序遍历:";
	PreOrder(T); 
	cout<<endl<<"中序遍历:";
	InOrder(T);

    destroy_BSTree(T);

    return 0;
}

运行结果:

随机产生10个数字构建平衡二叉树,重复的产生值当然是插不进去的。
在这里插入图片描述
由运行结果的先序遍历和中序遍历可推导出这颗二叉树为:
在这里插入图片描述
可知构建的二叉树是平衡二叉树。

返回顶部

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值