数据结构之平衡二叉树AVL

平衡二次树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_rchild->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;
}


 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值