平衡二叉樹的重點在於對不平衡的進行旋轉從而使它達到平衡.數據結構
下面是我理解的平衡二叉樹的操做總結:ide
平衡因子(BF):
這是一個描述平衡度的一個量,計算的方式爲 左子樹的深度-右子樹的深度。this
咱們能夠從BF中就能知道左子樹和右子樹之間的平衡程度。spa
插入數據3d
平衡二叉樹最複雜的就是將數據插入到樹中了,由於要涉及到位置的調整。對於位置的調整在平衡二叉樹中成爲樹的旋轉.根據平衡因子的狀態分爲左旋和右旋.code
那何時須要進行旋轉呢?blog
這個問題確實值得思考,通常都是在平衡因子的絕對值大於1的時候就須要進行旋轉了,也就是說左右子樹的深度相差超過了1.get
那從什麼地方作爲跟節點進行旋轉呢?it
這裏有一個術語叫作最小不平衡子樹,就是平衡因子絕對值大於1,而且最接近葉子節點的。io
咱們旋轉的時候,只須要對最小不平衡子樹進行旋轉就能夠了。
左旋:
當平衡因子爲正數的時候而且大於1的時候,進行左旋,左旋的方式爲:
根節點的左子樹的右子樹做爲根節點的右子樹,根節點做爲左子樹的右子樹。
右旋:
當平衡因子爲負數的時候,而且小於-1的時候進行右旋,右旋的方式爲:
將根節點的右節點的左子樹做爲根節點的右子樹.
根節點做爲跟節點的右節點的左子樹。
注意:
上面兩種實例根節點和子節點都是同一符號的,因此簡單的進行左旋或者右旋就能夠了。以下圖:
,可是若是咱們遇到符號不相同的狀況下,須要進行兩次旋轉,以下圖:
這種狀況下,第一次旋轉是將C做爲根節點右旋,以後再進行左旋.
咱們只須要記住正數的時候進行右旋,負數的時候進行左旋便可。
上面的原理講完了,下面是具體的JAVA代碼實現:
package com.hotusm.datastructure.tree; /** * @author luqibao * @date 2017/3/31 */ public class AVLTree { /** * 平衡因子所屬的狀態 */ private static final int LH = 1; //左邊高 private static final int EH = 0; //同樣高 private static final int RH = -1; //右邊高 private TreeNode root; //樹的根 /** * 向平衡二叉樹插入節點 * * @param data */ public void insertNode(int data) { if (this.root == null) { this.root = new TreeNode(null, null, EH, data, null); return; } insertAVLNode(this.root, data); } /** * 進行右旋 * * @param treeNode 須要旋轉的根 */ /* * 右旋 * 將根的左子樹的右子樹做爲根的左子樹 * 左子樹的右子樹指向根(最後左子樹變爲了根,根變爲了右子樹) */ private void rRotate(TreeNode treeNode) { TreeNode root = treeNode.getLeft(); if (treeNode == this.root) { this.root = root; } treeNode.setLeft(root.getRight()); root.setRight(treeNode); } /** * 進行左旋 * * @param treeNode 須要旋轉的根 */ /* * 左旋 * 將根的右子樹的左子樹做爲根的右子樹 * 右子樹的左子樹指向根(最後右子樹變爲個根,根變爲了左子樹) * */ private void lRotate(TreeNode treeNode) { TreeNode root = treeNode.getRight(); if (treeNode == this.root) { this.root = root; } treeNode.setRight(root.getLeft()); root.setLeft(treeNode); } /** * 左平衡旋轉(左邊平衡因子太大的緣由 須要向右移動) * * @param root */ private void leftBalance(TreeNode root) { TreeNode leftNode = root.getLeft(); switch (leftNode.getBf()) { case LH: root.setBf(EH); leftNode.setBf(EH); rRotate(root); break; //若是是這種狀況 根和左子樹平衡因子不是同符號的 因此須要兩次的旋轉 case RH: TreeNode doubleLeftNode = leftNode.getRight();// 左子樹的右子樹 switch (doubleLeftNode.getBf()) { case RH: root.setBf(EH); leftNode.setBf(LH); break; case EH: root.setBf(EH); leftNode.setBf(EH); break; case LH: root.setBf(RH); leftNode.setBf(EH); break; } doubleLeftNode.setBf(EH); lRotate(leftNode); rRotate(root); break; } } /** * 右平衡旋轉 右邊平衡因子太大的緣由 * * @param root */ private void rightBalance(TreeNode root) { TreeNode rightNode = root.getRight(); switch (rightNode.getBf()) { case RH: root.setBf(EH); rightNode.setBf(EH); lRotate(root); break; case LH: //若是是這種狀況 那麼根和右子樹的平衡因子不一樣符號 因此須要進行兩次的旋轉 TreeNode doubleLeftNode = rightNode.getLeft(); switch (doubleLeftNode.getBf()) { case LH: root.setBf(EH); rightNode.setBf(RH); break; case EH: root.setBf(EH); rightNode.setBf(EH); break; case RH: root.setBf(LH); rightNode.setBf(EH); break; } doubleLeftNode.setBf(EH); rRotate(rightNode); lRotate(root); break; } } /** * 向平衡二叉樹插入數據data * 若是增高那麼返回true 不然返回false * * @param data * @return */ private boolean insertAVLNode(TreeNode root, int data) { boolean taller = false; if (root.getData() == data) { return false; } if (data < root.getData()) { if (root.getLeft()==null){ TreeNode child=new TreeNode(null,null,EH,data,root); root.setLeft(child); if (root.getBf()==EH){ root.setBf(LH); return true; } /* * 在child 節點未插入到root的左子樹中的時候 * root的BF只能有兩種狀況 EH(左右都沒節點) 和 RH(有右葉子節點) * 因此還有一種可能就是當時RH的時候 BF變爲EH * */ root.setBf(EH); }else { taller=insertAVLNode(root.getLeft(),data); if (taller){ switch (root.getBf()){ case LH: leftBalance(root); taller=false; break; case EH: /* *進行上一級的回溯 * O * O O * O O */ root.setBf(LH); taller=true; break; default: root.setBf(EH); taller=false; } } } } else { if (root.getRight()==null){ TreeNode child=new TreeNode(null,null,EH,data,root); root.setRight(child); if (root.getBf()==EH){ root.setBf(RH); } /* * 和上面的相似,在右子樹插入到root以前 root的BF只有兩種狀況 EH(沒有左右節點) LH (只有左葉子節點) * */ root.setBf(EH); }else { taller=insertAVLNode(root.getRight(),data); if (taller){ switch (root.getBf()){ case RH: rightBalance(root); taller=false; break; case LH: root.setBf(EH); taller=false; break; default: /* *這裏會進行回溯到更上的一級進行判斷 從而進行旋轉 * O * O O * O O */ root.setBf(RH); taller=true; } } } } return taller; } public static void main(String[] args) { testInsertAVLTree(); } public static void testInsertAVLTree() { AVLTree avlTree = new AVLTree(); avlTree.insertNode(1); avlTree.insertNode(2); avlTree.insertNode(3); avlTree.insertNode(4); avlTree.insertNode(5); } /** * 樹的節點 */ public static class TreeNode { private TreeNode left; private TreeNode right; private TreeNode parent; private int bf; //平衡因子 private int data; public TreeNode(TreeNode left, TreeNode right, int bf, int data, TreeNode parent) { this.left = left; this.right = right; this.bf = bf; this.data = data; this.parent = parent; } public TreeNode getLeft() { return left; } public void setLeft(TreeNode left) { this.left = left; } public TreeNode getRight() { return right; } public void setRight(TreeNode right) { this.right = right; } public int getBf() { return bf; } public void setBf(int bf) { this.bf = bf; } public int getData() { return data; } public TreeNode getParent() { return parent; } public void setParent(TreeNode parent) { this.parent = parent; } public void setData(int data) { this.data = data; } @Override public String toString() { return "TreeNode{" + "left=" + left + ", right=" + right + ", bf=" + bf + ", data=" + data + '}'; } } }
代碼中進行了詳細的註釋,看起來應該是沒問題的。
參考:大話數據結構 第八章