1 AVL树的定义

AVL树是一种自平衡二叉排序树。它的特点是不论什么一个节点的左子树高度和右子树的高度差在-1,0,1三者之间。

AVL树的不论什么一个子树都是AVL树。

2 AVL树的实现

AVL树本质是一种二叉排序树,所以二叉排序树的不论什么性质AVL树都具有。可是AVL树略微复杂的地方就是AVL树必须满足平衡条件。详细跟BST不同的地方主要体如今插入,删除操作。

插入操作:当插入之后可能会出现不平衡,所以这时候要通过旋转树来实现平衡。

旋转有四种类型,左左,左右,右左,右右。当中左左旋转和右右旋转是镜像的,左右旋转和右左旋转是镜像的,所以实质上就是两种类型的旋转。

针对左左旋转。仅仅须要旋转一次就可以,针对左右旋转,须要运行两次旋转。见下图:

这里採用递归法实现插入和删除操作。使用递归方便的一点是假设函数的參数是引用类型的,当传入一个p->left的时候。我们在当前函数的下层递归的时候,对p进行的赋值操作事实上就是对上层递归中的p->left进行的操作,所以这样就不须要传递父指针了。

3 实现代码

//AVLTree.h

#ifndef DDXX_AVLTREE_H
#define DDXX_AVLTREE_H
#include <iostream>
#include <queue>
using namespace std;
template<typename Type>
class AVLTree
{
struct Node
{
Type e;
Node* left;
Node* right;
int h;
Node(Type _e):e(_e),left(NULL),right(NULL),h(0){}
Node(Type _e,Node* _left,Node* _right,int _h):e(e),left(_left),right(_right),h(_h){}
};
public:
AVLTree();
AVLTree(Type arr[],int nLength);
/*AVLTree(const AVLTree& right);
AVLTree& operator=(const AVLTree& right);*/
~AVLTree();
public:
bool insert(Type e,Node* &p);
void erase(Type e,Node* &p);
Node*& find(Type e)const;
void traverse(Node* p)const;
void traverseByLevel(Node* p)const;
int getLength(){return mLength;}
Node*& getParent(Node* p);
Node*& getRoot(){return mRoot;} //notice the return type
bool empty(){return mRoot==NULL;};
void clear();
void clears(Node* &p);
private:
void rotateLeft(Node* &k2);
void rotateRight(Node* &k2);
void rotateLeftDouble(Node* &p);
void rotateRightDouble(Node* &p);
int height(Node* p)const{ return p == NULL ? -1 : p->h ;}
int max(int x,int y){return x>y?x:y;}
private:
Node* mRoot;
int mLength; };
template<typename Type> AVLTree<Type>::AVLTree():mRoot(NULL),mLength(0)
{
} template<typename Type> AVLTree<Type>::AVLTree(Type arr[],int nLength):mRoot(NULL),mLength(0)
{
for(int i=0;i<nLength;i++)
{
insert(arr[i],mRoot);
}
} template<typename Type> AVLTree<Type>::~AVLTree()
{
clears(mRoot);
}
template<typename Type> bool AVLTree<Type>::insert(Type e,Node* &p)
{
if( p== NULL)
{
p = new Node(e);
mLength++;
}
else if(e < p->e)
{
insert(e,p->left);
if( height(p->left) - height(p->right) == 2)
{
if (e < p->left->e)
rotateLeft(p);
else
rotateLeftDouble(p);
}
}
else if(e > p->e)
{
insert(e,p->right);
if( height(p->left) - height(p->right) == -2)
{
if (e > p->right->e)
rotateRight(p);
else
rotateRightDouble(p);
}
}
else // e ia already exist
{
//return false;
}
p->h = max( height(p->left),height(p->right) )+1;
return true;
} template<typename Type> void AVLTree<Type>::rotateLeft(Node*& k2)
{
Node* k1 = k2->left;
k2->left = k1->right;
k1->right = k2; k1->h = max( height(k1->left),height(k1->right) ) + 1;
k2->h = max( height(k2->left),height(k2->right) ) + 1;
k2 = k1;// join the original node
} template<typename Type> void AVLTree<Type>::rotateRight(Node* &k2)
{
Node* k1 = k2->right;
k2->right = k1->left;
k1->left = k2; k1->h = max( height(k1->left),height(k1->right) ) + 1;
k2->h = max( height(k2->left),height(k2->right) ) + 1;
//k1=k2,由于在insert函数中传入的是p->left或者p->right的引用。所以这里能把根结点赋给其父结点的子节点
k2 = k1;
} template<typename Type> void AVLTree<Type>::rotateLeftDouble(Node*& k3)
{
rotateRight(k3->left);
rotateLeft(k3);
}
template<typename Type> void AVLTree<Type>::rotateRightDouble(Node*& k3)
{
rotateLeft(k3->right);
rotateRight(k3);
} template<typename Type> void AVLTree<Type>::traverse(Node* p)const
{
if( p == NULL)
return;
else
{
traverse(p->left);
cout<<"element:"<<p->e<<endl; //traverse by mid
traverse(p->right);
}
} template<typename Type> void AVLTree<Type>::traverseByLevel(Node* root)const
{
if(root == NULL)
{
cout<<"The tree is empty"<<endl;
return;
}
queue<Node*> que;
que.push(root);
while( !que.empty() )
{
Node* ptr = que.front();
que.pop();
cout<<"element:"<<ptr->e<<" th:"<<height(ptr->left) - height(ptr->right)<<endl;
if(ptr->left != NULL)
que.push(ptr->left);
if(ptr->right != NULL)
que.push(ptr->right);
}
} template<typename Type> typename AVLTree<Type>::Node* & AVLTree<Type>::getParent(Node* p)
{
if( p == m_root)
return NULL;
Node* ptr = m_root;
Node* ptf = ptr;
while( ptr != NULL )
{
if ( ptr->e == p->e )
return ptf;
if ( ptr->e > p->e )
{
ptf = ptr;
ptr = ptr->leftChild;
}
else
{
ptf = ptr;
ptr = ptr->rightChild;
}
}
} template<typename Type> typename AVLTree<Type>::Node*& AVLTree<Type>::find(Type e)const
{
Node* ptr = m_root; while(ptr != NULL)
{
if ( ptr->e == e )
return ptr;
if ( ptr->e > e )
ptr = ptr->leftChild;
else
ptr = ptr->rightChild;
}
//if ( ptr == NULL )
return NULL;
} template<typename Type> void AVLTree<Type>::clears(Node*& p)
{
if( p == NULL )
return;
else
{
clears(p->left);
clears(p->right);
delete p;
p = NULL;
mLength--;
}
} template<typename Type> void AVLTree<Type>::clear()
{
clears(mRoot);
} template<typename Type> void AVLTree<Type>::erase(Type e,Node* &p)
{
if( p == NULL)
return;
if( e > p->e)
{
erase(e,p->right);
if( height(p->left) - height(p->right) == 2)
{
if( height(p->left->left) > height(p->left->right) )
rotateLeft(p);
else
rotateLeftDouble(p);
}
}
else if( e < p->e)
{
erase(e,p->left);
if( height(p->left) - height(p->right) == -2)
{
if( height(p->right->right) > height(p->right->left) )
rotateRight(p);
else
rotateRightDouble(p);
}
}
else if ( e == p->e && p->left!= NULL && p->right!= NULL)
{
Node* pmax = p->left;
while( pmax->right != NULL)
{
pmax = pmax->right;
}
p->e = pmax->e;
erase(p->e,p->left);
}
else //终于的删除会在这里运行
{
Node* pNew = p->left==NULL ? p->right : p->left;
delete p;
p = pNew;
mLength--;
}
if ( p!=NULL)
p->h = max( height(p->left),height(p->right)) + 1;
}
#endif

//main.cpp

#include <iostream>
#include "AVLTree.h"
using namespace std; void main()
{
int Arr[9] = {6,2,8,4,10,0,12,16,14};
AVLTree<int> Tr(Arr,9);
Tr.traverse(Tr.getRoot());
Tr.traverseByLevel(Tr.getRoot()); Tr.erase(14,Tr.getRoot());
Tr.traverse(Tr.getRoot());
Tr.traverseByLevel(Tr.getRoot());
cout<<"Tree's length is:"<<Tr.getLength()<<endl;
Tr.clear();
cout<<"Tree's length is:"<<Tr.getLength()<<endl; }

4 測试结果

C++模板实现的AVL树的更多相关文章

  1. 数据结构图文解析之:AVL树详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  2. AVL树模板

    ///AVL树模板 typedef struct Node ///树的节点 { int val,data; int h; ///以当前结点为根结点的数的高度 int bf; ///平衡因子(左子树高度 ...

  3. PAT甲级题解-1066. Root of AVL Tree (25)-AVL树模板题

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6803291.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  4. 【PAT甲级】1066 Root of AVL Tree (25 分)(AVL树建树模板)

    题意: 输入一个正整数N(<=20),接着输入N个结点的值,依次插入一颗AVL树,输出最终根结点的值. AAAAAccepted code: #define HAVE_STRUCT_TIMESP ...

  5. PAT甲级1123 Is It a Complete AVL Tree【AVL树】

    题目:https://pintia.cn/problem-sets/994805342720868352/problems/994805351302414336 题意: 给定n个树,依次插入一棵AVL ...

  6. 二叉查找树,AVL树,伸展树【CH4601普通平衡树】

    最近数据结构刚好看到了伸展树,在想这个东西有什么应用,于是顺便学习一下. 二叉查找树(BST),对于树上的任意一个节点,节点的左子树上的关键字都小于这个节点的关键字,节点的右子树上的关键字都大于这个节 ...

  7. PAT甲级题解-1123. Is It a Complete AVL Tree (30)-AVL树+满二叉树

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/6806292.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  8. 算法与数据结构(十一) 平衡二叉树(AVL树)

    今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...

  9. AVL树原理及实现(C语言实现以及Java语言实现)

    欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. AVL定义 AVL树是一种改进版的搜索二叉树.对于一般的搜索二叉树而言,如果数据恰好 ...

随机推荐

  1. Redis 数据类型分析 字符串 哈希 列表 集合 有序集合 优缺点 分析 注意事项 存储结构

    一.提高Redis使用性能秘诀 KEY尽量少的原则,能放在1个KEY的就放入1个KEY,KEY开销很大尽量减少与Redis发生的交互次数,能批量的就批量,能事务.管道的就事务.管道从业务架构分析确定使 ...

  2. PHP 和 AJAX MySQL

    AJAX 可用来与数据库进行交互式通信. AJAX 数据库实例 在下面的 AJAX 实例中,我们将演示网页如何使用 AJAX 技术从 MySQL 数据库中读取信息. 在下拉列表中选择一个名字 (测试说 ...

  3. python基础-面向对象(装饰器)

    属性:   @property   @method_name.setter   @method_name.deleter   三个标签都是放在方法的上面来使用,且方法名要和后续使用的   变量名字相一 ...

  4. A. Test for Job

    A. Test for Job Time Limit: 5000ms Case Time Limit: 5000ms Memory Limit: 65536KB   64-bit integer IO ...

  5. [android开发篇] 权限

    Android 应用采用 Java 编程语言编写.Android SDK 工具将您的代码 — 连同任何数据和资源文件 — 编译到一个 APK:Android 软件包,即带有 .apk 后缀的存档文件中 ...

  6. android项目引入第三方库工程出现的问题及解决方案

    一.导入libar库工程 1.使用第三方库工程libary,基本上都是从github上下载,解压后里面有个libary文件夹 2.将libary导入到eclipse中,步骤如下 1)在eclipse包 ...

  7. .NET重构(二):ArrayList,List,IList的联系和区别

    导读:在机房重构的时候,为了降低耦合,不能返回DataTable型数据,而需要转换为泛型集合.我一直使用的就是IList,那天师傅过来帮我挑错,问我:你为什么一直写IList呢,不应该是List吗?好 ...

  8. jenkins之Tomcat7+jdk1.7+jenkins

    目的 在开发中,需要经常频繁的对测试服务器进行部署,而且在多人协同中开发经常遇到的问题就是别人更新了他的代码,而你去更新你的代码时并没有更新到别人的代码,导致测试环境的代码不是最新,当然这个问题也好解 ...

  9. 刷题总结——疫情控制(NOIP2012提高组)

    题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...

  10. 洛谷P3143 [USACO16OPEN]钻石收藏家Diamond Collector

    题目描述 Bessie the cow, always a fan of shiny objects, has taken up a hobby of mining diamonds in her s ...