ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

X16数据结构部分09

2021-11-01 22:32:34  阅读:153  来源: 互联网

标签:左子 leftNode 09 右子 value rightNode 数据结构 节点 X16


X16数据结构部分09

平衡二叉树概述以及左旋转实现思路

/*
    平衡二叉树(AVL树)概述
        解决了二叉排序树的一些问题
        举一个栗子
        给你1个数列{1,2,3,4,5,6}
        让你构造1棵二叉排序树
            根据左小右大原则
            你就会构造出来只有1直向右子树延申的
            所有节点最多只有1棵节点的二叉树
            也就是左子树全部为空

        此时你会发现
        你所构造的二叉排序树更像是1棵单链表
            这样的话,插入和删除速度不会受影响
            但查询速度会很慢
            甚至比单链表还要慢
            因为在查询的时候
            还需要判断左子树是否有节点

    解决方案
        平衡二叉树
        特点
            前提是二叉排序树
            是1棵空树或2棵子树的高度差绝对值不超过1
            并且左右2子树都是1棵平衡二叉树
            常见的实现方法有红黑树,替罪羊树,AVL算法,伸展树等;

    需求
        给你1个数列,要求创建1棵平衡二叉树
        {4,3,6,5,7,8}

    左旋转思路分析
        一旦右子树的高度 - 左子树的高度 > 1
        就采用左旋转
        降低右子树的高度

    如何进行左旋转
        1. 创建1个新节点,value等于当前根节点的值,创建1个当前指针,指向根节点
        2. 把新节点((NODE)value = 4)的左子树设置为当前节点((ROOT)value = 4)的左子树
        3. 把新节点的右子树设置为当前节点的右子树的左子树,如果没有指向null就行了
        4. 把当前节点的值换成右子节点的值((ROOT)value = 6),注意只是换,还没开始移动呢
        5. 把当前节点的右子树设置为当前节点右子树的右子树((ROOT)value = 6).rightNode = ROOT.r.r
        6. 当前节点的左子树指向新节点((NODE)value = 4)

        左旋转过后
            明显地发现原先根节点指向的右子树
            这条线已经断掉了
            实际上原来的右子树已经被销毁了
            新出现相同的节点只是副本而已
            想想有一种悲伤的感觉
        代码实现的话
            我会复用之前的Node1节点类
     */

树的高度求解

// 将以下方法写进Node类,创建AVLT平衡二叉树类,将原先的二叉排序树类复制进class AVLT,这里就不展示源码了
	/**
     * 返回左子树的高度
     * 递归出口
     *
     * @return 左子树的高度
     */
    public int leftTreeHeight() {
        if (leftNode == null) {
            return 0;
        }
        return leftNode.maximumHeightOfTree();
    }

    /**
     * 返回右子树的高度
     * 递归出口
     *
     * @return 右子树的高度
     */
    public int rightTreeHeight() {
        if (rightNode == null) {
            return 0;
        }
        return rightNode.maximumHeightOfTree();
    }

    /**
     * 树的最大高度
     *
     * @return 当前二叉树的最大高度
     */
    public int maximumHeightOfTree() {
        /*
        程序进入方法体
        递归左子树和右子树
        再取最大值
        还要+1的原因是当前自己
        也要加上
         */
        return Math.max(leftNode == null ? 0 : leftNode.maximumHeightOfTree(),
                rightNode == null ? 0 : rightNode.maximumHeightOfTree()) + 1;
    }

左右旋转的方法

/**
     * 左旋转方法
     */
    public void rotateLeft() {
        /*
        程序开始进行左旋转操作
        
        1. 创建1个新节点,value等于当前根节点的值,创建1个当前指针,指向根节点
        2. 把新节点((NODE)value = 4)的左子树设置为当前节点((ROOT)value = 4)的左子树
        3. 把新节点的右子树设置为当前节点的右子树的左子树,如果没有指向null就行了
        4. 把当前节点的值换成右子节点的值((ROOT)value = 6),注意只是换,还没开始移动呢
        5. 把当前节点的右子树设置为当前节点右子树的右子树((ROOT)value = 6).rightNode = ROOT.r.r
        6. 当前节点的左子树指向新节点((NODE)value = 4)

        此时
        默认value是根节点
        leftNode是根节点的左子树
         */
        
        Node1 newNode = new Node1(value);
        newNode.leftNode = leftNode;
        newNode.rightNode = rightNode.leftNode;
        value = rightNode.value;
        rightNode = rightNode.rightNode;
        leftNode = newNode;
    }

    /**
     * 右旋转方法
     */
    public void rotateRight() {
        /*
        右旋转实现思路
            1. 创建1个新节点,为当前根节点的值((NEW_NODE)value = 10)
            2. 新节点的右子树((NEW_NODE).r)设置为当前节点的右子树((ROOT).r)
            3. 新节点的左子树((NEW_NODE).l)设置为当前节点左子树的右子树((ROOT).l.r)
            4. 把当前根节点的值((ROOT).value)换成左子树节点的值((ROOT).l.value)
            5. 当前节点的左子树设置为当前节点左子树的左子树
            6. 把当前节点的右子树设置为新节点

            此时根节点的左子树节点已经被销毁了
            因为没有任何引用指向该节点
         */
        Node1 newNode = new Node1(value);
        newNode.rightNode = rightNode;
        newNode.leftNode = leftNode.rightNode;
        value = leftNode.value;
        leftNode = leftNode.leftNode;
        rightNode = newNode;
    }
    
    /**
     * 插入节点的方法
     *
     * @param node 需要插入的节点
     */
    public void insertNode(Node1 node) {
        if (node == null) {
            return;
        }
        /*
        程序运行到此处
        此时可以判断插入的节点和根节点的关系
        this.value表示根节点的值
         */
        if (node.value < this.value) {
            if (this.leftNode == null) {
                /*
                程序运行到此处
                说明当前插入的节点比根节点的值小
                并且根节点的左子树位空
                直接插入即可
                 */
                this.leftNode = node;
            } else {
                this.leftNode.insertNode(node);
            }
        } else {
            /*
            程序运行到此处
            说明当前节点比根节点大
            需要插入到右子树
             */
            if (this.rightNode == null) {
                this.rightNode = node;
            } else {
                this.rightNode.insertNode(node);
            }
        }
        /*
        程序运行到此处
        应该判断左子树和右子树的高度
        如果右子树的高度 - 左子树的高度 > 1
        应该左旋转
        如果左子树的高度 - 右子树的高度 > 1
        应该右旋转
         */
        if (rightTreeHeight() - leftTreeHeight() > 1) {
            /*
            程序运行到此处
            先不考虑那么多
            直接左旋转
             */
            rotateLeft();
        }
        if (leftTreeHeight() - rightTreeHeight() > 1) {
            rotateRight();
        }
    }

实现双旋转

/*
    这里分析几个特殊的情况比如给你1个数组
    {10,11,7,6,8,9}
    构造完二叉排序树
    此时满足右旋转的条件
    但进行右旋转过后
    仍然不是1棵平衡二叉树

    双旋转思路分析和条件
    1. 满足右旋转的条件
    2. 左子树的右子树高度 > 右子树高度
    3. 先对当前这个节点的左节点进行左旋转
    4. 再对当前根节点进行右旋转即可
     */
     /**
     * 插入节点的方法
     *
     * @param node 需要插入的节点
     */
    public void insertNode(Node1 node) {
        if (node == null) {
            return;
        }
        /*
        程序运行到此处
        此时可以判断插入的节点和根节点的关系
        this.value表示根节点的值
         */
        if (node.value < this.value) {
            if (this.leftNode == null) {
                /*
                程序运行到此处
                说明当前插入的节点比根节点的值小
                并且根节点的左子树位空
                直接插入即可
                 */
                this.leftNode = node;
            } else {
                this.leftNode.insertNode(node);
            }
        } else {
            /*
            程序运行到此处
            说明当前节点比根节点大
            需要插入到右子树
             */
            if (this.rightNode == null) {
                this.rightNode = node;
            } else {
                this.rightNode.insertNode(node);
            }
        }
        /*
        程序运行到此处
        应该判断左子树和右子树的高度
        如果右子树的高度 - 左子树的高度 > 1
        应该左旋转
        如果左子树的高度 - 右子树的高度 > 1
        应该右旋转
        注意这里需要判断是否满足双旋转的条件
         */
        if (rightTreeHeight() - leftTreeHeight() > 1) {
            if (rightNode != null && rightNode.leftTreeHeight() > rightNode.rightTreeHeight()) {
                rightNode.rotateRight();
                rotateLeft();
            }else {
                rotateLeft();
            }
            return;
        }

        if (leftTreeHeight() - rightTreeHeight() > 1) {
            if (leftNode != null && leftNode.rightTreeHeight() > leftNode.leftTreeHeight()) {
                leftNode.rotateLeft();
                rotateRight();
            }else {
                rotateRight();
            }
        }
    }

总目录

标签:左子,leftNode,09,右子,value,rightNode,数据结构,节点,X16
来源: https://blog.csdn.net/m0_54608045/article/details/121057939

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有