【1】为什么需要平衡二叉树?

矛盾是推进事物向前发展的源动力。

那么平衡二叉树是从哪里来?肯定是有矛盾存在的。请看下面的分析:

【2】什么是平衡二叉树?

平衡二叉树的基本认识:

【3】平衡二叉树的构建原理

平衡二叉树的形成肯定是有一定规律可循的,那么平衡二叉树的“生长”原理是什么呢?

请看程老师下面的构建示例以及详细讲解:

关于平衡二叉树的旋转分为以下四种情况:

【4】平衡二叉树的实现

平衡二叉树的实现代码如下:

 #include <iostream>
using namespace std; template<class Type>
class AVLtree; template<class Type>
class TNode
{
friend class AVLtree<Type>;
private:
Type data;
int balance; // 平衡因子
TNode<Type> *leftChild, *rightChild;
public:
TNode(const Type &x = Type(),TNode<Type> *left = NULL,TNode<Type> *right = NULL)
: data(x)
, leftChild(left)
, rightChild(right)
, balance()
{}
}; template<class Type>
class AVLtree
{
private:
TNode<Type> *root;
private:
void RightBalance(TNode<Type> * &r,bool &action);
void LeftBalance(TNode<Type> *&r,bool &action);
void Insert(TNode<Type> * &root,const Type &x,bool &action);
void LeftLeft(TNode<Type> * &r);
void RightRight(TNode<Type> * &r);
void LeftRight(TNode<Type> *&r);
void RightLeft(TNode<Type> *&r);
TNode<Type> *Parent(TNode<Type> *p,TNode<Type> *cur);
TNode<Type> *FindNodeNext(TNode<Type> *cur);
void DeleTNode(TNode<Type> *&cur,TNode<Type> *par);
void Remove(TNode<Type> * &r,const Type &x,bool &action);
void InOrder(TNode<Type> *p);
public:
AVLtree();
void Insert(const Type &bt);
TNode<Type> *Parent(TNode<Type> *cur);
void Remove(const Type &x);
void InOrder();
}; // 右平衡处理过程
template<class Type>
void AVLtree<Type>::RightBalance(TNode<Type> * &r, bool &action)
{
TNode<Type> *rightsub = r->rightChild, *leftsub = NULL;
switch (rightsub->balance) //判断右子树的平衡因子
{
case -: // RR型
r->balance = ;
rightsub->balance = ;
RightRight(r); //RR型处理
action = false;
break;
case :
break;
case : // RL型
leftsub = rightsub->leftChild;
switch (leftsub->balance) // 判断左子树的平衡因子
{
case : // RL型
r->balance = ;
rightsub->balance = ;
leftsub->balance = ;
break;
case : // RLL型
r->balance = ;
leftsub->balance = ;
rightsub->balance = -;
break;
case -: // RLR型
rightsub->balance = ;
leftsub->balance = ;
r->balance= -;
break;
}
RightLeft(r); // RL折线型转换处理
action = false;
break;
}
}
// 折线型LR处理
template<class Type>
void AVLtree<Type>::LeftRight(TNode<Type> *&r)
{
RightRight(r->leftChild); // 转换为LL型(一条直线)
LeftLeft(r); // LL型处理
}
// 折线型RL处理
template<class Type>
void AVLtree<Type>::RightLeft(TNode<Type> *&r)
{
LeftLeft(r->rightChild); // 先转换为RR型(一条直线)
RightRight(r); // RR型处理
}
// 1. 把RL转换为RR 2. LL型处理
template<class Type>
void AVLtree<Type>::LeftLeft(TNode<Type> * &r)
{
TNode<Type> *cur = r; // cur暂存r
r = r->leftChild; // 改变r就是改变根
cur->leftChild = r->rightChild;// 改变暂存cur 实现衔接
r->rightChild = cur; // 根的右子树置为cur
}
// 1. 把LR转换为LL 2. RR型处理
template<class Type>
void AVLtree<Type>::RightRight(TNode<Type> * &r)
{
TNode<Type> *cur = r; // cur暂存r
r = r->rightChild; // 改变r就是改变根
cur->rightChild = r->leftChild;// 改变暂存cur 实现衔接
r->leftChild = cur; // 根的左子树置为cur
}
// 左平衡处理过程
template<class Type>
void AVLtree<Type>::LeftBalance(TNode<Type> *&r, bool &action)
{
TNode<Type> *leftsub = r->leftChild;
TNode<Type> *rightsub = leftsub->rightChild;
switch (leftsub->balance)
{
case :// LL型
leftsub->balance = ;
r->balance = ;
LeftLeft(r);
action = false;
break;
case :
action = false;
break;
case -:// LR型
switch (rightsub->balance)
{
case :// LR型
r->balance = ;
rightsub->balance = ;
leftsub->balance = ;
break;
case -:// LRR型
r->balance = ;
rightsub->balance = ;
leftsub->balance = ;
break;
case :// LRL型
rightsub->balance = ;
leftsub->balance = ;
r->balance = -;
break;
}
LeftRight(r); // LR折线型转换处理
action = false;
break;
}
}
// Insert主函数
template<class Type>
void AVLtree<Type>::Insert(TNode<Type> * & root, const Type &x, bool &action)
{
if (NULL == root)
{
root = new TNode<Type>(x);
return;
}
else if (x > root->data)
{
Insert(root->rightChild, x, action);
if (action) // 右子树插入成功
{
switch (root->balance) // 需要重置根的平衡因子
{
case : // 表示左子树已经存在,现再插入右子树成功
root->balance = ; //平衡因子置0
break;
case : // 表示之前平衡,现再插入右子树成功
root->balance = -; //平衡因子置1
break;
case -: // 表示右子树已经存在,现再插入右子树成功
RightBalance(root, action); //右平衡
break;
}
}
}
else if (x < root->data)
{
Insert(root->leftChild, x, action);
if (action) // 左子树插入成功
{
switch (root->balance) // 需要重置根的平衡因子
{
case : // 平衡左子树
LeftBalance(root, action);
break;
case :
root->balance = ;
break;
case -:
root->balance = ;
action = false;
break;
}
}
}
else
cout << "数据" << x << "重复!" << endl;
}
// 查找当前节点的父节点
template<class Type>
TNode<Type> *AVLtree<Type>::Parent(TNode<Type> *p, TNode<Type> *cur)
{
if (NULL == p || NULL == cur|| p == cur)
return NULL;
if (cur == p->leftChild || cur == p->rightChild)
return p; if (p->data < cur->data)
return Parent(p->rightChild, cur);
else
return Parent(p->leftChild, cur);
}
// 查找当前结点的后继 (先序遍历的后继)
template<class Type>
TNode<Type> *AVLtree<Type>::FindNodeNext(TNode<Type> *cur)
{
if (NULL == cur)
return NULL;
TNode<Type> *p = cur->rightChild;
while (p->leftChild != NULL)
{
p = p->leftChild;
}
return p;
}
//////////////////////////////////////////////////////////////////////
/////////////////////////////////删除节点
template<class Type>
void AVLtree<Type>::DeleTNode(TNode<Type> *&cur, TNode<Type> *par)
{
if (NULL == cur)
return;
// 情况一:删除的是根节点,那么它的父节点必定为NULL
if (NULL == par)
{ // cur可能是根结点,并且树仅仅只有一个根
if (NULL == cur->rightChild && NULL == cur->leftChild)
{
delete cur;
cur = NULL;
return;
}
// 单分支的树
if (NULL == cur->rightChild)
{ // 右子树不存在
TNode<Type> *p = cur;
cur = cur->leftChild;
delete p;
p = NULL;
return;
}
if (NULL == cur->leftChild)
{ // 左子树不存在
TNode<Type> *q = cur;
cur = cur->rightChild;
delete q;
q = NULL;
return;
}
}
// 情况二:删除的属于双分支的节点
if (cur->leftChild != NULL && cur->rightChild != NULL)
{
TNode<Type> *p = FindNodeNext(cur); // 锁定先序遍历的后继
// 情况一:
if (cur->rightChild == p)
{ // 说明右子树仅仅只有一个节点
cur->balance += ; // 删除之后平衡因子改变
cur->data = p->data; // 填充数据,意味着改变删除对象
cur->rightChild = p->rightChild; // 衔接数据
delete p; //删除节点p
p = NULL;
return;
}
// 情况二:
// 否则
TNode<Type> *q = Parent(p); // 找到父节点
if (q->balance != ) // 不等于0,说明删除后会影响根结点的平衡因子
cur->balance += ; // 调整根节点的平衡因子
// 否则
q->balance -= ; // 删除的是左节点,所以加一
cur->data = p->data; // 填充数据,意味着改变删除对象 q->leftChild = p->rightChild; // 衔接数据 // 最后才可以动手删除节点 删除节点 释放内存
delete p;
p = NULL;
return;
}
// 情况三:单分支(其中包括了叶子节点的情况)
if (NULL == cur->leftChild)
{
TNode<Type> *p = cur;
if (cur == par->leftChild)
par->leftChild = cur->rightChild; // 衔接数据
else
par->rightChild = cur->rightChild; // 衔接数据 delete p;
p = NULL;
return;
}
if (NULL == cur->rightChild)
{
TNode<Type> *q = cur;
if (cur == par->leftChild)
par->leftChild = cur->leftChild;
else
par->rightChild = cur->leftChild; delete q;
q = NULL;
return;
}
}
// 删除过程的主函数
template<class Type>
void AVLtree<Type>::Remove(TNode<Type> * &r, const Type &x, bool &action)
{
if (NULL == r)
return;
if (x == r->data)
{
TNode<Type> *cur = r; // 确定数据的节点信息
TNode<Type> *par = Parent(r);// 确定当前结点的父节点
DeleTNode(r, par); // 删除当前指针
return;
}
else if (x > r->data)
{ // 右边查找
Remove(r->rightChild, x, action);
if (action)
{
switch (r->balance)
{
case -: // 若原来为1,现在删除了右节点,应该为0
r->balance = ;
break;
//若原来为-1,现在又再右枝上删除了节点,
//树一定不平衡,需要左平衡调整
case :
LeftBalance(r, action);
action = false;
break;
case : // 若原来为0,现在删除了右节点,应该为-1
r->balance = ;
action = false;
break;
}
}
}
else if (x < r->data)
{
Remove(r->leftChild, x, action);
if (action)
{
switch (r->balance)
{
case -:// 若原来为1,现在又再左枝上删除了节点,
// 树一定不平衡,需要右平衡调整
RightBalance(r, action);
break;
case :// 若原来为-1,现在删除了左节点,应该为0
r->balance = ;
break;
case :// 若原来为0,现在删除了左节点,应该为1
r->balance = -;
action = false;
break;
}
}
}
} template<class Type>
AVLtree<Type>::AVLtree(): root(NULL)
{}
template<class Type>
void AVLtree<Type>::Insert(const Type &bt)
{
bool action = true;
Insert(root, bt, action);
}
template<class Type>
TNode<Type> *AVLtree<Type>::Parent(TNode<Type> *cur)
{
return Parent(root, cur);
}
template<class Type>
void AVLtree<Type>::Remove(const Type &x)
{
bool action = true;
Remove(root, x, action);
}
template<class Type>
void AVLtree<Type>::InOrder(TNode<Type> *p)
{
if (p != NULL)
{
InOrder(p->leftChild);
cout << p->data << " ";
InOrder(p->rightChild);
}
}
template<class Type>
void AVLtree<Type>::InOrder()
{
InOrder(root);
cout << endl;
}

Good  Good Study, Day  Day  Up.

顺序  选择  循环  总结

查找(AVL平衡二叉树)的更多相关文章

  1. 数据结构中很常见的各种树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

    数据结构中常见的树(BST二叉搜索树.AVL平衡二叉树.RBT红黑树.B-树.B+树.B*树) 二叉排序树.平衡树.红黑树 红黑树----第四篇:一步一图一代码,一定要让你真正彻底明白红黑树 --- ...

  2. 3.1 C语言_实现AVL平衡二叉树

    [序] 上节我们实现了数据结构中最简单的Vector,那么来到第三章,我们需要实现一个Set set的特点是 内部有序且有唯一元素值:同时各种操作的期望操作时间复杂度在O(n·logn): 那么标准的 ...

  3. 数据结构【查找】—平衡二叉树AVL

    /*自己看了半天也没看懂代码,下次再补充说明*/ 解释: 平衡二叉树(Self-Balancing Binary Search Tree 或Height-Balanced Binary Search ...

  4. 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

    树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: BST树 ...

  5. AVL平衡二叉树

    AVL树 1.若它的左子树不为空,则左子树上所有的节点值都小于它的根节点值. 2.若它的右子树不为空,则右子树上所有的节点值均大于它的根节点值. 3.它的左右子树也分别可以充当为二叉查找树. 例如: ...

  6. 查找->动态查找表->平衡二叉树

    文字描述 平衡二叉树(Balanced Binary Tree或Height-Balanced Tree) 因为是俄罗斯数学家G.M.Adel’son-Vel’skii和E.M.Landis在1962 ...

  7. InnoDB索引概述,二分查找法,平衡二叉树

    索引是应用程序设计和开发的一个重要方面.如果索引太多,应用的性能可能会受到影响:如果索引太少,对查询性能又会产生影响.要找到一个合适的平衡点,这对应用的性能至关重要. 如果知道数据的使用,从一开始就应 ...

  8. PAT A1123 Is It a Complete AVL Tree (30 分)——AVL平衡二叉树,完全二叉树

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  9. AVL平衡二叉树实现,图解分析,C++描述,完整可执行代码

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

随机推荐

  1. 《Maven实战》阅读笔记

    java -versionmvn -vmvn help:system m2eclipse maven->install MAVEN_OPTS: -Xms128m -Xmx512mmvn clea ...

  2. http://www.cnblogs.com/dumuqiao/p/3654702.html?utm_source=tuicool&utm_medium=referral

    http://www.cnblogs.com/dumuqiao/p/3654702.html?utm_source=tuicool&utm_medium=referral

  3. python笔记 - day7-1 之面向对象编程

    python笔记 - day7-1 之面向对象编程 什么时候用面向对象: 多个函数的参数相同: 当某一些函数具有相同参数时,可以使用面向对象的方式,将参数值一次性的封装到对象,以后去对象中取值即可: ...

  4. Android标签云控件:TagCloudLinkView

    可以完成添加.删除.选择操作的标签控件,可以自定样式(颜色等),可删除的标签末尾带有'×'符号.和Android-Cloud-TagView-Plus(见正文相关代码)类似. 1.layout in ...

  5. idea 的问题

    IDEA的maven项目中,默认源代码目录下的xml等资源文件并不会在编译的时候一块打包进classes文件夹,而是直接舍弃掉. 如果使用的是Eclipse,Eclipse的src目录下的xml等资源 ...

  6. Java基础——数组应用之StringBuilder类和StringBuffer类

    接上文:Java基础——数组应用之字符串String类 一.StringBuffer类 StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和 ...

  7. MySQL内存使用分析

    转自: http://www.jb51.net/article/38936.htm 本篇文章是对MySQL内存的使用说明(全局缓存+线程缓存)进行了详细的分析介绍,需要的朋友参考下    首先我们来看 ...

  8. 修改最大打开文件数和最大proc数量

    1.vim /etc/profile  增加 ulimit -n 10240 ulimit -u 10240 2.修改/etc/security/limits.conf *      soft     ...

  9. ASP.NET页面传值之Server.Transfer 和Response.Direct

    先看实例: B.apsx:         public string TextBox1Text         {             get             {             ...

  10. Snapchat面经(师兄的)

    给一个LinkedList环,给其中任一个节点的reference,求删去LinkedList中所有value=k的点 我的想法:假设给定的点事ListNode oneNode, 设置ListNode ...