博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
平衡二叉树(AVL树)
阅读量:4046 次
发布时间:2019-05-25

本文共 4054 字,大约阅读时间需要 13 分钟。

平衡二叉树是在二叉搜索树的基础上增加了限制:

①:树的深度为logN。

②:每个节点的左子树和右子树的高度最多差一的二叉搜索树。

基本操作:调整!!!

引入平衡因子:左右子树的高度差。

当平衡因子绝对值大于等于2的时候,就需要调整。

单旋转比较简单,直接把被破坏节点下一个节点提上去,然后再根据二叉搜索树的特点进行换儿子即可。如下图:

实现:

#include
#include
#define ElementType inttypedef struct BiNode{    ElementType Data;    int Height;    struct BiNode* Left;    struct BiNode* Right;} BiNode, *BinTree,*Position;int Height(Position P){    if(!p)return 0;    else return P->Height;}//为什么非要用这个函数?直接用结构体中的不行吗?---NULL!!!Position Single_Rotate_With_Left(Position K2)//把k2的左儿子k1提上去,k2当k1的右儿子。{ Position K1 = K2->Left; K2->Left = K1->Right;//换儿子 K1->Right = K2;//提上去 K2->Height = max(Height(K2->Left), Height(K2->Right)) + 1; K1->Height = max(Height(K1->Left), Height(K1->Right)) + 1; return K1;}Position Single_Rotate_With_Right(Position K2){ Position K1 = K2->Right; K2->Right = K1->Left; K1->Left = K2; K2->Height = max(Height(K2->Left), Height(K2->Right)) + 1; K1->Height = max(Height(K1->Left), Height(K1->Right)) + 1; return K1;}

双旋转是“麻烦节点”在左儿子的右边,或者右儿子的左边。如下图:这时候是把麻烦节点提上去,然后再进行儿子的交换即可。

实现:可以通过两次单旋转进行完成,避免了换儿子的过程。

Position Double_Rotate_With_Left(Position K3){	K3->Left = Single_Rotate_With_Right(K3->Left);	return Single_Rotate_With_Left(K3);}Position Double_Rotate_With_Right(Position K3){	K3->Right = Single_Rotate_With_Left(K3->Right);	return Single_Rotate_With_Right(K3);}Position Double_Rotate_With_Left(Position K3){    Position K2=K3->Left->Right,K1=K3->Left;       K3->Left=K2->Right;//换儿子       K2->Right=K3;//提       K1->Right=K2->Left;//换儿子       K2->Left=K1;//提}

AVL树的插入,在二叉搜索树插入的基础上,增添调整就可以!

注意这里有递归回溯。(拓展GCD有没有)。

至于删除,我的思路是假设是删除左边了,这时候要看根节点右边的树高是否比左边树高大于等于2,然后进而根据右子树对应的左树高和右树高,右大于左,那就要对根节点进行RR旋转,否则RL旋转。(网上都是引入的平衡因子,也就是高度差,我这种想法的正确与否,考完期末再写个例子进行检验~!插入的历程是正确的(直接在黑书上拿来的。))。

BinTree Insert( ElementType X, BinTree BST )if( !BST ){    BST = (Bintree)malloc(sizeof(struct TreeNode));    BST->Data = X;    BST->Left = BST->Right = NULL;    BST->Height=1;}else if( X < BST->Data ){    BST->Left = Insert( X, BST->Left);    if(Height(BST->Left)-Height(BST->Right)==2)//自底向上回溯        if(X
Left->Data)            BST=Single_Rotate_With_Left(BST);        else BST=Position Double_Rotate_With_Left(BST);}else if( X > BST->Data ){    BST->Right = Insert( X, BST->Right);    if(Height(BST->Right)-Height(BST->Left)==2)        if(X>BST->Right->Data)   BST=Single_Rotate_With_Right(BST);        else BST=Double_Rotate_With_Right(BST);}/* else X已经存在,什么都不做 */BST->Height=max(Height(BST->left),Height(BST->Right))+1;//更新树高return BST;}BinTree Delete( ElementType X, BinTree BST ){ Position Tmp; if( !BST ) printf("要删除的元素未找到"); else if( X < BST->Data ) { BST->Left = Delete( X, BST->Left); /* 左子树递归删除 */ if(Height(BST->Right)-Height(BST->Left)==2) if(Height(BST->Right->Right)>=Height(BST->Right->Left)) Single_Rotate_With_Right(BST); else Double_Rotate_With_Right(BST); } else if( X > BST->Data ) { BST->Right = Delete( X, BST->Right); if(Height(BST->Left)-Height(BST->Right)==2) if(Height(BST->Left->Left)>=Height(BST->Left->Right)) Single_Rotate_With_Left(BST); else Double_Rotate_With_Left(BST); }/* 右子树递归删除 */ else /*找到要删除的结点 */ if( BST->Left && BST->Right ) { /*被删除结点有左右两个子结点 */ Tmp = FindMin( BST->Right ); /*在右子树中找最小的元素填充删除结点*/ BST->Data = Tmp->Data; BST->Right = Delete( BST->Data, BST->Right); /*在删除结点的右子树中删除最小元素*/ if(Height(BST->Right)-Height(BST->Left)==2) if(Height(BST->Right->Right)>=Height(BST->Right->Left)) Single_Rotate_With_Right(BST); else Double_Rotate_With_Right(BST); } else { /*被删除结点有一个或无子结点*/ Tmp = BST; if( !BST->Left ) /* 有右孩子或无子结点*/ BST = BST->Right; else if( !BST->Right ) /*有左孩子或无子结点*/ BST = BST->Left; free( Tmp ); } BST->Height=max(Height(BST->left),Height(BST->Right))+1;//更新树高 return BST;}

你可能感兴趣的文章
解决国内NPM安装依赖速度慢问题
查看>>
Brackets安装及常用插件安装
查看>>
Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
查看>>
fastcgi_param 详解
查看>>
Nginx配置文件(nginx.conf)配置详解
查看>>
标记一下
查看>>
IP报文格式学习笔记
查看>>
autohotkey快捷键显示隐藏文件和文件扩展名
查看>>
Linux中的进程
查看>>
学习python(1)——环境与常识
查看>>
学习设计模式(3)——单例模式和类的成员函数中的静态变量的作用域
查看>>
自然计算时间复杂度杂谈
查看>>
当前主要目标和工作
查看>>
使用 Springboot 对 Kettle 进行调度开发
查看>>
一文看清HBase的使用场景
查看>>
解析zookeeper的工作流程
查看>>
搞定Java面试中的数据结构问题
查看>>
慢慢欣赏linux make uImage流程
查看>>
linux内核学习(7)脱胎换骨解压缩的内核
查看>>
以太网基础知识
查看>>