您的位置:首页 > 理论基础 > 数据结构算法

数据结构之平衡二叉树AVL

2013-11-11 21:38 525 查看
平衡二次树AVL:是二叉查找树的改进版,不会像二叉查找树一样,在碰到序列有序是糟糕成达到O(n),平很二叉树在每次插入的时候,都会试图检查左右子树的高度差是不超过1(包括1),如果超过了,就会调整树的结构,使树一直保持平衡,以至于达到非常好的效率,O(logn).

#include <iostream>
using namespace std;
typedef struct BBNode
{
int m_data;
// 平衡因子,如果【左子树的深度】减去【右子树的深度】,右因为平衡二叉树左右子树的深度查不超过1(包括一),所以factor的值为【-1, 0, 1】
int m_factor;
BBNode* m_lchild;
BBNode* m_rchild;
}BBNode, *BBSTree;

/*
         a             b
        /             / \
       b      =>     c   a
      /
     c
*/
// 向右旋转
void R_Rotate(BBSTree& tree)
{
 // 左孩子
 BBNode* lchild = tree->m_lchild;
 // 【左孩子】已经有指针指向了,所以可以指向别的地方了,那么就指向根【左孩子】的【右孩子】
 tree->m_lchild = lchild->m_rchild;
 // 【左孩子】的【右孩子】已经有指针指向了,那么可以指向根结点了
 lchild->m_rchild = tree;
 tree = lchild;
}

/*
a		       b
\		      / \
b	   =>    a   c
\
c
*/
// 向左旋转
void L_Rotate(BBSTree& tree)
{
BBNode* rchild = tree->m_rchild;
tree->m_rchild = rchild->m_lchild;
rchild->m_lchild = tree;
tree = rchild;
}

/*
a		      a			    c
/		     /			   / \
b	=>      c	     =>	    b   a
\		   /
c		  b
*/
// 调整左子树的平衡
// 1:单旋转-右旋转
// 2: 双旋转-【左子树】先左旋转-再右旋转
void LeftBalance(BBSTree& tree)
{
BBNode* lchild = tree->m_lchild;
// 如果是偏向一边的(根->左孩子->左孩子),只需要单旋转
if (lchild->m_factor == 1)
{
tree->m_factor = 0;
lchild->m_factor = 0;
R_Rotate(tree);
}
// 如果不是偏向一边(根->左孩子->右孩子),则需要双选
// 即先将【左子树】左旋转,再将树右旋转
else if (lchild->m_factor == -1)
{
BBNode* lchild_rchild = lchild->m_rchild;
// 修改【根结点】和【左孩子】的【平衡因子】
switch (lchild_r
bdc6
child->m_factor)
{
case -1:
{
tree->m_factor = 0;
lchild->m_factor = 1;
}break;
case 0:
{
tree->m_factor = 0;
lchild->m_factor = 0;
}break;
case 1:
{
tree->m_factor = -1;
lchild->m_factor = 0;
}break;
}
lchild_rchild->m_factor = 0;
L_Rotate(lchild);
R_Rotate(tree);
}
}

/*
a                   a                       c
\                   \                     / \
b       =>          c          =>       a   b
/                     \
c                       b
*/
// 调整右子树的,两种情况
// 1:只需要单旋转-左旋转
// 2: 双旋转-【右子树】先右旋转-再左旋转
void RightBalance(BBSTree& tree)
{
BBNode* rchild = tree->m_rchild;
// 如果是偏向一边的(根->右孩子->右孩子)
if (rchild->m_factor == -1)
{
tree->m_factor = 0;
rchild->m_factor = 0;
L_Rotate(tree);
}
// 如果不是偏向一边的(根->右孩子->左孩子)
else if (rchild->m_factor == 1)
{
BBNode* rchild_lchild = rchild->m_lchild;
switch (rchild_lchild->m_factor)
{
case -1:
{
tree->m_factor = 1;
rchild->m_factor = 0;
}break;
case 0:
{
tree->m_factor = 0;
rchild->m_factor = 0;
}break;
case 1:
{
tree->m_factor = 0;
rchild->m_factor = -1;
}break;
}
rchild_lchild->m_factor = 0;
L_Rotate(rchild);
R_Rotate(tree);
}
}

// @tree:平衡二叉树
// @e:要插入的元素
// @taller:是否增高了
int insertAVL(BBSTree& tree, int e, bool& taller)
{
// 如果tree不存,则在此处插入结点
if (!tree)
{
BBNode* node = new BBNode;
node->m_data = e;
node->m_factor = 0;	//新结点没有左右孩子,factor自然为0
node->m_lchild = 0;
node->m_rchild = 0;
tree = node;
// 只要是新结点,taller都标记为true,但是它实际上存在着下面三种情况的:
// 1:如果父节点没有左右孩子,则插入node,真的右增高
// 2:如果父节点存在左孩子,插入node作为右孩子,则实际上并未增高
// 3:如果父节点存在右孩子,插入node作为左孩子,则实际上并未增高
// 但是这些都留待上一层的函数里去处理
taller = true;
}
else
{
// 要插入的元素小于当前结点
if (e < tree->m_data)
{
// 将元素插入到当前结点的左子树中
if (!insertAVL(tree->m_lchild, e, taller))
{
// 如果插入失败
return 0;
}
// 子树是不是增高了
if (taller)
{
switch (tree->m_factor)
{
// 如果之前【右子树】高于【左子树】
case -1:
{
// 因为插入的是【左子树】,所以两边的深度相等了
tree->m_factor = 0;
// 当然,因为插入元素之后,高度不变
taller = false;
}break;
// 如果之前【左子树】高度等于【右子树】
case 0:
{
// 因为插入的是【左子树】,所以当前【左子树】高于【右子树】
// 但是还未超过【平衡二叉树】【左右子树】高度差不大于1的限制
tree->m_factor = 1;
taller = true;
}
// 如果之前【左子树】高度大于【右子树】
case 1:
{
// 当前插入的是【左子树】,所以当前【左子树】高于了【右子树】,
// 并且超过了【平衡二叉树】【左右子树】高度差不大于1的限制
// 所以要调整下
LeftBalance(tree);
taller = false;
}
}  // switch
}  // if(taller)
}
else if (e == tree->m_data)
{
return 0;
}
else
{
if (!insertAVL(tree->m_rchild, e, taller))
{
return 0;
}
if (taller)
{
switch(tree->m_factor)
{
// 如果之前【左子树】低于【右子树】
case -1:
{
// 因为当前插入的是【右子树】,所以【右子树】的高度
// 超过了【平衡二次树】的【左右子树】深度差不超过1的限制
// 所以要调整下
RightBalance(tree);
taller = false;
}break;
// 如果之前【左子树】高度等于【右子树】
case 0:
{
// 因为当前插入的是【右子树】,所以【右子树】的高度增高了,
// 但是不会超过【平衡二次树】的【左右子树】深度差不超过1的限制
tree->m_factor = -1;
taller = true;
}break;
// 如果之前【左子树】高于【右子树】
case 1:
{
// 因为当前插入的是【右子树】,所以两边的高度相等了
tree->m_factor = 0;
taller = false;
}break;
}
}
}  // else
}  // else
return 1;
}
 

// 中序遍历
void orderTraver(BBSTree tree)
{
if (tree)
{
orderTraver(tree->m_lchild);
cout<<tree->m_data<<" ";
orderTraver(tree->m_rchild);
}
}

int main()
{
BBSTree tree = 0;
bool taller;
insertAVL(tree, 1, taller);
insertAVL(tree, 2, taller);
insertAVL(tree, 3, taller);
insertAVL(tree, 4, taller);
insertAVL(tree, 5, taller);
insertAVL(tree, 6, taller);
orderTraver(tree);
return 0;
}


 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  平衡二叉树 AVL