栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

平衡树(AVL树)java代码

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

平衡树(AVL树)java代码

debug了好久才写出来的平衡树,代码里有注释可以方便理解
可能有代码冗余或者有误的地方,欢迎指出错误
(好像因为是看了别人的博客,所以混淆了结点高度这个概念,我先解释一下我代码里的Height=当前结点到叶子结点的经过的边+1)
很抱歉影响了你的观看体验!

推荐一个网站(数据结构操作可视化)
(我这里给出的是平衡树界面)
AVL Tree Visualzation
(我debug就是看着可视化的树查错的)

还是讲下一些关键操作吧:
1、左旋(基操)
左旋不会改变中序遍历

2、右旋(基操)
右旋不会改变中序遍历

3、LL(左左)
用下图举例的话,就是插入操作为在结点1的左孩子的左孩子处插入结点3,这样会使得平衡度== 2
就是对结点1进行一个右旋

4、RR(右右,在结点1的右孩子的右孩子处插入结点3,这样会使得平衡度==-2)
就是对结点1进行一个左旋

5、LR(左右,在结点1的左孩子的右孩子处插入结点3,这样会使得平衡度==-2)
就是先对结点2右旋,再对结点1左旋

6、RL(开摆!你们自己对照着LR比划去罢)

7、计算平衡度
首先得到当前结点的左右孩子的高度(高度的更新是在回溯的时候进行的,所以可以保证子结点的高度已经是正确的了)
然后就是return leftHeight-rightHeight了

8、找到左子树的最大值
删除一个左右子结点都存在的结点时,需要用左子树的最大结点或右子树的最小结点来替代当前结点(我的代码里用的是左子树的最大结点)
其实左子树的最大结点就是左子树的最右下角的结点

下面开始放代码(欢迎喷我代码的问题)

import java.util.linkedList;




public class AVLTree,V> {
    //树结点类
    private class Node{
        //键
        private K key;
        //值
        private V value;
        //高度
        private Integer height;
        //左右父
        private Node left,right,parent;

        public Node(K key,V value) {
            this.key=key;
            this.value = value;
            height=1;
        }

        
        private int getBalanceFactor(){
            int leftHeight=left==null?0:left.getHeight();
            int rightHeight=right==null?0:right.getHeight();
            return leftHeight-rightHeight;
        }

        private int getHeight(){
            return height;
        }

        private void setHeight(Integer height){
            this.height=height;
        }

        
        private void updateHeight(){
            int leftHeight=left==null?0:left.getHeight();
            int rightHeight=right==null?0:right.getHeight();
            height=1+Math.max(leftHeight,rightHeight);
        }

        private K getKey() {
            return key;
        }

        private void setKey(K key) {
            this.key = key;
        }

        private V getValue() {
            return value;
        }

        private void setValue(V value) {
            this.value = value;
        }

        private void setKeyAndValue(K key,V value){
            setKey(key);
            setValue(value);
        }

        private Node getLeft() { return left; }

        private void setLeft(Node left) { this.left = left; }

        private Node getRight() { return right; }

        private void setRight(Node right) { this.right = right; }

        private Node getParent() { return parent; }

        private void setParent(Node parent) { this.parent = parent; }

        @Override
        public String toString() {
            return "Node{" +
                    "key=" + key +
                    ", value=" + value +
                    '}';
        }
    }
    //结点个数
    private int size;
    //根结点
    private Node root;

    public AVLTree(){
        clear();
    }

    
    private Node leftRotate(Node node1){
        Node node2=node1.getRight();
        node1.setRight(node2.getLeft());
        node1.setParent(node2);
        if(node1.getRight()!=null){
            node1.getRight().setParent(node1);
        }
        node2.setLeft(node1);
        node1.updateHeight();
        node2.updateHeight();
        return node2;
    }

    
    private Node rightRotate(Node node1){
        Node node2=node1.getLeft();
        node1.setLeft(node2.getRight());
        node1.setParent(node2);
        if(node1.getLeft()!=null){
            node1.getLeft().setParent(node1);
        }
        node2.setRight(node1);
        node1.updateHeight();
        node2.updateHeight();
        return node2;
    }

    
    private Node addNode(Node root,K key,V value){
        if(root==null){
            //直接返回结点,让父节点更新子结点,同时不走下面的reBalance
            return new Node(key,value);
        }
        int cmpRes=key.compareTo(root.getKey());
        //小于,看左子树
        if(cmpRes<0){
            //这里需要更新左子结点
            Node leftChild=addNode(root.getLeft(),key,value);
            root.setLeft(leftChild);
            leftChild.setParent(root);
        }else if(cmpRes>0){//大于,看右子树
            //这里需要更新右子结点
            Node rightChild=addNode(root.getRight(),key,value);
            root.setRight(rightChild);
            rightChild.setParent(root);
        }else{
            //key值相等就认为是更新
            root.setValue(value);
        }
        return reBalance(root);
    }

    private Node reBalance(Node root){
        int bf=root.getBalanceFactor();
        //左子树高
        if(bf>1){
            Node leftChild=root.getLeft();
            int childBF=leftChild.getBalanceFactor();
            
            if(childBF>0){
                //右旋
                root=rightRotate(root);
            }
            
            else{
                //先左旋再右旋
                //注意左旋是以2为根结点
                root.setLeft(leftRotate(root.getLeft()));
                root=rightRotate(root);
            }
        }else if(bf<-1){//右子树高
            Node rightChild=root.getRight();
            int childBF=rightChild.getBalanceFactor();
            
            if(childBF>0){
                //注意右旋是以2为根结点
                root.setRight(rightRotate(root.getRight()));
                root=leftRotate(root);
            }
            
            else{
                //左旋
                root=leftRotate(root);
            }
        }
        //这里可以在回溯时更新路径上的所有结点的高度(已平衡的结点会直接来这里更新高度)
        root.updateHeight();
        return root;
    }

    
    private Node findNode(Node root,K key){
        if(root==null){
            return null;
        }
        int cmpRes=key.compareTo(root.getKey());
        if(cmpRes<0){
            return findNode(root.getLeft(),key);
        }else if(cmpRes>0){
            return findNode(root.getRight(),key);
        }else{
            return root;
        }
    }

    
    private Node replaceNode(Node root,Node deletedNode){
        if(root.getRight()==null){
            deletedNode.setKeyAndValue(root.getKey(),root.getValue());
            return null;
        }
        root.setRight(replaceNode(root.getRight(),deletedNode));
        root.updateHeight();
        return reBalance(root);
    }

    
    private Node deleteNode(Node root,K key){
        if(root==null){
            return null;
        }
        int cmpRes=key.compareTo(root.getKey());
        if(cmpRes<0){
            //找左子树
            Node leftChild=deleteNode(root.getLeft(), key);
            root.setLeft(leftChild);
            if(leftChild!=null){
                //
                leftChild.setParent(root);
            }
        }else if(cmpRes>0) {
            //找右子树
            Node rightChild=deleteNode(root.getRight(), key);
            root.setRight(rightChild);
            if(rightChild!=null){
                rightChild.setParent(root);
            }
        }else{
            //找到要删除的结点了
            if(root.getLeft()==null&&root.getRight()==null){//叶子结点
                if(root.getParent()==null){
                    setRoot(null);
                }
                return null;
            }else if(root.getLeft()==null){//左子树为空,右子树不为空
                root.getRight().setParent(root.getParent());
                if(root.getParent()==null){
                    setRoot(root.getRight());
                }
                return root.getRight();
            } else if(root.getRight()==null){//右子树为空,左子树不为空
                root.getLeft().setParent(root.getParent());
                if(root.getParent()==null){
                    setRoot(root.getLeft());
                }
                return root.getLeft();
            }
            else{//有两个儿子结点
                Node leftChild=root.getLeft();
                if(leftChild.getRight()==null){
                    //直接把左子树根节点置为null
                    root.setKeyAndValue(leftChild.getKey(),leftChild.getValue());
                    root.setLeft(null);
                    leftChild.setParent(null);
                }else{
                    //用左子树的最大节点覆盖被删除的结点(可视为删除),并更新左孩子
                    Node newLeft=replaceNode(leftChild,root);
                    root.setLeft(newLeft);
                    if(newLeft!=null){
                        newLeft.setParent(root);
                    }
                }
            }
        }
        root.updateHeight();
        return reBalance(root);
    }

    
    public void put(K key,V value){
        if(root==null){ setRoot(new Node(key,value)); }
        else{
            setRoot(addNode(root,key,value));
            //因为这些操作不涉及根结点的处理,所以需要单独写一个根结点的父节点置空
            getRoot().setParent(null);
        }
        size++;
    }

    
    public V get(K key){
        if(key==null){
            throw new NullPointerException("key cannot be null");
        }
        Node node=findNode(root,key);
        if(node==null){
            return null;
        }
        return node.getValue();
    }

    
    public void remove(K key){
        if(key==null){
            throw new NullPointerException("key cannot be null");
        }
        setRoot(deleteNode(root,key));
        if(getRoot()!=null){
            getRoot().setParent(null);
        }
        size--;
    }

    
    public void clear(){
        size=0;
        root=null;
    }

    public boolean isEmpty(){ return size==0; }

    public int size() { return size; }

    private void setSize(int size) { this.size = size; }

    private Node getRoot() { return root; }

    private void setRoot(Node root) { this.root = root; }

    private StringBuilder preOrderTraverse(Node root,StringBuilder sb){
        if(root==null){
            //null结点为#
            sb.append("# ");
            return sb;
        }
        sb.append(root.getKey()).append(" ");
        sb=preOrderTraverse(root.getLeft(),sb);
        sb=preOrderTraverse(root.getRight(),sb);
        return sb;
    }

    @Override
    public String toString(){
        StringBuilder sb=new StringBuilder();
        sb.append("preOrderTraverseSequenceOfKey is [");
        sb=preOrderTraverse(root,sb);
        sb.deleteCharAt(sb.length()-1);
        sb.append("]");
        return sb.toString();
    }
}

class AVLTreeDemo{
    public static void main(String[] args) {
        AVLTree tree=new AVLTree<>();
        linkedList list=new linkedList<>();
        for(int i=0;i<=10;i++){
            list.add(i);
        }
        list.add(-1);
        System.out.println(list);
        System.out.println("----------put测试----------");
        System.out.println("输出的是前序遍历的key序列:");
        for(Integer it:list){
            tree.put(it,it);
            System.out.println(tree);
        }
        System.out.println("------------get测试--------------");
        System.out.println(tree.get(2));
        System.out.println("------------delete测试--------------");
        tree.remove(2);
        System.out.println(tree);
        tree.remove(1);
        System.out.println(tree);
        tree.remove(-1);
        System.out.println(tree);
        tree.remove(0);
        System.out.println(tree);
        tree.put(11,11);
        System.out.println(tree);
        tree.remove(8);
        System.out.println(tree);
        tree.remove(9);
        tree.remove(11);
        System.out.println(tree);
        tree.remove(3);
        System.out.println(tree);
        tree.remove(6);
        tree.remove(4);
        System.out.println(tree);
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/726370.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号