avl平衡树
2018-03-26 21:09
399 查看
package com.algorithm.charactor1; /** * 在前面二叉查找树的基础上改的。。。。。 * * 平衡avl树 * * 注意:高度是指节点到 叶子的路径长 * * 有四种可能, * 1,在节点X的左节点的左子树上插入值,导致节点X,不满足 左右子树的高度差1 * 2,在节点X的右节点的右子树上插入值,导致节点X,不满足 左右子树的高度差1 * 1和2是 同一种对称情形,通过单旋转来达到平衡 * * 3,在节点X的左节点的右子树上插入值,导致节点X,不满足 左右子树的高度差1 * 4,在节点X的右节点的左子树上插入值,导致节点X,不满足 左右子树的高度差1 * 3和4是 同一种对称情形,需要通过双旋转来使树达到平衡 */ public class AVLTree<Element extends Comparable<? super Element>> { //根节点 private AVLNode<Element> root; //移除一个元素 public void remove(Element element){ root = remove(element,root); } /** * 移除一个节点 分三种情况, * 一个是 该节点本身是叶子, * 一个是 该节点含有一个儿子节点 * 一个是 该节点还有两个儿子节点 * @param e * @param comareElement */ private AVLNode<Element> remove(Element e, AVLNode<Element> comareElement) { if (comareElement == null) { return comareElement; } int compareTo = e.compareTo(comareElement.element);//要删除的元素 和当前元素进行比较 if (compareTo == 1) {//说明要删除的元素 在当前节点 的右边 comareElement.right = remove(e, comareElement.right); //等式的左边保留的是当前比较节点的父节点的引用 }else if (compareTo == -1) {//说明要删除的元素 在当前节点 的左边 comareElement.left = remove(e, comareElement.left); //等式的左边保留的是当前比较节点的父节点的引用 }else if (compareTo == 0) { //当要删除的节点是叶子的时候 直接置为null if (comareElement.left == null && comareElement.right == null) { comareElement = null; } else if (comareElement.left == null) { //要删除的节点的左子节点为空的情况 comareElement = comareElement.right; }else if (comareElement.right == null){ //要删除的节点的右子节点为空的情况 comareElement = comareElement.left; }else { //要删除的节点的 左右儿子节点都不为空的情况。 删除的节点 用右子树中最小节点替代,当然也可以用其他节点替代 AVLNode<Element> min = findMin(comareElement);//右子树中最小节点 Element element = min.element;//右子树中的元素 comareElement.element = element;//将右子树的值赋值给,当前找到元素的值。 comareElement.right = remove(element, comareElement.right);//将最小节点删掉 } } return balance(comareElement); } private AVLNode<Element> findMin(AVLNode<Element> element){//查找并返回一个输入元素 最小子节点 if (element == null) { return null; }else if (element.left == null) {//左节点无值,说明该节点就是最小值 return element; }else if (element.left != null) { return findMin(element.left); } return null; } //插入一个元素 public void insert(Element element){ root = insert(element,root); } private AVLNode<Element> insert(Element e, AVLNode<Element> comareElement) { if (comareElement == null) {//根节点无值,或者当前节点无值,说明要插入 comareElement = new AVLNode<Element>(e,null,null); return comareElement; } int compareTo = e.compareTo(comareElement.element);//要查找的元素 和当前元素进行比较 if (compareTo == 1) {//说明要插入的值要 在当前比较节点的右边 comareElement.right = insert(e, comareElement.right); }else if (compareTo == -1) {//说明要插入的值 在当前比较节点的左边 comareElement.left = insert(e, comareElement.left); }else if (compareTo == 0 ) {//说明当前 插入的值存在 // return null; } return balance(comareElement); } /** * 左左情形 右旋转 * x * c d * b y * a * * x为失衡节点, x的左儿子的左子树 添加了一个节点导致x失衡 * @param x * @return */ private AVLNode<Element> rotateLeft(AVLNode<Element> x){ AVLNode<Element> c = x.left; x.left = c.right; c.right = x ; x.height = Math.max(height(x.left), height(x.right)) + 1 ; c.height = Math.max(height(c.left), x.height) + 1 ; return c; } /** * 字母都是随机的,不按照字母表排序 * 右右情形 ,左旋转 * x * a y * d z * c * x为失衡点 在x的右儿子的 右字数中 添加 ,导致x失衡 * */ private AVLNode<Element> rotateRight(AVLNode<Element> x){ AVLNode<Element> y = x.right; x.right = y.left; y.left = x; x.height = Math.max(height(x.left), height(x.right)) + 1 ; y.height = Math.max(height(y.left), x.height) + 1 ; return y; } /** * x为失衡点 * x的左儿子的 右子树中 ,添加一个 导致x失衡 * * x x y * w d 左旋转 y d 右旋转 w x * a y a79c -----> w c ------> a c d * b c a b */ private AVLNode<Element> rotateLeftAndRight(AVLNode<Element> x){ x.left = rotateRight(x.left);//先对x.left进行左旋转 , AVLNode<Element> y = rotateLeft(x);//对x进行右旋转 return y; } /** * x为失衡点 * x的右儿子的 左子树中,添加一个 导致x失衡的情况 * 先进行右旋转, 后进行左旋转 */ private AVLNode<Element> rotateRightAndLeft(AVLNode<Element> x){ x.right = rotateLeft(x.right);//对x的有节点先进行右旋转 AVLNode<Element> y = rotateRight(x);//然后对x节点进行左旋转; return y; } /** * 节点插入后 要进行平衡操作。 * @param comareElement * @return */ private AVLNode<Element> balance(AVLNode<Element> comareElement) { if (comareElement == null) { return null; } if (height(comareElement.left) - height(comareElement.right) >1) {//说明有需要进行平衡的节点 if (height(comareElement.left.left) >= height(comareElement.left.right)) {//说明左左 需要就行右旋转 comareElement = rotateLeft(comareElement); }else { comareElement = rotateLeftAndRight(comareElement);//先左旋转 后右旋转 } }else if(height(comareElement.right) - height(comareElement.left) >1) { if (height(comareElement.right.right) >= height(comareElement.right.left)) {//右右 需要进行做旋转 comareElement = rotateRight(comareElement); }else { comareElement = rotateRightAndLeft(comareElement);//先有旋转 后做旋转 } } comareElement.height = Math.max(height(comareElement.left), height(comareElement.right))+1; return comareElement; } /** * 返回节点的 高度 * @param node * @return */ private Integer height(AVLNode<Element> node){ return node == null ? -1:node.height; } //是否包含某一个元素 public Boolean contains(Element element){ return contains(element,root); } private Boolean contains(Element e, AVLNode<Element> comareElement) { if (comareElement == null) { return false; } int compareTo = e.compareTo(comareElement.element);//要查找的元素 和当前元素进行比较 if (compareTo == 1) {//说明在右边 return contains(e, comareElement.right);//进行递归 }else if (compareTo == -1) {//说明在左边 return contains(e, comareElement.left); } return true; //说明找到了当前节点 } //节点的 左节点小 右节点大 private static class AVLNode<Element>{ //一个二叉树节点 private Element element; private AVLNode<Element> left; private AVLNode<Element> right; private Integer height =0;//相较于二叉查找树,新增对各节点 高度的值,用于计算是否平衡 public AVLNode(Element element, AVLNode<Element> left, AVLNode<Element> right, Integer height) { super(); this.element = element; this.left = left; this.right = right; this.height = height; } public AVLNode(Element element, AVLNode<Element> left, AVLNode<Element> right) { super(); this.element = element; this.left = left; this.right = right; } } public static void main(String[] args) { AVLTree<Integer> binaryTree = new AVLTree<Integer>(); binaryTree.insert(6); binaryTree.insert(2); binaryTree.insert(8); binaryTree.insert(1); binaryTree.remove(2); print(binaryTree.root); } static void print( AVLNode<Integer> node){ if (node!=null) { if (node.right!=null) { print(node.right); System.out.println(node.right.element); } if (node.left!=null) { print(node.left); System.out.println(node.left.element); } } } }