数据结构与算法——平衡二叉搜索树 (Java泛型类)

泛型类实现平衡二叉搜索树

一、完整代码

平衡二叉搜索树的节点类

http://www.cnblogs.com/hugeNumber/articles/7840519.html

2 AVLTree 代码

public class AVLTree  <T extends Comparable<T>>{
    private AVLTreeNode<T> head;

    public AVLTreeNode<T> getHead(){
        return head;
    }
    public NTreeNode<T> Create(T[] data){
        NTreeNode<T> root = null;
        for(T i : data){
            root = Insert(root, i);
        }
        head = (AVLTreeNode<T> )root;
        return root;
    }
    //先根遍历
    public  void PreOrder(NTreeNode<T> root){
        if(root != null){
            //Do something;
            System.out.print(root.getData()+"  ");
            PreOrder(root.getLeft());
            PreOrder(root.getRight());
        }
    }
    //逐层打印
    public void LevelPrint(NTreeNode<T> root){
        if(root == null) return;
        else{
            LLQueue<NTreeNode<T>> Q = new LLQueue<>();
            LLNode<NTreeNode<T>> temp;
            Q.enQueue(root);
            while(!Q.IsEmpty()){
                temp = Q.deQueue();//取队头的值
                //Do something
                System.out.print(temp.data.getData() + "  ");//打印
                if(temp.data.getLeft() != null){
                    Q.enQueue(temp.data.getLeft());//左儿子入队列
                }
                if(temp.data.getRight() != null){
                    Q.enQueue(temp.data.getRight());//右儿子入队列
                }

            }
        }
    }

    //求树的高度
    int Height(NTreeNode<T> root){
        return Height((AVLTreeNode<T>) root);
    }
    //求AVL树的高度
    int Height(AVLTreeNode<T> root){
        if(root == null)
            return -1;
        else
            return root.getHeight();//节点中已保存Height = 根到该节点的路径长(根记为0)
    }

    //可能违背AVL树性质的4种情况
    //1 在节点X的左孩子节点的左子树中插入元素
    //左左旋转
    AVLTreeNode<T> SingleRotateLeft(AVLTreeNode<T> X){
        AVLTreeNode W = (AVLTreeNode<T>)X.getLeft();
        X.setLeft(W.getRight());
        W.setRight(X);

        X.setHeight( Math.max(Height(X.getLeft()), Height(X.getRight())) + 1);
        W.setHeight( Math.max(Height(W.getLeft()), X.getHeight()) + 1);
        return W;
    }

    //2 在节点Z的左孩子节点的右子树中插入元素 [左->右]放入
    //左右旋转(双旋转)先在X右旋转,再在Z左旋转,(X是Z的左孩子)   [照图示做]
    AVLTreeNode<T> DoubleRotatewithLeft(AVLTreeNode<T> Z){
        AVLTreeNode<T> X = (AVLTreeNode<T>) Z.getLeft();
        AVLTreeNode<T> Y = (AVLTreeNode<T>)X.getRight();
        X.setRight(Y.getLeft());
        Y.setLeft(X);
        Z.setLeft(Y.getRight());
        Y.setRight(Z);
        return Y;
    }

    //3 在节点Z的右孩子节点的左子树中插入元素  [右->左]放入
    //右左旋转,先在X左旋转,再在Z右旋转,(X是Z的右孩子)
    AVLTreeNode<T> DoubleRotatewithRight(AVLTreeNode<T> Z){
        AVLTreeNode<T> X = (AVLTreeNode<T>) Z.getRight();
        AVLTreeNode<T> Y = (AVLTreeNode<T>)X.getLeft();
        X.setLeft(Y.getRight());
        Y.setRight(X);
        Z.setRight(Y.getLeft());
        Y.setLeft(Z);
        return Y;
    }


    //4 在节点X的右孩子节点的右子树中插入元素
    //右右旋转
    AVLTreeNode<T> SingleRotateRight(AVLTreeNode<T> W){
        AVLTreeNode X = (AVLTreeNode<T>)W.getRight();
        W.setRight(X.getLeft());
        X.setLeft(W);
        W.setHeight( Math.max(Height(W.getLeft()), Height(W.getRight())) + 1);
        X.setHeight( Math.max(Height(X.getLeft()), W.getHeight()) + 1);
        return X;
    }

    //a大于b,返回1;a小于b,返回-1;a等于b,返回0;
    private int Compare(T a, T b){
        /* compareTo()
            如果指定的数与参数相等返回0。
            如果指定的数小于参数返回 -1。
            如果指定的数大于参数返回 1。
         */
        return a.compareTo(b);
    }


    //AVL树的插入操作
    //插入一个元素后,需要检查高度是否平衡,如果不平衡,需要调用相应的旋转函数
    NTreeNode<T> Insert(NTreeNode<T> root, T data){
        return Insert((AVLTreeNode) root, data);
    }
    //AVL树的插入操作【改】
    AVLTreeNode<T> Insert( AVLTreeNode<T> root, T data){
        if(root == null){
            root = new AVLTreeNode();
            root.setData(data);
            root.setHeight(0);
            root.setLeft(null);
            root.setRight(null);
        }
        else if(Compare(data, root.getData()) < 0){
            root.setLeft(Insert(root.getLeft(), data));//向左子树插入
            if((Height(root.getLeft())) - Height(root.getRight()) == 2){
                if(Compare(data, root.getLeft().getData()) <0 ){//情形1
                    root = SingleRotateLeft(root);
                }
                else{
                    root = DoubleRotatewithLeft(root);//情形2
                }
            }
        }
        else if(Compare(data, root.getData()) > 0){
            root.setRight(Insert(root.getRight(),data));//向右子树插入
            if((Height(root.getRight()) - Height(root.getLeft())) == 2){
                if(Compare(data, root.getRight().getData()) > 0){//情形4
                    root = SingleRotateRight(root);
                }else
                {
                    root = DoubleRotatewithRight(root);//情形3
                }
            }
        }
        //相等时,数据已经在树中,什么也不做
        root.setHeight(Math.max(Height(root.getLeft()), Height(root.getRight())) + 1);//新调整高度
        return root;
    }


    //【例】判断一颗二叉搜索树,是否为AVL树。不是AVL树,返回-1
    int IsAVL(BinaryTreeNode root){
        int left, right;
        if(root == null){
            return 0;
        }
        left = IsAVL(root.getLeft());
        if(left == -1){
            return left;
        }

        right = IsAVL(root.getRight());
        if(right == -1){
            return right;
        }

        if(Math.abs(left - right) > 1)
            return -1;
        return Math.max(left, right)+1;
    }

    //逐层打印
    public void PrintTree(NTreeNode<T> root){

        if(root == null)return;
        AVLTreeNode<T> symbol = new AVLTreeNode<>();//标识节点
        int level = Height(root);//节点所在的高,根最高【平衡二叉树的高度反了】
        //满二叉树上,n层的节点数为2^n
        int leafNum = (int)Math.pow(2, level);//满二叉树叶子数(最低层)
        LLQueue<NTreeNode<T>> Q = new LLQueue<>();//新建二叉搜索树节点队列
        LLNode<NTreeNode<T>> temp;
        Q.enQueue(root);//根入队列
        //逐层
        for(int i=0; i <= level; i++){
            int num = (int)Math.pow(2, i);//每一层最多为2^n
            int length = Math.round(leafNum/(num +1));//int length = (leafNum -(num + 1))/(num + 1);
            //System.out.println(num);
            for(int j = 0; j < num; j++){ //每一层最多为2^n 节点
                temp = Q.deQueue();//取队头
                //打印////////////////////////////
                for(int k = 0; k < length; k++){
                    System.out.print("//");
                }
                //队列中的节点为symbol,打印占位符//
                if(symbol == (temp.data)){ //temp.data == symbol
                    System.out.print("//");
                }else {//否则打印节点信息
                    T info = temp.data.getData();
                    System.out.print(info);//打印节点值
                }

                if(temp.data.getLeft() != null){
                    Q.enQueue(temp.data.getLeft());//左儿子入队列
                }else{
                    Q.enQueue(symbol);//压入一个空标志
                }
                if(temp.data.getRight() != null){
                    Q.enQueue(temp.data.getRight());//右儿子入队列
                }else{
                    Q.enQueue(symbol);
                }
            }
            //再打印些
            for(int k = 0; k < length; k++){
                System.out.print("//");
            }
            System.out.println();
        }
    }


}

先上代码,图示有空再添……

二、综合测试

1 测试用例

   public static void main(String[] args){
        System.out.println("start ====================");
        Integer[] A = {14,5,20,9,41,13,25,17,8,33,3,12,7,1,21,31};//随机个数组
//        Integer[] A = {0,1,2,3,4,5,6,7,8,9};

        AVLTree<Integer> nSearchTree = new AVLTree<>();
        nSearchTree.Create(A);
        nSearchTree.PreOrder(nSearchTree.getHead());
        System.out.println();
        //分层打印
        nSearchTree.PrintTree(nSearchTree.getHead());
}

 

2 实验展示

图 1

 

图2 数组为0123456789

posted @ 2017-11-15 19:23  倪明  阅读(166)  评论(0)    收藏  举报