AVL树全程二叉平衡树,是在二叉查找树之上添加一个平衡条件,那就是左右子树的高度差不超过2,二叉查找树的优点就是插入和查询一个节点的速度快,但是当二叉查找树出现偏缀也就是每个节点都只有左孩子,这个树就会无限向下延申导致查找和插入的效率下降,所以二叉平衡树就出现了。
在这个平衡条件下,就出现了维持二叉树平衡的手段,也就是旋转,在我了解一点这个AVL树的时候我以为这个旋转会很复杂,事实告诉我任何东西只有你上手做你才会了解到他到底难不难。
首先是二叉平衡树的节点
1 public class TreeNode { 2 int val; 3 TreeNode left; 4 TreeNode right; 5 int hight; 6 public TreeNode(int val, TreeNode left, TreeNode right){ 7 this.val = val; 8 this.left = left; 9 this.right = right; 10 this.hight = 0; 11 } 12 }
节点有一个hight属性,也就是左子树或者右子树的最大值。接下来是增删改查四个方法。
在增加之前了解四个旋转方法:LL单旋转,RR单旋转,LR双旋转,RL双旋转
1 public TreeNode leftleftRotation(TreeNode k2){ 2 TreeNode k1 ; 3 k1 = k2.left; 4 k2.left = k1.right; 5 k1.right = k2; 6 7 k2.hight = max(getHight(k2.right), getHight(k2.left)); 8 k1.hight = max(getHight(k1.left), k2.hight); 9 10 return k1; 11 }
1 //RR型单旋转 2 public TreeNode rightRightRotation(TreeNode k2){ 3 TreeNode k1; 4 k1 = k2.right; 5 k2.right = k1.left; 6 k1.right = k2; 7 8 k2.hight = max(getHight(k2.left), getHight(k2.right)); 9 k1.hight = max(getHight(k1.right), k1.hight); 10 11 return k1; 12 }
//LR双旋转 public TreeNode leftRightRotation(TreeNode k3){ k3.left = rightRightRotation(k3.left); return leftleftRotation(k3); }
1 //RL双旋转 2 public TreeNode rightLeftRotation(TreeNode k3){ 3 k3.right = leftleftRotation(k3.right); 4 return rightRightRotation(k3); 5 }
然后是insert方法,我是用递归写的insert,在每次insert之后判断node是否失衡,如果失衡在判断失衡类型采用哪种旋转方法,增加之后更新高度。
1 //增加 2 public void insert(TreeNode node,int val){ 3 if(node == null){ 4 node = new TreeNode(val, null, null); 5 } 6 int com = compareTo(val, node.val); 7 8 if(com < 0){ 9 insert(node.left, val); 10 if(getHight(node.left) - getHight(node.right) == 2){ 11 if(val < node.left.val){ 12 node = leftleftRotation(node); 13 }else{ 14 node = leftRightRotation(node); 15 } 16 } 17 }else if(com > 0){ 18 insert(node.right, val); 19 if(getHight(node.left) - getHight(node.right) == 2){ 20 if(val > node.right.val){ 21 node = rightRightRotation(node); 22 }else{ 23 node = rightLeftRotation(node); 24 } 25 } 26 }else if(com == 0){ 27 return ; 28 } 29 node.hight = max(getHight(node.left), getHight(node.right)); 30 }
接着是删除功能,删除节点之后需要寻找替换节点,这个就是跟二叉查找树一样寻找删除节点的前驱节点或者后继节点,在这之前写一个获取最大节点和获取最小节点两个方法。
1 //获取二叉树的最大节点 2 public TreeNode getMax(TreeNode root){ 3 TreeNode p,x; 4 if(root == null){ 5 return root; 6 } 7 p = root; 8 x = p.right; 9 while(true){ 10 if(x != null){ 11 p = x; 12 x = x.right; 13 }else{ 14 return p; 15 } 16 } 17 }
1 //获取二叉树的最小节点 2 public TreeNode getMin(TreeNode root){ 3 TreeNode p,x; 4 if(root == null){ 5 return root; 6 } 7 p = root; 8 x = p.left; 9 while(true){ 10 if(x != null){ 11 p = x; 12 x = x.left; 13 }else{ 14 return p; 15 } 16 } 17 }
1 public TreeNode del(TreeNode root, int val){ 2 if(val < root.val){ 3 root.left = del(root.left, val); 4 if(getHight(root.right) - getHight(root.left) == 2){ 5 TreeNode node = root.right; 6 if(getHight(node.left) > getHight(node.right)){ 7 root.right = rightLeftRotation(node); 8 }else{ 9 root.right = rightRightRotation(node); 10 } 11 } 12 }else if(val > root.val){ 13 root.right = del(root.right, val); 14 if(getHight(root.left) - getHight(root.right) == 2){ 15 TreeNode node = root.left; 16 if(getHight(node.right) > getHight(node.left)){ 17 root.left = leftRightRotation(node); 18 }else{ 19 root.left = leftleftRotation(node); 20 } 21 } 22 }else{ 23 //找到删除节点后,如果左子树hight > 右子树hight,用左子树的最大节点替换在删除这个节点。 24 //左右子树都非空 25 if ((root.left!=null) && (root.right!=null)) { 26 if (getHight(root.left) > getHight(root.right)) { 27 TreeNode leftMax = getMax(root.left); 28 root.val = leftMax.val; 29 del(root.left, leftMax.val); 30 } else if (getHight(root.left) < getHight(root.right)) { 31 TreeNode rightMin = getMin(root.right); 32 root.val = rightMin.val; 33 del(root.right, rightMin.val); 34 } 35 }else{ 36 root = null; 37 } 38 } 39 return root; 40 }
最后是查询功能
1 //查询 2 public TreeNode sel(TreeNode root, int val){ 3 if(root == null || root.val == val){ 4 return root; 5 } 6 if(val < root.val){ 7 root = sel(root.left, val); 8 }else{ 9 root = sel(root.right, val); 10 } 11 return root; 12 }
总结
实现的很简陋,但是帮我理解了这个二叉平衡树的大部分原理,在我以前看来很艰难很复杂的旋转也并不难,只要加油都会有收获的。