【数据结构】手撕自平衡二叉树(Adelson-Velsky-Landis Tree)


备注:实现语言为C#(.NET Core),语法和Java别无二致

综述

AVL树是二叉搜索树(Binary Search Tree)的升级版,主要就是为了解决BST在插入有序序列时会退化成链表、使查找性能由 O ( l o g n ) O(logn) O(logn) 变为 O ( n ) O(n) O(n) 的极端情况
其用法与BST一致,都包含:

  • Add()结点添加方法
  • Del()结点删除方法
  • Have()结点查找方法
  • Previous_travel()先序遍历方法
  • Medium_travel()中序遍历方法
  • Post_travel()后序遍历方法

AVL树与BST的最大区别就是AVL是自平衡的。当AVL树的左右子树高度差超过ALLOWED_IMBALANCE(默认为1)时,会进行一系列的结点旋转操作来调节自身的平衡。此操作由balance()函数来实现

话不多说,上代码 ~

第一步 构建结点类

private class AVLNode    // AVL树的结点类
{
    public int data;
    public AVLNode left;
    public AVLNode right;
    public int height;   // 比BST多了height字段,用于记录自身高度

    public AVLNode(int val)
    {
        this.data = val;
        this.right = null;
        this.left = null;
        height = 0;
    }
}

第二步 实现结点添加方法(重点)

// 添加方法的外部API
public void Add(int val)
{
    root = Add(val, root);
    size++;
}
// 递归实现部分
private AVLNode Add(int val, AVLNode node)
{
    if (node == null) return new AVLNode(val);
    if (val < node.data) node.left = Add(val, node.left);
    else if (val > node.data) node.right = Add(val, node.right);
    return balance(node); // 返回左右子树平衡的结点
}

第三步 实现结点删除方法(重难点)

// 外部API
public void Del(int val)
{
    root = Del(val, root);
    size--;
}
// 递归实现部分
private AVLNode Del(int val, AVLNode node)
{
    if (node == null) return null;
    if (val < node.data) node.left = Del(val, node.left);
    else if (val > node.data) node.right = Del(val, node.right);
    else // 找到要删除的结点
    {
        if(node.left == null)
        {
            if (node.right == null) return null; // 叶子结点直接删
            else node = node.right; // 右子树不为空则让右子树替代自身
        }
        else
        {
            if (node.right == null) node = node.left; // 左子树不为空则让左子树替代自身
            else
            { // 左右子树都不空则在右子树中找最小(或左子树中找最大也一样)的结点替代自身
                AVLNode findMin = node.right;
                while (findMin.left != null)
                    findMin = findMin.left;
                node.data = findMin.data;
                node.right = Del(node.data, node.right);
            }
        }
    }
    return balance(node); // 返回左右子树平衡的结点
}

第四步 实现结点的查找方法

// Have方法较为简单,所以使用while循环实现
public bool Have(int val)
{
    AVLNode node = root;
    while(node != null)
    {
        if (val < node.data)
            node = node.left;
        else if (val > node.data)
            node = node.right;
        else
            return true;
    }
    return false;
}

第五步 实现平衡二叉树的遍历算法(先、中、后、层次)

//先序遍历
public void Previous_travel()
{
    Previous_travel(root);
}
private void Previous_travel(AVLNode node)
{
    if (node != null)
    {
        Console.Write(node.data + " ");
        Previous_travel(node.left);
        Previous_travel(node.right);
    }
}

//中序遍历
public void Medium_travel()
{
    Medium_travel(root);
}
private void Medium_travel(AVLNode node)
{
    if (node != null)
    {
        Medium_travel(node.left);
        Console.Write(node.data + " ");
        Medium_travel(node.right);
    }
}

//后序遍历
public void Post_travel()
{
    Post_travel(root);
}
private void Post_travel(AVLNode node)
{
    if (node != null)
    {
        Post_travel(node.left);
        Post_travel(node.right);
        Console.Write(node.data + " ");
    }
}

//层次遍历
public void layer_travel()
{
    Queue<AVLNode> nodes = new Queue<AVLNode>();
    nodes.Enqueue(root);
    AVLNode node = null;

    while (nodes.Count != 0)
    {
        node = nodes.Dequeue();
        if (node != null)
        {
            Console.Write(node.data + " ");
            if (node.left != null)
                nodes.Enqueue(node.left);
            if (node.right != null)
                nodes.Enqueue(node.right);
        }
    }
}

第六步 AVL树平衡算法的实现(重难点)

备注:此处很难理解,需要掌握递归程序设计思想,啃不动的要补补课了。。

//计算结点高度
private int height(AVLNode node)
{
    return node == null ? -1 : node.height;
}

private const int ALLOWED_IMBALLANCE = 1; //允许最大不平衡的程度

//结点平衡方法
private AVLNode balance(AVLNode node)
{
    if (node == null) return null;

    if (height(node.left) - height(node.right) > ALLOWED_IMBALLANCE)
    {
        if (height(node.left.left) >= height(node.left.right)) // 左单旋
            node = rotateLeft(node);
        else // 左双旋
            node = doubleRotateLeft(node);
    }
    else if (height(node.right) - height(node.left) > ALLOWED_IMBALLANCE)
    {
        if (height(node.right.right) >= height(node.right.left)) // 右单旋
            node = rotateRight(node);
        else // 右双旋
            node = doubleRotateRight(node);
    }

    node.height = Math.Max(height(node.left), height(node.right)) + 1; // 更新高度
    return node;
}

// 左单旋算法实现
private AVLNode rotateLeft(AVLNode node)
{
    AVLNode l = node.left;
    node.left = l.right;
    l.right = node;

    // 更新高度
    node.height = Math.Max(height(node.left), height(node.right)) + 1;
    l.height = Math.Max(height(l.left), node.height) + 1;

    return l;
}

// 左双旋算法实现
private AVLNode doubleRotateLeft(AVLNode node)
{
    node.left = rotateRight(node.left);
    return rotateLeft(node);
}

// 右单旋算法实现
private AVLNode rotateRight(AVLNode node)
{
    AVLNode r = node.right;
    node.right = r.left;
    r.left = node;

    // 更新高度
    node.height = Math.Max(height(node.left), height(node.right)) + 1;
    r.height = Math.Max(height(r.right), node.height) + 1;

    return r;
}

// 右双旋算法实现
private AVLNode doubleRotateRight(AVLNode node)
{
    node.right = rotateLeft(node.right);
    return rotateRight(node);
}

完整代码实现

class AVLTree
    {
        private class AVLNode
        {
            public int data;
            public AVLNode left;
            public AVLNode right;
            public int height;

            public AVLNode(int val)
            {
                this.data = val;
                this.right = null;
                this.left = null;
                height = 0;
            }

            public AVLNode(int val, AVLNode r, AVLNode l)
            {
                this.data = val;
                this.right = r;
                this.left = l;
                height = 0;
            }
        }

        private int size;

        public int Size
        {
            get
            {
                return size;
            }
        }

        private AVLNode root;

        public AVLTree()
        {
            size = 0;
            root = null;
        }

        public void Add(int val)
        {
            root = Add(val, root);
            size++;
        }
        public void Del(int val)
        {
            root = Del(val, root);
            size--;
        }
        public bool Have(int val)
        {
            AVLNode node = root;
            while(node != null)
            {
                if (val < node.data)
                    node = node.left;
                else if (val > node.data)
                    node = node.right;
                else
                    return true;
            }
            return false;
        }

        //先序遍历
        public void Previous_travel()
        {
            Previous_travel(root);
        }
        private void Previous_travel(AVLNode node)
        {
            if (node != null)
            {
                Console.Write(node.data + " ");
                Previous_travel(node.left);
                Previous_travel(node.right);
            }
        }

        //中序遍历
        public void Medium_travel()
        {
            Medium_travel(root);
        }
        private void Medium_travel(AVLNode node)
        {
            if (node != null)
            {
                Medium_travel(node.left);
                Console.Write(node.data + " ");
                Medium_travel(node.right);
            }
        }

        //后序遍历
        public void Post_travel()
        {
            Post_travel(root);
        }
        private void Post_travel(AVLNode node)
        {
            if (node != null)
            {
                Post_travel(node.left);
                Post_travel(node.right);
                Console.Write(node.data + " ");
            }
        }

        //层次遍历
        public void layer_travel()
        {
            Queue<AVLNode> nodes = new Queue<AVLNode>();
            nodes.Enqueue(root);
            AVLNode node = null;

            while (nodes.Count != 0)
            {
                node = nodes.Dequeue();
                if (node != null)
                {
                    Console.Write(node.data + " ");
                    if (node.left != null)
                        nodes.Enqueue(node.left);
                    if (node.right != null)
                        nodes.Enqueue(node.right);
                }
            }
        }
    

        private int height(AVLNode node)
        {
            return node == null ? -1 : node.height;
        }

        private AVLNode Add(int val, AVLNode node)
        {
            if (node == null) return new AVLNode(val);
            if (val < node.data) node.left = Add(val, node.left);
            else if (val > node.data) node.right = Add(val, node.right);
            else {}
            return balance(node);
        }

        private AVLNode Del(int val, AVLNode node)
        {
            if (node == null) return null;
            if (val < node.data) node.left = Del(val, node.left);
            else if (val > node.data) node.right = Del(val, node.right);
            else
            {
                if(node.left == null)
                {
                    if (node.right == null) return null;
                    else node = node.right;
                }
                else
                {
                    if (node.right == null) node = node.left;
                    else
                    {
                        AVLNode findMin = node.right;
                        while (findMin.left != null)
                            findMin = findMin.left;
                        node.data = findMin.data;
                        node.right = Del(node.data, node.right);
                    }
                }
            }
            return balance(node);
        }


        //结点平衡方法
        private const int ALLOWED_IMBALLANCE = 1; //允许最大不平衡的程度
        private AVLNode balance(AVLNode node)
        {
            if (node == null) return null;

            if (height(node.left) - height(node.right) > ALLOWED_IMBALLANCE)
            {
                if (height(node.left.left) >= height(node.left.right)) // 左单旋
                    node = rotateLeft(node);
                else // 左双旋
                    node = doubleRotateLeft(node);
            }
            else if (height(node.right) - height(node.left) > ALLOWED_IMBALLANCE)
            {
                if (height(node.right.right) >= height(node.right.left)) // 右单旋
                    node = rotateRight(node);
                else // 右双旋
                    node = doubleRotateRight(node);
            }
            else {}

            node.height = Math.Max(height(node.left), height(node.right)) + 1; // 更新高度
            return node;
        }

        // 左单旋算法实现
        private AVLNode rotateLeft(AVLNode node)
        {
            AVLNode l = node.left;
            node.left = l.right;
            l.right = node;

            // 更新高度
            node.height = Math.Max(height(node.left), height(node.right)) + 1;
            l.height = Math.Max(height(l.left), node.height) + 1;

            return l;
        }

        // 左双旋算法实现
        private AVLNode doubleRotateLeft(AVLNode node)
        {
            node.left = rotateRight(node.left);
            return rotateLeft(node);
        }

        // 右单旋算法实现
        private AVLNode rotateRight(AVLNode node)
        {
            AVLNode r = node.right;
            node.right = r.left;
            r.left = node;

            // 更新高度
            node.height = Math.Max(height(node.left), height(node.right)) + 1;
            r.height = Math.Max(height(r.right), node.height) + 1;

            return r;
        }

        // 右双旋算法实现
        private AVLNode doubleRotateRight(AVLNode node)
        {
            node.right = rotateLeft(node.right);
            return rotateRight(node);
        }

    }

调试代码及运行结果

class Program
{
    static void Main(string[] args)
    {
        string[] nums = Console.ReadLine().Split(" ");
        AVLTree tree = new AVLTree();

        foreach (string num in nums)
            tree.Add(int.Parse(num));

        Console.WriteLine("树中元素的个数为:{0}", tree.Size);
        if (tree.Have(2))
            Console.WriteLine("树中包含2这个元素");
        else
            Console.WriteLine("树中不包含2这个元素");

        Console.Write("先序遍历结果:");
        tree.Previous_travel();
        Console.Write("\n中序遍历结果:");
        tree.Medium_travel();
        Console.Write("\n后序遍历结果:");
        tree.Post_travel();
        Console.Write("\n层序遍历结果:");
        tree.layer_travel();

        Console.Write("\n请输入要删除的元素:");
        int del = int.Parse(Console.ReadLine());
        tree.Del(del);

        Console.Write("删除后先序遍历结果:");
        tree.Previous_travel();
        Console.Write("\n删除后中序遍历结果:");
        tree.Medium_travel();
        Console.Write("\n删除后后序遍历结果:");
        tree.Post_travel();
        Console.Write("\n删除后层序遍历结果:");
        tree.layer_travel();

        Console.ReadKey();
    }
}

运行结果:
在这里插入图片描述平衡方法参考自https://blog.csdn.net/weixin_41186657/article/details/84109017

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值