基于链表的AVL实现(java)——树结构学习(2)

上一节中介绍并实现了二叉搜索树,它有一个明显缺陷,当按某种顺序插入Node构建的树高度接近N,那么增删查的时间复杂度退化为O(N),AVL可以有效的弥补这方面缺陷,简单来说AVL在每次完成BST的增删操作后,会对树结构进行旋转以维持树的高度在\log_{2}N

树的高度

以Node为根的树的高度等于Node到每个叶子的最大值,规定null的高度为0,一个Node的高度为1,三个Node组成的满二叉树高度为2,以此类推。

//以该Node为根的树高度
    public static int getHeight(Node node) {
        if (node == null) return 0;
        return Math.max(getHeight(node.leftChild), getHeight(node.rightChild)) + 1;
    }

不平衡Node

如果一个Node的左子树高度与右子树高度相差绝对值大于一,则认为该Node是不平衡的。

//从当前Node向上查找第一个不平衡Node
    public static Node unbalancedNode(Node node) {
        if(node == null)return null;
        do {
            if (Math.abs(getHeight(node.leftChild) - getHeight(node.rightChild)) > 1)
                return node;
            node = node.getParent();
        } while (node != null);
        return null;
    }

旋转操作

旋转是AVL维持树高度的核心方法,对于一个Node向父Node方向查找的第一个不平衡Node(UnbalancedNode),如果引起它不平衡的Leaf位于左Node的左子树则对UnbalancedNode使用LL旋转,如果该Leaf位于右Node的右子树则对UnbalancedNode使用RR旋转,同理还有LR旋转与RL旋转。

更新后的Node类

Node与BST中的Node几乎一致,不过此次增加两种操作,第一种操作是返回以该Node为根的树高度;第二种操作是从该Node沿父Node方向查找第一不平衡的Node。

 

package TreeStructure.BinaryTree;

import org.jetbrains.annotations.NotNull;

public class Node<T extends Comparable<T>> implements Comparable<Node<T>> {
    private T data;
    //父Node
    private Node<T> parent;
    //左子Node
    private Node<T> leftChild;
    //右子Node
    private Node<T> rightChild;


    public Node(T data) {
        this.data = data;
    }

    public Node(T data, Node<T> parent) {
        this.data = data;
        this.parent = parent;
    }

    @Override
    public int compareTo(@NotNull Node<T> tNode) {
        return this.data.compareTo(tNode.getData());
    }

    public void visit() {
        //节点的访问动作写在这里
//        System.out.println("Parent:" + (this.parent == null ? "null" : this.parent.data));
        System.out.println("Node:" + data);
//        System.out.println("Left Child:" + (this.leftChild == null ? "null" : this.leftChild.data));
//        System.out.println("Right Child:" + (this.rightChild == null ? "null" : this.rightChild.data));
//        System.out.println();
    }

    //判断该Node是否有子Node
    public boolean hasChild() {
        return this.getLeftChild() != null || this.getRightChild() != null;
    }

    public boolean isLeaf() {
        return this.getLeftChild() == null && this.getRightChild() == null;
    }

    public boolean hasLeftChild() {
        return this.getLeftChild() != null;
    }

    public boolean hasRightChild() {
        return this.getRightChild() != null;
    }

    //判断该Node是否为parentBinaryNode的左子Node
    public boolean isLeftChildOf(Node<T> parentNode) {
        if (parentNode != null && parentNode.getLeftChild() == this) return true;
        return false;
    }

    public boolean isRightChildOf(Node<T> parentNode) {
        if (parentNode != null && parentNode.getRightChild() == this) return true;
        return false;
    }

    public Node<T> getParent() {
        return parent;
    }

    //返回Node右子树中的最小值
    public Node<T> getSuccessor() {
        if (rightChild == null) return null;
        Node<T> current = rightChild;
        while (current.hasLeftChild()) current = current.getLeftChild();
        return current;
    }

    public void setParent(Node<T> parent) {
        this.parent = parent;
    }


    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Node<T> getLeftChild() {
        return leftChild;
    }

    public void setLeftChild(Node<T> leftChild) {
        this.leftChild = leftChild;
    }

    public Node<T> getRightChild() {
        return rightChild;
    }

    public void setRightChild(Node<T> rightChild) {
        this.rightChild = rightChild;
    }


    //从当前Node向上查找第一个不平衡Node
    public static Node unbalancedNode(Node node) {
        if(node == null)return null;
        do {
            if (Math.abs(getHeight(node.leftChild) - getHeight(node.rightChild)) > 1)
                return node;
            node = node.getParent();
        } while (node != null);
        return null;
    }

    //以该Node为根的树高度
    public static int getHeight(Node node) {
        if (node == null) return 0;
        return Math.max(getHeight(node.leftChild), getHeight(node.rightChild)) + 1;
    }
}

AVL类(继承自BST类)

插入操作

AVL的插入操作可以先按照BST的方法插入,然后寻找插入Node的父Node方向的第一不平衡Node,对该UnbalancedNode完成旋转,因此需要让BST的插入方法返回该插入Node

删除操作

 AVL的删除操作可以先按照BST的方法删除,如果删除的Node没有或只有一个子Node,那么删除Node的父Node可能出现不平衡,因此需要从删除Node的父Node向上查找UnbalancedNode,如果删除Node含有两个Child,那么我们实际删除的Node是Successor因此要返回Successor的父Node

更新后的BST类

package TreeStructure.BinaryTree;

import org.jetbrains.annotations.NotNull;

public class BST<T extends Comparable<T>> extends BinaryTree<T> {


    @Override
    public Node<T> insert(T key) {
        if (root == null) {
            //树上没有Node直接把root设置为插入Node
            root = new Node<T>(key);
            return root;
        } else {
            //插入Node的父Node
            Node<T> parent;
            //遍历Node
            Node<T> current = root;
            do {
                parent = current;
                if (current.getData().compareTo(key) > 0) current = current.getLeftChild();
                    //相等的Node插入右子树
                else current = current.getRightChild();
            } while (current != null);
            current = new Node<T>(key, parent);
            //此时Parent的子Node是null,null用插入Node替代
            if (parent.getData().compareTo(key) > 0) parent.setLeftChild(current);
            else parent.setRightChild(current);
            return current;
        }
    }

    @Override
    public Node<T> delete(T key) {
        //待删除Node
        Node<T> delete = find(key);
        if (delete == null) return null;
        if (delete.hasChild())
            if (delete.hasLeftChild() && delete.hasRightChild())
                //delete有两个Child
                return deleteNodeWithTwoChild(delete);
            else
                //delete有一个Child
                return deleteNodeWithOneChild(delete);
        else
            //delete没有Child
            return deleteNodeWithoutChild(delete);

    }

    protected Node<T> deleteNodeWithoutChild(@NotNull Node<T> delete) {
        //delete没有子Node(叶子Node)
        if (delete == root) return root = null;
        else {
            //delete的父Node
            Node<T> parent = delete.getParent();
            if (delete.isLeftChildOf(parent)) parent.setLeftChild(null);
            else parent.setRightChild(null);
            return parent;
        }
    }

    protected Node<T> deleteNodeWithOneChild(@NotNull Node<T> delete) {
        //delete有一个Child
        if (delete == root) {
            //delete是root
            if (root.hasLeftChild()) root = root.getLeftChild();
            else root = root.getRightChild();
            root.setParent(null);
            return null;
        } else {
            //delete的父Node
            Node<T> parent = delete.getParent();
            if (delete.isLeftChildOf(parent)) {
                if (delete.hasLeftChild()) {
                    parent.setLeftChild(delete.getLeftChild());
                    delete.getLeftChild().setParent(parent);
                } else {
                    parent.setLeftChild(delete.getRightChild());
                    delete.getRightChild().setParent(parent);
                }
            } else {
                if (delete.hasLeftChild()) {
                    parent.setRightChild(delete.getLeftChild());
                    delete.getLeftChild().setParent(parent);
                } else {
                    parent.setRightChild(delete.getRightChild());
                    delete.getRightChild().setParent(parent);
                }
            }
            return parent;
        }
    }

    private Node<T> deleteNodeWithTwoChild(@NotNull Node<T> delete) {
        if(!delete.hasLeftChild() && delete.hasRightChild()) return null;
        //delete有两个Child
        Node<T> successor = delete.getSuccessor();
        delete.setData(successor.getData());
        if (successor.hasRightChild())
            //successor有右子节点
            return deleteNodeWithOneChild(successor);
        else
            return deleteNodeWithoutChild(successor);
    }
}

AVL类

package TreeStructure.BinaryTree;

import org.jetbrains.annotations.NotNull;

import static TreeStructure.BinaryTree.Node.unbalancedNode;

public class AVL<T extends Comparable<T>> extends BST<T> {
    @Override
    public Node<T> insert(T key) {
        Node<T> insertNode = super.insert(key);
        rotate(unbalancedNode(insertNode));
        return insertNode;
    }

    @Override
    public Node<T> delete(T key) {
        Node<T> deleteNode = super.delete(key);
        rotate(unbalancedNode(deleteNode));
        return deleteNode;
    }


    private void rotate(Node<T> unbalancedNode) {
        if (unbalancedNode == null) return;
        if (Node.getHeight(unbalancedNode.getLeftChild()) > Node.getHeight(unbalancedNode.getRightChild())) {
            if (Node.getHeight(unbalancedNode.getLeftChild().getLeftChild()) > Node.getHeight(unbalancedNode.getLeftChild().getRightChild()))
                LL(unbalancedNode);
            else LR(unbalancedNode);
        } else {
            if (Node.getHeight(unbalancedNode.getRightChild().getRightChild()) > Node.getHeight(unbalancedNode.getRightChild().getLeftChild()))
                RR(unbalancedNode);
            else RL(unbalancedNode);
        }
    }


    private void LL(@NotNull Node<T> node) {
        if (node == root) root = node.getLeftChild();
        node.getLeftChild().setParent(node.getParent());
        if (node.isLeftChildOf(node.getParent())) node.getParent().setLeftChild(node.getLeftChild());
        if (node.isRightChildOf(node.getParent())) node.getParent().setRightChild(node.getLeftChild());
        if (node.getLeftChild().getRightChild() != null) node.getLeftChild().getRightChild().setParent(node);

        node.setParent(node.getLeftChild());
        node.setLeftChild(node.getParent().getRightChild());
        node.getParent().setRightChild(node);
    }

    private void RR(@NotNull Node<T> node) {
        if (node == root) root = node.getRightChild();
        node.getRightChild().setParent(node.getParent());
        if (node.isRightChildOf(node.getParent())) node.getParent().setRightChild(node.getRightChild());
        if (node.isLeftChildOf(node.getParent())) node.getParent().setLeftChild(node.getRightChild());
        if (node.getRightChild().getLeftChild() != null) node.getRightChild().getLeftChild().setParent(node);

        node.setParent(node.getRightChild());
        node.setRightChild(node.getParent().getLeftChild());
        node.getParent().setLeftChild(node);
    }

    private void LR(@NotNull Node<T> node) {
        if (node == root) root = node.getLeftChild().getRightChild();
        RR(node.getLeftChild());
        LL(node);
    }

    private void RL(@NotNull Node<T> node) {
        if (node == root) root = node.getRightChild().getLeftChild();
        LL(node.getRightChild());
        RR(node);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jinyihao823

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值