X16数据结构部分09
2021/11/1 23:13:41
本文主要是介绍X16数据结构部分09,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
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(); } } }
总目录
这篇关于X16数据结构部分09的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-04百万架构师第六课:设计模式:策略模式及模板模式
- 2025-01-04百万架构师第七课:设计模式:装饰器模式及观察者模式
- 2025-01-04适用于企业管理的协作工具API推荐
- 2025-01-04挑战16:被限流的CPU
- 2025-01-03企业在选择工具时,如何评估其背后的技术团队
- 2025-01-03Angular中打造动态多彩标签组件的方法
- 2025-01-03Flask过时了吗?FastAPI才是未来?
- 2025-01-0311个每位开发者都应知道的免费实用网站
- 2025-01-03从REST到GraphQL:为什么以及我是如何完成转型的
- 2025-01-03掌握RAG:从单次问答到连续对话