首先讲一下平衡二叉树的基本思路,算是一种总结。
平衡二叉树是在二叉排序树的基础上产生的,如果你不了解二叉排序树,请先看看《算法导论》。
由于二叉排序树有时会产生不平衡的情况,于是需要设计算法使不平衡的情况从新归为平衡。
于是,就涉及两个问题。
1,如何发现不平衡
这里为二叉树加入高度的概念,当左子树和右子树高度差为2时,为不平衡。于是调整该子树。
在代码的具体实现中,就体现在增加节点,和删除节点后,判断二叉树不是否平衡,若不平衡,哪里开始不平衡。
这需要在递归的过程中进行判断,例如插入节点时,需要在递归的过程中寻找插入位置。而在退出递归时,每退出一层,都会在该层递归函数尾,重新设定该节点高度(叶子节点为1,以上每一层加一,且父亲节点高度取子节点高度最大值加一),并判断该子树是否平衡。不平衡则调整。这样的方式,在递归(插入,删除操作),以及一层层退出递归(调整二叉树)的过程中,实现平衡。
2,如何重新变为平衡
四种旋转方式:
图取自http://www.cnblogs.com/skywang12345/p/3577479.html
I will wrote code of AVLTree carefully,to wrote the best of java code.
and I will apply java's Generic,and the principle of "Interface oriented programming" by the structure of three layerings of entity,service and serviceimpl.
具体实现,参照下文代码。
实体类代码,基本二叉树结构外加入height:
1 /** 2 * @ClassName: AVLNode 3 * @author Hyuga 4 * @date 2015-12-29 下午1:58:39 5 * @Description: Entity class of AVL tree 6 * @version 1.0 7 */ 8 public class AVLNode<T extends Comparable<T>> 9 { 10 11 // Value of node 12 private T data; 13 14 // Left child 15 private AVLNode<T> leftChild; 16 17 // Right child 18 private AVLNode<T> rightChild; 19 20 //Height of node 21 private Integer height; 22 23 public T getData() 24 { 25 return data; 26 } 27 28 public void setData(T data) 29 { 30 this.data = data; 31 } 32 33 public AVLNode<T> getLeftChild() 34 { 35 return leftChild; 36 } 37 38 public void setLeftChild(AVLNode<T> leftChild) 39 { 40 this.leftChild = leftChild; 41 } 42 43 public AVLNode<T> getRightChild() 44 { 45 return rightChild; 46 } 47 48 public void setRightChild(AVLNode<T> rightChild) 49 { 50 this.rightChild = rightChild; 51 } 52 53 public Integer getHeight() 54 { 55 return height; 56 } 57 58 public void setHeight(Integer height) 59 { 60 this.height = height; 61 }
面向接口编程,接口列表:
/** * @ClassName: AVLService * @Description: Service class of avl tree * @author Hyuga * @date 2015-12-29 - 2015-12-31 * @version 1.0 * @param <T> */ public interface AVLService<T extends Comparable<T>> { /** * add node to AVL tree,return the information of execution */ public AVLNode<T> addNode(AVLNode<T> node,T value); /** * delete node from AVL tree,return the information of execution */ public AVLNode<T> deleteNode(AVLNode<T> root,AVLNode<T> node,T value); /** * search the node of value given */ public AVLNode<T> searchNode(AVLNode<T> root,T value); /** * level traverse */ public void levelTraverse(AVLNode<T> root); /** * LDR */ public AVLNode<T> inOrderTraverse(AVLNode<T> root); }
具体实现类
对外方法:
插入节点:addNode
删除节点 deleteNode
层次遍历 levelTraverse
中序遍历 inOrderTraverse
查找结点 searchNode
内部方法
四种旋转方式 rightRightRotation
leftLeftRotation
leftRightRotation
rightLeftRotation
求两int数中大值 max
返回左子树和右子树中高的大值+1
getMaxHeight
或取子树最大节点--最右边 的父节点
getParentOfMax
将找到的节点删除
remove
判断是LL旋转还是LR旋转,并旋转
LL_LR
判断是RR旋转还是RL旋转,并旋转
RR_RL
/** * @ClassName: AVLServiceImpl * @Description: Service impl class of avl tree * @author Hyuga * @date 2015-12-29 - 2015-12-31 * @version 1.0 * @param <T> */ public class AVLServiceImpl<T extends Comparable<T>> implements AVLService<T> { /** * insert a node to AVL tree. */ @Override public AVLNode<T> addNode(AVLNode<T> root, T value) { if (null == value) { System.out.println("Please insert valid value"); return null; } if (null == root) { root = new AVLNode<T>(); root.setData(value); root.setHeight(0); } else { int cmp = root.getData().compareTo(value); AVLNode<T> leftChild = root.getLeftChild(); AVLNode<T> rightChild = root.getRightChild(); if (cmp == 0) System.out.println("You should not add duplicate node"); if (cmp < 0) // insert to right { root.setRightChild(addNode(rightChild, value)); if (getHeight(rightChild) - getHeight(leftChild) == 2) { root = RR_RL(root); } } else // insert to left { root.setLeftChild(addNode(leftChild, value)); if (getHeight(leftChild) - getHeight(rightChild) == 2) { root = LL_LR(root); } } } root.setHeight(getMaxHeight(root)); return root; } @Override public AVLNode<T> searchNode(AVLNode<T> root, T value) { if (null == root) { System.out.println("Node does not exist"); return null; } int cmp = root.getData().compareTo(value); if (value == root.getData()) return root; if (cmp > 0) return searchNode(root.getLeftChild(), value); else return searchNode(root.getRightChild(), value); } /** * find and delete a node */ @Override public AVLNode<T> deleteNode(AVLNode<T> parent, AVLNode<T> node, T value) { if (null == value) { System.out.println("Please insert valid value"); return null; } else if (null == node) { System.out.println("Tree does not exist"); } else { int cmp = node.getData().compareTo(value); if (cmp == 0) { node = remove(parent, node, value); } else if (cmp < 0) { deleteNode(node, node.getRightChild(), value); if (getHeight(node.getLeftChild()) - getHeight(node.getRightChild()) == 2) { node = LL_LR(node); } } else { deleteNode(node, node.getLeftChild(), value); if (getHeight(node.getRightChild()) - getHeight(node.getLeftChild()) == 2) { node = RR_RL(node); } } } node.setHeight(getMaxHeight(node)); return node; } /** * LL or LR */ private AVLNode<T> LL_LR(AVLNode<T> root) { AVLNode<T> temp = root.getLeftChild().getRightChild(); if(null == temp || (null == temp.getRightChild()&&null == temp.getLeftChild())) return leftLeftRotation(root); else return leftRightRotation(root); } /** * RR or RL */ private AVLNode<T> RR_RL(AVLNode<T> root) { AVLNode<T> temp = root.getRightChild().getLeftChild(); if(null == temp|| (null == temp.getLeftChild() && null == temp.getRightChild())) return rightRightRotation(root); else return rightLeftRotation(root); } /** * remove the node which found */ private AVLNode<T> remove(AVLNode<T> parent, AVLNode<T> node, T value) { if (null == node.getLeftChild() && null == node.getRightChild()) { if (parent.getData().compareTo(value) > 0) parent.setLeftChild(null); else parent.setRightChild(null); node = parent; } else if (null == node.getLeftChild()) { if (parent.getData().compareTo(value) > 0) parent.setLeftChild(node.getRightChild()); else parent.setRightChild(node.getRightChild()); } else if (null == node.getRightChild()) { if (parent.getData().compareTo(value) > 0) parent.setLeftChild(node.getLeftChild()); else parent.setRightChild(node.getLeftChild()); } else { // either leftChild or rightChild is not null,get the max node of // left child tree to be the root AVLNode<T> parentOfMax; if (null == node.getLeftChild().getRightChild()) { node.getLeftChild().setRightChild(node.getRightChild()); node = node.getLeftChild(); if(parent.getData().compareTo(node.getData())<0) parent.setRightChild(node); else parent.setLeftChild(node); } else { // get the parent of the max node of the leftchild of root. parentOfMax = getParentOfMax(node.getLeftChild()); AVLNode<T> temp = parentOfMax.getRightChild(); // remove the root and set the max node of the leftchild to be // the root temp.setLeftChild(node.getLeftChild()); temp.setRightChild(node.getRightChild()); parentOfMax.setRightChild(null); node = temp; } } return node; } /** * get the parent of max node */ private AVLNode<T> getParentOfMax(AVLNode<T> root) { if (null == root.getRightChild().getRightChild() || null == root.getRightChild()) return root; else return getParentOfMax(root.getRightChild()); } private int getHeight(AVLNode<T> root) { if (null == root) return 0; return root.getHeight(); } /** * get max value of two int */ private int max(int int1, Integer int2) { if (int1 >= int2) return int1; return int2; } private int getMaxHeight(AVLNode<T> root) { int leftHeight = (null == root.getRightChild() ? 0 : root .getRightChild().getHeight()); int rightHeight = (null == root.getLeftChild() ? 0 : root .getLeftChild().getHeight()); return max(leftHeight, rightHeight) + 1; } @Override public void levelTraverse(AVLNode<T> root) { if (null == root) return; Queue<AVLNode<T>> queue = new LinkedList<AVLNode<T>>(); queue.add(root); while (!queue.isEmpty()) { AVLNode<T> temp = queue.peek().getLeftChild(); if (null != temp) queue.add(temp); temp = queue.peek().getRightChild(); if (null != temp) queue.add(temp); System.out.print(queue.poll().getData() + " "); } } @Override public AVLNode<T> inOrderTraverse(AVLNode<T> root) { if(null == root) return null; inOrderTraverse(root.getLeftChild()); System.out.print(root.getData() + " "); inOrderTraverse(root.getRightChild()); return root; } private AVLNode<T> leftLeftRotation(AVLNode<T> node) { AVLNode<T> temp = node.getLeftChild(); node.setLeftChild(temp.getRightChild()); temp.setRightChild(node); node.setHeight(max(getHeight(node.getLeftChild()), getHeight(node.getRightChild())) + 1); temp.setHeight(max(getHeight(temp.getLeftChild()), node.getHeight()) + 1); return temp; } private AVLNode<T> leftRightRotation(AVLNode<T> node) { node.setLeftChild(rightRightRotation(node.getLeftChild())); return leftLeftRotation(node); } private AVLNode<T> rightLeftRotation(AVLNode<T> node) { node.setRightChild(leftLeftRotation(node.getRightChild())); return rightRightRotation(node); } private AVLNode<T> rightRightRotation(AVLNode<T> node) { AVLNode<T> temp = node.getRightChild(); node.setRightChild(temp.getLeftChild()); temp.setLeftChild(node); node.setHeight(max(getHeight(node.getLeftChild()), getHeight(node.getRightChild())) + 1); temp.setHeight(max(getHeight(temp.getRightChild()), node.getHeight()) + 1); return temp; } }
最后测试代码及结果:
public class AVLTest { /** * test code */ public static void main(String[] args) { System.out.println("Algorithm of AVLBinaryTree by 无名.2015.12.31"); AVLNode<Integer> root = new AVLNode<Integer>(); AVLService<Integer> avlService = new AVLServiceImpl<Integer>(); root.setData(12); root.setHeight(0); System.out.println("insert,13,15,17,19,20"); System.out.println("inserting..."); root = avlService.addNode(root, 13); root = avlService.addNode(root, 15); root = avlService.addNode(root, 17); root = avlService.addNode(root, 19); root = avlService.addNode(root, 20); System.out.println("inorder traverse:"); avlService.inOrderTraverse(root); System.out.println(); System.out.println("level traverse:"); avlService.levelTraverse(root); System.out.println(); System.out.println("delete 17 and level traverse:"); root = avlService.deleteNode(root, root, 17); avlService.levelTraverse(root); System.out.println(); System.out.println("delete 19,20 and level traverse:"); root = avlService.deleteNode(root, root, 19); root = avlService.deleteNode(root, root, 20); avlService.levelTraverse(root); } }