平衡二叉树

        平衡二叉树,是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1。有两位俄罗斯数学家G.M.Adelson-Velskii和E.M.Landis在1962年共同发明一种解决平衡二叉树的算法,所以不少资料也称这样的平衡二叉树为AVL树。

        平衡因子(Balance Factor):二叉树上结点的左子树深度减去右子树深度的值。那么平衡二叉树上所有节点的平衡因子只可能是:-1,0和1。

        最小不平衡子树:距离插入节点最近的,且平衡因子的绝对值大于1的节点为根的子树。

        对于最小不平衡树进行平衡调整的方法:当最小不平衡子树根节点的平衡因子大于1时,右旋,小于1时就左旋。此时还需要比较根节点对应的子节点BF与根节点BF是否符号相同。即:最小不平衡子树根节点为2时,查看其左孩子节点是否为-1,为-1时则先以左孩子节点为根节点进行左旋,然后以最小不平衡树根节点进行右旋,否则直接以最小不平衡树根节点进行单向右旋;若最小不平衡子树根节点为-2时则查看其右孩子节点是否为1,为1时则先以右孩子节点为根节点进行右旋,然后以最小不平衡树根节点进行左旋,否则直接以最小不平衡树根节点进行单向左旋。

       

        AVL插入操作:过程如二叉查找树的插入,需要栈记录查找路径。插入新增节点后依次更新栈中其父节点的BF,若其父节点BF为+2或-2,则该节点为最小不平衡子树的根节点,依照上述调整方法进行平衡旋转调整,而且平衡调整后其最小不平衡子树的高度与插入节点前相同,这样其高度未变话,此时栈中如果仍有节点,则其BF并没有随插入新节点而变化,至此平衡调整过程结束。注意:若栈中节点进行更新过程中遇到BF更新为0,则说明剩余的节点没必要进行更新,这时整个平衡调整过程也可以结束。

        AVL删除过程:与二叉查找树相似,分三种情况。

           1、删除节点无孩子节点,即删除叶子节点。记录查找到该节点的路径,删除节点后回溯更新路径中每个节点的BF。若更新为0,有可能子树高度有变化, 继续回溯;若更新为-1或+1,表明子树高度并未发生变化,停止继续回溯更新;若为+2或-2,则进行相应的旋转调整,调整后查看子树根节点BF,与上述相同为0继续回溯,为-1或+1则停止回溯。

            2、删除节点仅有左子树或右子树,将其孩子节点提到当前节点位置,然后回溯更新路径中每个节点BF,过程与1中相同。

            3、删除节点左子树和右子树都存在,搜索删除节点的路径并记录,然后找到其中序遍历的前驱结点,该路径也记录在栈中,该前驱结点一定属于1或2 的情景,交换删除节点和前驱节点的Key值,删除前驱节点,并从前驱节点的父节点开始回溯更新BF,进行必要的旋转调整。


性能分析:
       平衡二叉树的查找、插入和删除在平均和最坏情况下都是O(logN)[1],只是删除时可能需要多次的旋转调整,较插入略微复杂。一个AVL树的高度最多为1.44log(N+2)-1.328,但实际上高度只略大于logN[2]。


参考文献:
[1] 百度百科. http://baike.baidu.com/view/593144.htm
[2] Mark Allen Weiss. 《数据结构与算法分析——Java语言描述》[M]. 北京:机械工业出版社, 2011. 92.


相应的代码如下:

/**
 * 
 * @ClassName:AVLNode
 * @Description: AVL的节点结构
 * @author Gu
 * @date 2013-2-26上午9:39:13
 * 
 */
class AVLNode
{
	private Integer nodeKey;
	private Integer BF;
	private AVLNode lchild;
	private AVLNode rchild;

	public Integer getNodeKey()
	{
		return nodeKey;
	}
	public void setNodeKey(Integer nodeKey)
	{
		this.nodeKey = nodeKey;
	}
	public Integer getBF()
	{
		return BF;
	}
	public void setBF(Integer bF)
	{
		BF = bF;
	}
	public AVLNode getLchild()
	{
		return lchild;
	}
	public void setLchild(AVLNode lchild)
	{
		this.lchild = lchild;
	}
	public AVLNode getRchild()
	{
		return rchild;
	}
	public void setRchild(AVLNode rchild)
	{
		this.rchild = rchild;
	}

}

	// get height of given key node
	private Integer getHeight(AVLNode aNode)
	{
		if (aNode == null)
		{
			return 0; // null indicates 0;
		} else
		{
			Integer l = getHeight(aNode.getLchild()) + 1;
			Integer r = getHeight(aNode.getRchild()) + 1;
			return (l > r) ? l : r;
		}
	}

	// get BF of given key node
	private void calBF(AVLNode aNode)
	{
		aNode.setBF(getHeight(aNode.getLchild()) - getHeight(aNode.getRchild()));
	}

	// right rotate
	private AVLNode r_rotate(AVLNode root)
	{
		AVLNode leftNode = root.getLchild();
		AVLNode temp = leftNode.getRchild();
		leftNode.setRchild(root);
		root.setLchild(temp);

		// update BF
		calBF(leftNode);
		calBF(root);

		return leftNode;
	}

	// left rotate
	private AVLNode l_rotate(AVLNode root)
	{
		AVLNode rightNode = root.getRchild();
		AVLNode temp = rightNode.getLchild();
		rightNode.setLchild(root);
		root.setRchild(temp);

		// update BF
		calBF(rightNode);
		calBF(root);

		return rightNode;
	}

	// right balance rotate
	private AVLNode r_balance_rotate(AVLNode root)
	{
		AVLNode _root = root.getLchild();
		// left rotate
		root.setLchild(l_rotate(_root));
		// right rotate
		return r_rotate(root);
	}

	// left balance rotate
	private AVLNode l_balance_rotate(AVLNode root)
	{
		AVLNode _root = root.getRchild();
		// right rotate
		root.setRchild(r_rotate(_root));
		// left rotate
		return l_rotate(root);
	}
 
    // reconstruct new link
    private void reconstructLink(AVLNode pre, AVLNode p)
    {
        if (pre.getNodeKey() < p.getNodeKey())
        {
            pre.setRchild(p);
        } else
        {
            pre.setLchild(p);
        }
    }

    private final static int LH = 1;
    private final static int EH = 0;
    private final static int RH = -1;

    private final static int LLH = 2;
    private final static int RRH = -2;
	/**
	 * AVL树的插入
	 * 
	 * @Title: insertAVLTree
	 * @Description: AVL树插入一个节点
	 * @param root
	 *            AVL树根节点
	 * @param key
	 *            插入节点的Key
	 * @return AVLNode AVL树根节点
	 */
	public AVLNode insertAVLTree(AVLNode root, Integer key)
	{
		AVLNode p = root;
		if (p == null) // root is NULL!
		{
			p = new AVLNode();
			p.setNodeKey(key);
			p.setLchild(null);
			p.setRchild(null);
			p.setBF(EH);
			return p;
		} else
		{
			// record search path
			Stack<AVLNode> s = new Stack<AVLNode>();
			while (p != null)
			{
				if (p.getNodeKey() == key)
				{
					// exists!
					return root;
				} else if (p.getNodeKey() < key)
				{
					s.push(p);
					p = p.getRchild();
				} else
				{
					s.push(p);
					p = p.getLchild();
				}
			}
			// insert node key
			AVLNode avlNode = new AVLNode();
			avlNode.setBF(EH);
			avlNode.setLchild(null);
			avlNode.setRchild(null);
			avlNode.setNodeKey(key);

			p = s.pop();
			if (p.getNodeKey() < key)
			{
				p.setRchild(avlNode);
			} else
			{
				p.setLchild(avlNode);
			}
			s.push(p); // form full path

			// update path node BF
			while (!s.isEmpty())
			{
				p = s.pop();
				// update BF
				calBF(p);
				// ----------------deal with BF--------------------//
				switch (p.getBF())
				{
					case EH :
						// Stop!
						s.clear(); // insert proceed is OK, and over!
						break;
					case LH :
					case RH :
						// do nothing... continue next...
						break;
					case LLH :
						if (p.getLchild().getBF() == RH)
						{
							if (s.isEmpty())
							{
								// p is root!
								root = r_balance_rotate(p);
							} else
							{
								// p is not root!
								reconstructLink(s.peek(), r_balance_rotate(p));
							}
						} else if (p.getLchild().getBF() == LH)
						{
							if (s.isEmpty())
							{
								root = r_rotate(p);
							} else
							{
								reconstructLink(s.peek(), r_rotate(p));
							}
						}
						return root;

					case RRH :
						if (p.getRchild().getBF() == LH)
						{
							if (s.isEmpty())
							{
								root = l_balance_rotate(p);
							} else
							{
								reconstructLink(s.peek(), l_balance_rotate(p));
							}
						} else if (p.getRchild().getBF() == RH)
						{
							if (s.isEmpty())
							{
								root = l_rotate(p);
							} else
							{
								reconstructLink(s.peek(), l_rotate(p));
							}
						}
						return root;
				}
			}
			return root;
		}
	} 

    /**
     * AVL树的删除
     * 
     * @Title: deleteAVLTree
     * @Description:AVL树中删除一个节点
     * @param root
     *            AVL树根节点
     * @param key
     *            删除节点的Key
     * @return AVLNode AVL树根节点
     */
    public AVLNode deleteAVLTree(AVLNode root, Integer key)
    {
        AVLNode p;
        // AVL tree is NULL!
        if ((root == null)
                || (root.getNodeKey() == key && root.getLchild() == null && root
                        .getRchild() == null))
        {
            return null;
        } else
        {
            Stack<AVLNode> s = new Stack<AVLNode>();
            // search key and record path
            p = root;
            while (p != null)
            {
                if (p.getNodeKey() == key)
                {
                    break;
                } else if (p.getNodeKey() > key)
                {
                    // search left
                    s.push(p);
                    p = p.getLchild();
                } else if (p.getNodeKey() < key)
                {
                    s.push(p);
                    p = p.getRchild();
                }
            }

            if (p == null)
            {
                // AVL tree not exists key !
                return root;
            } else
            {
                // delete key is root!
                if (s.isEmpty())
                {
                    if (root.getLchild() == null)
                    {
                        // root right child is not null!
                        return root.getRchild();
                    } else if (root.getRchild() == null)
                    {
                        return root.getLchild();
                    } else
                    {
                        // root left child and right child are not null!
                        // in this case, process is the same as (key is not root
                        // and its left/right child is not null!)
                    }
                }
                // delete key is not root!
                if ((p.getLchild() == null) && (p.getRchild() == null))
                {
                    deleteAVLNode(s.peek(), null, key);
                } else if (p.getLchild() == null)
                {
                    deleteAVLNode(s.peek(), p.getRchild(), key);
                } else if (p.getRchild() == null)
                {
                    deleteAVLNode(s.peek(), p.getLchild(), key);
                } else
                {
                    // search in-order pre node
                    s.push(p); // put p into s
                    AVLNode temp = p.getLchild();
                    AVLNode tempPre = p;
                    while (temp.getRchild() != null) // search right child
                    {
                        s.push(temp);
                        tempPre = temp;
                        temp = temp.getRchild();
                    }
                    // swap key
                    p.setNodeKey(temp.getNodeKey());
                    // delete temp
                    if (tempPre == p)
                    {
                        tempPre.setLchild(temp.getLchild());
                    } else
                    {
                        tempPre.setRchild(temp.getLchild());
                    }
                }

                // adjust the tree from s
                while (!s.isEmpty())
                {
                    p = s.pop();
                    // calculate the BF of p
                    calBF(p);
                    if ((p.getBF() == LH) || (p.getBF() == RH))
                    {
                        // stop!
                        break;
                    } else if (p.getBF() == EH)
                    {
                        // do nothing...
                        continue;
                    } else if (p.getBF() == LLH)
                    {
                        // right balance rotate
                        if (p.getLchild().getBF() == RH)
                        {
                            if (s.isEmpty())
                            {
                                root = r_balance_rotate(p);
                            } else
                            {
                                reconstructLink(s.peek(),
                                        s.push(r_balance_rotate(p)));
                            }
                        } else
                        {
                            // right rotate
                            if (s.isEmpty())
                            {
                                root = r_rotate(p);
                            } else
                            {
                                reconstructLink(s.peek(), s.push(r_rotate(p)));
                            }
                        }
                    } else if (p.getBF() == RRH)
                    {
                        // left balance rotate
                        if (p.getRchild().getBF() == LH)
                        {
                            if (s.isEmpty())
                            {
                                root = l_balance_rotate(p);
                            } else
                            {
                                reconstructLink(s.peek(),
                                        s.push(l_balance_rotate(p)));
                            }
                        } else
                        {
                            if (s.isEmpty())
                            {
                                root = l_rotate(p);
                            } else
                            {
                                reconstructLink(s.peek(), s.push(l_rotate(p)));
                            }
                        }
                    }
                }
            }
            return root;
        }
    }

    private void deleteAVLNode(AVLNode pre, AVLNode pchild, Integer key)
    {
        if (pre.getNodeKey() > key)
        {
            pre.setLchild(pchild);
        } else
        {
            pre.setRchild(pchild);
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值