数据结构与算法之AVL平衡树<六>
来源:互联网 发布:淘宝登陆异常 编辑:程序博客网 时间:2024/05/16 09:11
AVL平衡树是计算机科学中是最先发明的自平衡二叉查找树。
最简单的想法便是要求左右子树具有相同的高度。这种理想的平衡树太过于严格
而难以实现
所以我们必须对其放宽条件。只要其左右子树的高度相差不超过1即可。
既然条件放宽了,那我们如何实现呢?
这里就要引入平衡树的一个重要思想那就是调整思想
当我们在按照二叉搜索树的插入方法插入时。如果这个二叉树不满足AVL树的条件
这时候就该对其调整使其满足AVL树的条件
如何调整?
AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法。但是要进行预先或随后做一次或多次所谓的“AVL 旋转”。
假设由于在二叉排序树上插入结点而失去平衡的最小子树根结点为a(即a是离插入点最近,且平衡因子绝对值超过1的祖先结点),则失去平衡后进行进行的规律可归纳为下列四种情况:
单向右旋平衡处理RR:由于在a的左子树根结点的左子树上插入结点,a的平衡因子由1增至2,致使以a为根的子树失去平衡,则需进行一次右旋转操作;
单向左旋平衡处理LL:由于在a的右子树根结点的右子树上插入结点,a的平衡因子由-1变为-2,致使以a为根的子树失去平衡,则需进行一次左旋转操作;
双向旋转(先左后右)平衡处理LR:由于在a的左子树根结点的右子树上插入结点,a的平衡因子由1增至2,致使以a为根的子树失去平衡,则需进行两次旋转(先左旋后右旋)操作。
双向旋转(先右后左)平衡处理RL:由于在a的右子树根结点的左子树上插入结点,a的平衡因子由-1变为-2,致使以a为根的子树失去平衡,则需进行两次旋转(先右旋后左旋)操作。
了解了这么多的二叉树的方法
我这以Java语言对其实现
AVL树的节点重点内容
public class AvlNode<T> { public AvlNode(T date) { this(date, null, null); } public AvlNode(T date, AvlNode<T> left, AvlNode<T> right) { super(); this.date = date; this.left = left; this.right = right; this.hight = 0; } T date; AvlNode<T> left; AvlNode<T> right; int hight; // 该节点的高度}
AVL树的实现
ublic class AvlTree<T extends Comparable<? super T>> { /* * 节点高度 */ public int getNodeHight(AvlNode<T> node) { return node == null ? 0 : node.hight; } /* * 将节点按照二叉搜索树插入 然后进行调整 */ public AvlNode<T> insert(AvlNode<T> node, T x) { // 递归出口 if (node == null) { return new AvlNode<T>(x); } int result = x.compareTo(node.date); // 二叉搜索树 左边节点小于根节点 右边节点大于根节点 if (result < 0) { node.left = insert(node.left, x); } else if (result > 0) node.right = insert(node.right, x); else ; return balance(node); } // 允许子树之间的高度差为1 private static final int ALLOWED_IMBALANCE = 1; private AvlNode<T> balance(AvlNode<T> node) { if (node == null) return node; // 如果左子树比右子树高度超过一 if (getNodeHight(node.left) - getNodeHight(node.right) > ALLOWED_IMBALANCE) // 如果左子树的左子树的高度大于等于右子树的高度则向左旋转 if (getNodeHight(node.left.left) >= getNodeHight(node.left.right)) node = rotateWithLeftChild(node); else // 如果左子树的右子树的高度大于左子树的高度则向双向右旋转 node = doubleWithRightChild(node); // 如果右子树比左子树高度超过一 else if (getNodeHight(node.right) - getNodeHight(node.left) > ALLOWED_IMBALANCE) // 如果右子树的右子树的高度大于等于左子树的高度则向右旋转 if (getNodeHight(node.right.right) >= getNodeHight(node.right.left)) node = rotateWithRightChild(node); else // 如果左子树的右子树的高度大于左子树的高度则向双向右旋转 node = doubleWithLeftChild(node); // 平衡完成后将高度更新 node.hight = Math.max(getNodeHight(node.left), getNodeHight(node.right) + 1); return node; } // 单向右旋转 private AvlNode<T> rotateWithRightChild(AvlNode<T> node) { // 翻转节点为 node 和 node.left AvlNode<T> nodeR = node.right; // 向左翻转 nodeR.left = node; node.right = nodeR.left; // 先更新node高度因为node的高度降低了 node.hight = Math.max(getNodeHight(node.left), getNodeHight(node.right)); // 更新nodeR nodeR高度上升了 node.hight = Math.max(getNodeHight(nodeR.left), getNodeHight(nodeR.right)); return nodeR; } // 双向右旋转 private AvlNode<T> doubleWithRightChild(AvlNode<T> node) { // 所以先将节点的右树向左旋转使得其右树大于等于左树 node.right = rotateWithLeftChild(node.right); // 然后便可以使用单向左旋转 return rotateWithLeftChild(node); } // 单向左旋转 private AvlNode<T> rotateWithLeftChild(AvlNode<T> node) { // 翻转节点为 node 和 node.left AvlNode<T> nodeL = node.left; // 向左翻转 nodeL.right = node; node.left = nodeL.right; // 先更新node高度因为node的高度降低了 node.hight = Math.max(getNodeHight(node.left), getNodeHight(node.right)); // 更新nodeL nodeL高度上升了 node.hight = Math.max(getNodeHight(nodeL.left), getNodeHight(nodeL.right)); return nodeL; } // 双向左旋转 private AvlNode<T> doubleWithLeftChild(AvlNode<T> node) { // 双向左旋转的条件是node的左子树的左子树小于右子树 // 左旋转由于左旋转会将原node的左子树的右子树给旋转后的node的左子树 // 由于原node的左子树的左子树小于右子树 // node的高度=原node的左子树的右子树的高度+1大于旋转后的左子树 // 所以先将节点的左树向右旋转使得其左树大于等于右树 node.left = rotateWithRightChild(node.left); // 然后便可以使用单向左旋转 return rotateWithLeftChild(node); } // 移除一个节点 public AvlNode<T> remove(T x, AvlNode<T> node) { // 未找到 if (node == null) { return node; } int result = x.compareTo(node.date); if (result < 0) node.left = remove(x, node.left); else if (result > 0) node.right = remove(x, node.right); //两个子树 else if (node.left != null && node.right != null) { node.date = findMin(node.right); node.right = remove(node.date, node.right); } else //一个子树 node = node.left == null ? node.right : node.left; return balance(node); } private T findMin(AvlNode<T> node) { if (node == null) { return null; } // 递归出口 else if (node.left == null) return node.date; return findMin(node.left); }
到此AVL平衡树基本实现了。
- 数据结构与算法之AVL平衡树<六>
- 算法与数据结构 其六 Avl平衡树
- 数据结构与算法分析之AVL平衡树
- 数据结构与算法10: 平衡二叉树AVL(AVL Tree)
- java数据结构与算法之平衡二叉树(AVL树)的设计与实现
- java数据结构与算法之平衡二叉树(AVL树)的设计与实现
- java数据结构与算法之平衡二叉树(AVL树)的设计与实现
- 数据结构与算法之10(AVL自平衡二叉树与RB红黑树)
- 数据结构与算法系列----平衡二叉树(AVL树)
- 数据结构与算法问题 AVL二叉平衡树
- 数据结构与算法专题之树——平衡二叉树(AVL树)
- Java数据结构与算法解析(六)——AVL树
- Java数据结构与算法解析(六)——AVL树
- Java数据结构与算法解析(六)——AVL树
- 【数据结构】平衡二叉树之AVL树
- 数据结构之平衡二叉树AVL
- 数据结构之 AVL平衡树 (c++)
- java数据结构与算法之平衡二叉树(AVL树)的设计与实现中的事实代码
- 初识Linux
- Hihocoder 1054 滑动解锁 暴力dfs
- 从windows上提交代码到spark集群发现driver地址不通
- openwrt 桥接技术
- JavaScript定义变量和变量优先级问题探讨
- 数据结构与算法之AVL平衡树<六>
- ls 主要目录
- 小试ThreadLocal想到“隐式参数”方式
- Matplotlib 绘图并保存图像
- 优先队列——成绩从高到低排列,相同者按语文成绩排列
- 用shell脚本监控进程是否存在 不存在则启动的实例
- Erlang 保护式
- ATS来了,网页HTTP访问怎么办?
- ios 属性readwrite,readonly,assign,retain,copy,nonatomic