AVL,平衡二叉查找树。删除,插入,查找的复杂度都是O(logn)。它是一棵二叉树。对于每个节点来说,它的左孩子的键值都小于它,右孩子的键值都大于它。对于任意一个节点,它的左右孩子的高度差不大于1。树的高度的定义为:空节点的高度为0,非空节点的高度为左右孩子高度的最大值加1。

在插入删除过程中,会出现不平衡的时候。这时,会通过以下方式进行旋转保持树的平衡。下图中每一列最后一行是旋转后的结果,上面两行是对应的初始化状态。

1 插入。在以某个节点为根的子树中插入一个节点后,有可能使得该节点的左右子树的高度差大于1(其实此时的高度差是2),那么视情况进行LL,RR,LR,RL四种旋转中的一种可维持树的平衡。

2 删除。删除的键值小于当前节点键值时,在左子树中删除;大于当前节点键值时在右子树中进行删除;否则就是删除当前节点。删除当前节点时,找到后继节点,然后将后继结点替换当前节点,然后递归地删除这个后继结点即可。

template<class _ValyeType,class _FuncType>
class CAVLTree
{
protected:
struct AVLTreeNode
{
_ValyeType m_iValue;
AVLTreeNode* m_pLeftSon;
AVLTreeNode* m_pRightSon;
int m_nHeight;
int m_nValueNumber;
};
AVLTreeNode* m_pRoot;
_FuncType* m_pCompareFunc; AVLTreeNode* _NewNode()
{
AVLTreeNode* pNode=new AVLTreeNode;
pNode->m_pLeftSon=nullptr;
pNode->m_pRightSon=nullptr;
pNode->m_nHeight=;
pNode->m_nValueNumber=;
return pNode;
}
AVLTreeNode* _NewNode(const _ValyeType& iValue)
{
AVLTreeNode* pNode=new AVLTreeNode;
pNode->m_pLeftSon=nullptr;
pNode->m_pRightSon=nullptr;
pNode->m_nHeight=;
pNode->m_iValue=iValue;
pNode->m_nValueNumber=;
return pNode;
} int _Height(AVLTreeNode* pNode)
{
if(pNode) return pNode->m_nHeight;
return ;
} void _PushUp(AVLTreeNode* pNode)
{
if(!pNode) return;
const int nLeftSonHeight=_Height(pNode->m_pLeftSon);
const int nRightSonHeight=_Height(pNode->m_pRightSon);
if(nLeftSonHeight<nRightSonHeight) pNode->m_nHeight=+nRightSonHeight;
else pNode->m_nHeight=+nLeftSonHeight;
} /**
pNode的左孩子将成为根,返回新的树根
**/
AVLTreeNode* _LLRotate(AVLTreeNode* pNode)
{
if(!pNode) return pNode;
AVLTreeNode* pLeftSon=pNode->m_pLeftSon;
pNode->m_pLeftSon=pLeftSon->m_pRightSon;
pLeftSon->m_pRightSon=pNode;
_PushUp(pNode);
_PushUp(pLeftSon);
return pLeftSon;
} /**
pNode的右孩子将成为根,返回新的树根
**/
AVLTreeNode* _RRRotate(AVLTreeNode* pNode)
{
if(!pNode) return pNode;
AVLTreeNode* pRightSon=pNode->m_pRightSon;
pNode->m_pRightSon=pRightSon->m_pLeftSon;
pRightSon->m_pLeftSon=pNode;
_PushUp(pNode);
_PushUp(pRightSon);
return pRightSon;
}
/**
pNode的左孩子的右孩子将成为根,返回新的树根
**/
AVLTreeNode* _LRRotate(AVLTreeNode* pNode)
{
if(!pNode) return pNode;
pNode->m_pLeftSon=_RRRotate(pNode->m_pLeftSon);
return _LLRotate(pNode);
} /**
pNode的右孩子的左孩子将成为根,返回新的树根
**/
AVLTreeNode* _RLRotate(AVLTreeNode* pNode)
{
if(!pNode) return pNode;
pNode->m_pRightSon=_LLRotate(pNode->m_pRightSon);
return _RRRotate(pNode);
} AVLTreeNode* _Rotate(AVLTreeNode* pNode)
{
if(!pNode) return pNode;
if(==_Height(pNode->m_pLeftSon)-_Height(pNode->m_pRightSon))
{
if(_Height(pNode->m_pLeftSon->m_pLeftSon)>=_Height(pNode->m_pLeftSon->m_pRightSon))
{
pNode=_LLRotate(pNode);
}
else pNode=_LRRotate(pNode);
}
else if(==_Height(pNode->m_pRightSon)-_Height(pNode->m_pLeftSon))
{
if(_Height(pNode->m_pRightSon->m_pLeftSon)>=_Height(pNode->m_pRightSon->m_pRightSon))
{
pNode=_RLRotate(pNode);
}
else pNode=_RRRotate(pNode);
}
return pNode;
} AVLTreeNode* _Insert(AVLTreeNode* pRoot,const _ValyeType& iInsertValue)
{
if(nullptr==pRoot)
{
pRoot=_NewNode(iInsertValue); return pRoot;
}
else if(m_pCompareFunc(iInsertValue,pRoot->m_iValue))
{
pRoot->m_pLeftSon=_Insert(pRoot->m_pLeftSon,iInsertValue);
if(==_Height(pRoot->m_pLeftSon)-_Height(pRoot->m_pRightSon))
{
if(m_pCompareFunc(iInsertValue,pRoot->m_pLeftSon->m_iValue))
{
pRoot=_LLRotate(pRoot);
}
else
{
pRoot=_LRRotate(pRoot);
}
}
}
else if(m_pCompareFunc(pRoot->m_iValue,iInsertValue))
{
pRoot->m_pRightSon=_Insert(pRoot->m_pRightSon,iInsertValue);
if(==_Height(pRoot->m_pRightSon)-_Height(pRoot->m_pLeftSon))
{
if(m_pCompareFunc(iInsertValue,pRoot->m_pRightSon->m_iValue))
{
pRoot=_RLRotate(pRoot);
}
else
{
pRoot=_RRRotate(pRoot);
}
}
}
else
{
++pRoot->m_nValueNumber;
} _PushUp(pRoot);
return pRoot;
} AVLTreeNode* _Delete(AVLTreeNode* pRoot,const _ValyeType& iDeleteValue)
{
if(nullptr==pRoot) return nullptr;
if(m_pCompareFunc(iDeleteValue,pRoot->m_iValue))
{
pRoot->m_pLeftSon=_Delete(pRoot->m_pLeftSon,iDeleteValue);
}
else if(m_pCompareFunc(pRoot->m_iValue,iDeleteValue))
{
pRoot->m_pRightSon=_Delete(pRoot->m_pRightSon,iDeleteValue);
}
else
{
if(==--pRoot->m_nValueNumber)
{
if(nullptr==pRoot->m_pLeftSon)
{
AVLTreeNode* pTmp=pRoot;
pRoot=pRoot->m_pRightSon;
delete pTmp;
}
else if(nullptr==pRoot->m_pRightSon)
{
AVLTreeNode* pTmp=pRoot;
pRoot=pRoot->m_pLeftSon;
delete pTmp;
}
else
{
AVLTreeNode* pTmp=pRoot->m_pRightSon;
while(pTmp->m_pLeftSon) pTmp=pTmp->m_pLeftSon;
pRoot->m_iValue=pTmp->m_iValue;
pRoot->m_pRightSon=_Delete(pRoot->m_pRightSon,pRoot->m_iValue);
}
}
else
{
return pRoot;
}
}
_PushUp(pRoot);
if(pRoot&&pRoot->m_pLeftSon) pRoot->m_pLeftSon=_Rotate(pRoot->m_pLeftSon);
if(pRoot&&pRoot->m_pRightSon) pRoot->m_pRightSon=_Rotate(pRoot->m_pRightSon);
if(pRoot) pRoot=_Rotate(pRoot);
return pRoot;
} public:
CAVLTree(_FuncType* pCompareFunc):m_pRoot(nullptr),m_pCompareFunc(pCompareFunc) {} void Insert(const _ValyeType& iInsertValue)
{
m_pRoot=_Insert(m_pRoot,iInsertValue);
} void Delete(const _ValyeType& iDeleteValue)
{
m_pRoot=_Delete(m_pRoot,iDeleteValue);
} int Find(const _ValyeType& iSearchValue)
{
AVLTreeNode* pCurrent=m_pRoot;
while()
{
if(!pCurrent) break;
if(m_pCompareFunc(iSearchValue,pCurrent->m_iValue))
{
pCurrent=pCurrent->m_pLeftSon;
}
else if(m_pCompareFunc(pCurrent->m_iValue,iSearchValue))
{
pCurrent=pCurrent->m_pRightSon;
}
else return pCurrent->m_nValueNumber;
}
return ;
} };

AVL学习笔记的更多相关文章

  1. 尚学堂JAVA基础学习笔记

    目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  4. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  5. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  6. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  7. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  8. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  9. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

随机推荐

  1. 修改linux下mysql目录权限

    1.进入当前目录:例cd /srun3/mysql 2.修改权用户限 chown -R mysql ipt_authd_remote(表示给ipt_authd_remotemysql权限) 3.修改用 ...

  2. 似是而非的k=sqrt(n)

    //题目:输入一个大于3的整数n,判定它是否为素数(prime,又称质数)#include <stdio.h>#include <math.h>int main(){int n ...

  3. Openstack的error僵尸实例的解决办法

    在我们对集群环境进行各种调整的情况下,很容易产生一些僵尸实例. 僵尸实例主要是没有该主机,但是在dashboard上,数据库中存在,解决办法网络上有的人给出了繁杂的修改数据库的方法,其实按照下面的命令 ...

  4. php 缓存加速器软件

    Xcache 和 memcached 是两个不同层面的缓存,不存在可比性.Xcache 是 php 底层的缓存,它将PHP程式编译成字节码(byte code),再透过服务器上安装对应的程式来执行PH ...

  5. 一个基于和围绕Docker生态环境构建的早期项目列表

    https://blog.docker.com/2013/07/docker-projects-from-the-docker-community/

  6. JSP页面显示乱码

    下面的显示页面(display.jsp)就出现乱码: <html> <head> <title>JSP的中文处理</title> <meta ht ...

  7. 理解Linux中断 (1)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/7425685 版权声明:本文为博主原创文章,未经博主允许不得转载. 一直认为,理解中断是理解内核 ...

  8. IE11打不开网页, 所有菜单都被禁用了。

    估计是安装完PPS之后,PPS安装程序附加了一些加载项到浏览器,而我在安装时强制禁用了它的加载项引起的. 解决方法是重置IE设置,命令为:inetcpl.cpl,点击高级选项卡的重置即可.

  9. WebService工作原理

    1.WebService工作原理-SOAP 当客户端调用一个WebService的方法时,首先将方法名称和需要传递的参数包装成XML,也就是SOAP包,通过HTTP协议传递到服务器端,然后服务器端解析 ...

  10. SQLServer学习笔记<>相关子查询及复杂查询

    二.查询缺少值的查询 在这里我们加入要查询2008年每一天的订单有多少?首先我们可以查询下订单表的订单日期在2008年的所有订单信息. 1 select distinct orderdate,coun ...