博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AVL数
阅读量:5291 次
发布时间:2019-06-14

本文共 5311 字,大约阅读时间需要 17 分钟。

平衡二叉树(AVL树)

AVL树是一种二叉搜索树,并且每个节点的左右子树高度之差最多为1。AVL树是第一个在最坏的情况下保证以O(logn)的时间进行搜索,插入和删除操作的数据结构,AVL树能在对数时间内完成操作的主要思想是在插入和删除的时候花一些时间来保持树的平衡,使树的高度总在O(logn)范围内

插入后不满足AVL树的情况

令x是要插入AVL树种的关键字,首先将x插入树的底部,如果插入后仍是AVL树,则没有问题,否则要对数进行平衡。假设节点A的左子树和右子树在插入后失去平衡(高度差为2),这将分四种情况:

  • 对A的左孩子的左子树进行了一次插入
  • 对A的左孩子的右子树进行了一次插入
  • 对A的右孩子的左子树进行了一次插入
  • 对A的右孩子的右字树进行了一次插入
  • 其中第一和第四种情形对称,第二和第三种情形对称,第一,四可以通过一次单旋转完成调整,

    下图是其中两种,剩两种与它们右对称

     

  • 图(a)插入新节点后,B树的高度是h+2,C树高度是h,为了保持树的平衡需要进行旋转,将B转到树顶,然后根据二叉搜索树的性质调整树的其他部分.
  • 图(b)插入节点后,旋转一个位置不够,需要旋转两个位置. 首先对B进行顺时针旋转,然后对A作顺时针旋转
  •  

    顺时针和逆时针旋转两种方式:

    双旋转的方式

    (首先对B进行逆时针旋转,然后对A进行顺时针旋转)

    (首先对B进行顺时针旋转,然后对A进行逆时针旋转)

    上面两个例子中 A被称作关键节点

    关键节点: 它是插入操作之后非AVL树的最小树的根节点,在插入节点之前必须找到关键节点,从而判断是哪种情况。于是我们在每个节点中记录一个平衡因子,即左右子树的高度之差.对AVL树而言,任意一个节点的平衡因子只能是1,-1或0. 关键节点的平衡因子一定不是0,并且在平衡后高度与插入前相同


    源代码namespace AVLTree{    public class Node    {        public int Value;        public Node Left;        public Node Right;        public int Factor;    }    public class AVLTree    {        private Node root;        private Node ParentNode(int x)        {            Node node = root;            Node parent = null;            while (node != null)            {                if (node.Value == x)                {                    return parent;                }                parent = node;                if (node.Value > x)                {                    node = node.Left;                }                else                {                    node = node.Right;                }            }            throw new Exception(string.Format("{0} has no parent", x));        }        public void Insert(int x)        {            Insert(ref root,x);        }        private void Insert(ref Node tree, int x)        {            Node node = new Node() { Value = x };            if (tree == null)            {                tree = node;            }            if (tree.Value > x)            {                Insert(ref tree.Left,x);                    if (Depth(tree.Left) - Depth(tree.Right) == 2)                {                    if (tree.Left.Value > x)                    {                        R_Rotate(tree);                    }                    else if (tree.Left.Value < x)                    {                        LR_Rotate(tree);                    }                }            }            else if (tree.Value < x)            {                Insert(ref tree.Right,x);                if (Depth(tree.Right) - Depth(tree.Left) == 2)                {                    if (tree.Right.Value < x)                    {                        L_Rotate(tree);                    }                    else if (tree.Right.Value > x)                    {                        RL_Rotate(tree);                    }                }            }        }        public void L_Rotate(Node tree)        {            Node parent = ParentNode(tree.Value);            Node lr = tree.Right;            tree.Right = lr.Left;            lr.Left = tree;            if (parent != null)            {                if (Object.ReferenceEquals(parent.Left, tree))                {                    parent.Left = lr;                }                else if (Object.ReferenceEquals(parent.Right, tree))                {                    parent.Right = lr;                }            }            else            {                root = tree;            }        }        public void R_Rotate( Node tree)        {            Node parent = ParentNode(tree.Value);            Node lc = tree.Left;            tree.Left = lc.Right;            lc.Right = tree;            if (parent != null)            {                if (Object.ReferenceEquals(parent.Left, tree))                {                    parent.Left = lc;                }                else if (Object.ReferenceEquals(parent.Right, tree))                {                    parent.Right = lc;                }            }            else            {                root = lc;            }        }        public void LR_Rotate(Node tree)        {            L_Rotate(tree.Left);            R_Rotate(tree);        }        public void RL_Rotate(Node tree)        {            R_Rotate(tree.Right);            L_Rotate(tree);        }        private int Depth(Node tree)         {            if (tree == null) return 0;            else            {                int dleft = Depth(tree.Left);                     int dright = Depth(tree.Right);                    return (dleft > dright ? dleft + 1 : dright + 1);            }        }        public override string ToString()        {            return Tree(root);        }        private string Tree(Node node)        {            if (node == null)            {                return string.Empty;            }            string left = Tree(node.Left);            string right = Tree(node.Right);            if (!string.IsNullOrEmpty(left) || !string.IsNullOrEmpty(right))            {                return string.Format("{0}({1},{2})", node.Value, Tree(node.Left), Tree(node.Right));            }            else            {                return node.Value.ToString();            }        }        public static void Swap(ref int x, ref int y)        {            int temp = x;            x = y;            y = temp;        }    }}

 

posted on
2016-04-16 20:04 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/phenixyu/p/5399214.html

你可能感兴趣的文章
狄利克雷过程(Dirichlet Process)
查看>>
五子棋项目的实现(二)博弈树算法的描述
查看>>
Hibernate : Disabling contextual LOB creation as createClob() method threw error
查看>>
【bzoj4872】[Shoi2017]分手是祝愿 期望dp
查看>>
字符串元转分
查看>>
thinkphp 防sql注入
查看>>
201521123044 《Java程序设计》第1周学习总结
查看>>
MIT Scheme 的基本使用
查看>>
程序员的“机械同感”
查看>>
在16aspx.com上下了一个简单商品房销售系统源码,怎么修改它的默认登录名和密码...
查看>>
c++回调函数
查看>>
linux下Rtree的安装
查看>>
【Java】 剑指offer(53-2) 0到n-1中缺失的数字
查看>>
Delphi中ListView类的用法
查看>>
bzoj3110: [Zjoi2013]K大数查询 【树套树,标记永久化】
查看>>
[原创]Java 的传值小例子
查看>>
博客第一弹—聊聊HTML的那些事
查看>>
Mysql安装方法及安装问题解决
查看>>
Java动态代理的两种实现方式:
查看>>
PHP trait
查看>>