AVLTree遍历

AVL树(平衡二叉树):

  AVL树本质上是一颗二叉查找树,但是它又具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为平衡二叉树。


* 前序遍历:对于当前节点,先输出该节点,然后输出他的左孩子,最后输出他的右孩子。
* 中序遍历:对于当前结点,先输出它的左孩子,然后输出该结点,最后输出它的右孩子。
* 后续遍历:对于当前结点,先输出它的左孩子,然后输出它的右孩子,最后输出该结点。


        package com.neusoft.data.structure;


/**
 * Java 语言: AVL树
 * 前序遍历:对于当前节点,先输出该节点,然后输出他的左孩子,最后输出他的右孩子。
 * 中序遍历:对于当前结点,先输出它的左孩子,然后输出该结点,最后输出它的右孩子。
 * 后续遍历:对于当前结点,先输出它的左孩子,然后输出它的右孩子,最后输出该结点。
 * @author
 * @date 2015/12/23
 */

public class AVLTree<T extends Comparable<T>> {
    private AVLTreeNode<T> mRoot;    // 根结点

    // AVL树的节点(内部类)

    class AVLTreeNode<T extends Comparable<T>> {
        T key;                // 关键字(键值)
        int height;         // 高度
        AVLTreeNode<T> left;    // 左孩子
        AVLTreeNode<T> right;    // 右孩子

        public AVLTreeNode(T key, AVLTreeNode<T> left, AVLTreeNode<T> right) {
            this.key = key;
            this.left = left;
            this.right = right;
            this.height = 0;
        }
    }

    // 构造函数
    public AVLTree() {
        mRoot = null;
    }

    /*
     * 获取树的高度
     */
    private int height(AVLTreeNode<T> tree) {
        if (tree != null){
            return tree.height;
        }

        return 0;
    }

    public int height() {
        return height(mRoot);
    }

    /*
     * 比较两个值的大小
     */
    private int max(int a, int b) {
        return a>b ? a : b;
    }

    /*
     * 前序遍历"AVL树"
     */
    private void preOrder(AVLTreeNode<T> tree) {
        if(tree != null) {
            System.out.print(tree.key+" ");
            preOrder(tree.left);
            preOrder(tree.right);
        }
    }

    public void preOrder() {
        preOrder(mRoot);
    }

    /*
     * 中序遍历"AVL树"
     */
    private void inOrder(AVLTreeNode<T> tree) {
        if(tree != null){
            inOrder(tree.left);
            System.out.print(tree.key+" ");
            inOrder(tree.right);
        }
    }

    public void inOrder() {
        inOrder(mRoot);
    }

    /*
     * 后序遍历"AVL树"
     */
    private void postOrder(AVLTreeNode<T> tree) {
        if(tree != null) {
            postOrder(tree.left);
            postOrder(tree.right);
            System.out.print(tree.key+" ");
        }
    }

    public void postOrder() {
        postOrder(mRoot);
    }


    /*
     * 查找最小结点:返回tree为根结点的AVL树的最小结点。
     */
    private AVLTreeNode<T> minimum(AVLTreeNode<T> tree) {
        if (tree == null){
            return null;
        }

        while(tree.left != null){
            tree = tree.left;
        }
        return tree;
    }

    public T minimum() {
        AVLTreeNode<T> p = minimum(mRoot);
        if (p != null){
            return p.key;
        }

        return null;
    }

    /*
     * 查找最大结点:返回tree为根结点的AVL树的最大结点。
     */
    private AVLTreeNode<T> maximum(AVLTreeNode<T> tree) {
        if (tree == null){
            return null;
        }

        while(tree.right != null){
            tree = tree.right;
        }
        return tree;
    }

    public T maximum() {
        AVLTreeNode<T> p = maximum(mRoot);
        if (p != null){
            return p.key;
        }

        return null;
    }

    /*
     * LL:左左对应的情况(左单旋转)。
     *        2
     *     A                     B
     *    /  1                 /   \
     *   B   -->>LL--->>      X     A
     *  /  0
     * X
     * 返回值:旋转后的根节点
     * (插入的节点是左子树的左边节点)
     */
    private AVLTreeNode<T> leftLeftRotation(AVLTreeNode<T> k2) {
        AVLTreeNode<T> k1;

        k1 = k2.left;
        k2.left = k1.right;
        k1.right = k2;
        //关于高度,树的高度即为最大层次。
        //即空的二叉树的高度是0,非空树的高度从1计数,等于它的最大层次(根的层次为1,根的子节点为第2层,依次类推)。
        k2.height = max( height(k2.left), height(k2.right)) + 1;
        k1.height = max( height(k1.left), k2.height) + 1;//左右比较

        return k1;
    }

    /*
     * RR:右右对应的情况(右单旋转)。
     *
     *      -2                              0
     *     A                               B
     *      \ -1                         /0  \0
     *       B         -->>RR--->>      A     X
     *        \ 0
     *         X
     *
     *(插入节点是右子树的右边节点)
     * 返回值:旋转后的根节点
     */
    private AVLTreeNode<T> rightRightRotation(AVLTreeNode<T> k1) {
        AVLTreeNode<T> k2;

        k2 = k1.right;
        k1.right = k2.left;
        k2.left = k1;

        k1.height = max( height(k1.left), height(k1.right)) + 1;
        k2.height = max( height(k2.right), k1.height) + 1;

        return k2;
    }

    /*
     * LR:左右对应的情况(左双旋转)。--对应RR-LL
     *(插入节点是左子树的右边节点)
     * 返回值:旋转后的根节点
     */
    private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> k3) {
        k3.left = rightRightRotation(k3.left);

        return leftLeftRotation(k3);
    }

    /*
     * RL:右左对应的情况(右双旋转)。对应 LL-RR
     *(插入节点是右子树的左边节点)
     * 返回值:旋转后的根节点
     */
    private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> k1) {
        k1.right = leftLeftRotation(k1.right);

        return rightRightRotation(k1);
    }

    /*
     * 将结点插入到AVL树中,并返回根节点
     *
     * 参数说明:
     *     tree AVL树的根结点
     *     key 插入的结点的键值
     * 返回值:
     *     根节点
     */
    private AVLTreeNode<T> insert(AVLTreeNode<T> tree, T key) {
        if (tree == null) {
            // 新建节点
            tree = new AVLTreeNode<T>(key, null, null);

        } else {
            int cmp = key.compareTo(tree.key);//新增加的键值距离他最近的平衡因子绝对值超过1的3进行比较

            if (cmp < 0) {    // 应该将key插入到"tree的左子树"的情况
                tree.left = insert(tree.left, key);
                // 插入节点后,若AVL树失去平衡,则进行相应的调节。
                //因为BF为正,因此我们将整个树进行右旋(顺时针旋转),
                if (height(tree.left) - height(tree.right) == 2) {//打破平衡
                    if (key.compareTo(tree.left.key) < 0){//新插入的值和将要插在某个节点下面的值进行比较  ,
                        //插入的值小于当前节点的左子节点,  插入的节点是左子树的左边节点,
                        //进行比对 LL型,左左型,
                        tree = leftLeftRotation(tree);
                    }else{//LR左右型  插入的节点是左子树的右边节点,
                        tree = leftRightRotation(tree);
                    }
                }
            } else if (cmp > 0) {    // 应该将key插入到"tree的右子树"的情况
                tree.right = insert(tree.right, key);
                // 插入节点后,若AVL树失去平衡,则进行相应的调节。
                //因为BF为负,因此我们将整个树进行左旋(逆时针旋转),
                if (height(tree.right) - height(tree.left) == 2) {//打破平衡
                    if (key.compareTo(tree.right.key) > 0){//插入的值大于当前节点的右子节点,  插入的节点是右子树的右边节点,
                        tree = rightRightRotation(tree);//RR型,右右型
                    }else{//新插入的值比右节点小 RL //插入的值小于当前节点的右子节点,  插入的节点是右子树的左边节点,
                        tree = rightLeftRotation(tree);//RL型 右左型
                    }
                }
            } else {    // cmp==0
                System.out.println("添加失败:不允许添加相同的节点!");
            }
        }

        tree.height = max( height(tree.left), height(tree.right)) + 1;//从0开始算高度

        return tree;
    }

    public void insert(T key) {
        mRoot = insert(mRoot, key);
    }


    /*
     * 销毁AVL树
     */
    private void destroy(AVLTreeNode<T> tree) {
        if (tree==null)
            return ;

        if (tree.left != null)
            destroy(tree.left);
        if (tree.right != null)
            destroy(tree.right);

        tree = null;
    }

    public void destroy() {
        destroy(mRoot);
    }

    /*
     * 打印"二叉查找树"
     *
     * key        -- 节点的键值
     * direction  --  0,表示该节点是根节点;
     *               -1,表示该节点是它的父结点的左孩子;
     *                1,表示该节点是它的父结点的右孩子。
     */
    private void print(AVLTreeNode<T> tree, T key, int direction) {
        if(tree != null) {
            if(direction==0)    // tree是根节点
                System.out.printf("%2d is root\n", tree.key, key);
            else                // tree是分支节点
                System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left");

            print(tree.left, tree.key, -1);
            print(tree.right,tree.key,  1);
        }
    }

    public void print() {
        if (mRoot != null)
            print(mRoot, mRoot.key, 0);
    }

    private static int arr[]= {3,2,1,4,5,6,7,10,9,8};

    public static void main(String[] args) {
        int i;
        AVLTree<Integer> tree = new AVLTree<Integer>();

        System.out.printf("== 依次添加: ");
        for(i=0; i<arr.length; i++) {

            tree.insert(arr[i]);
            System.out.printf("%d ", arr[i]);
        }

        System.out.printf("\n== 前序遍历: ");
        tree.preOrder();

        System.out.printf("\n== 中序遍历: ");
        tree.inOrder();

        System.out.printf("\n== 后序遍历: ");
        tree.postOrder();
        System.out.printf("\n");

        System.out.printf("== 高度: %d\n", tree.height());
        System.out.printf("== 最小值: %d\n", tree.minimum());
        System.out.printf("== 最大值: %d\n", tree.maximum());
        System.out.printf("== 树的详细信息: \n");
        tree.print();


        // 销毁二叉树
        tree.destroy();
    }

}


      

输出:

v2-f68733dfc6fd1fdd20adf464d998a93e_b.jpg

发布了158 篇原创文章 · 获赞 18 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/yunfengfengfeng/article/details/105509187
今日推荐