二叉查找樹已經可以很好的應用到應用程序中,但它們在最壞的狀況下性能仍是很糟糕。考慮到如圖所示這種狀況: 查找操做的性能徹底等同於線性。而AVL樹的查找操做,可以保證不管怎麼構造它,運行時間一直對數級別的。一塊兒來學習一下AVL樹吧。java
AVL(Adelson-Velsky 和 Landis)樹,是帶有平衡條件的二叉查找樹,這個平衡條件必需要容易保持,而且它保證樹的深度是O(LogN).算法
一顆AVL樹是其每一個節點的左右子樹節點高度最多差1的二叉查找樹。編程
我門上面說,一顆AVL樹是其每一個節點的左右子樹節點高度最多差1的二叉查找樹。 左右子樹的高度最多差1即是AVL樹的平衡條件。數據結構
當進行插入操做時,咱們須要更新通往根節點的全部節點的平衡信息。而插入操做隱含困難的緣由在於,可能會破壞AVL樹的特性(例如,考慮將6插入到圖1的AVL樹中將會破壞節點爲8的平衡條件)。若是發生這種情形,那麼就要考慮在插入完成以後從新回覆節點的平衡信息。事實上,總能夠經過對樹進行簡單的修正獲得,咱們稱其爲旋轉(ratation).app
在插入之後,只有那些從插入點到根節點的平衡條件可能變化,由於只有這些節點的字數可能發生變化。當咱們沿着這條路路徑行進到根節點,能夠發現一個節點它的新平衡破壞了AVL樹的特性。咱們須要在這個節點從新平衡這棵樹。ide
咱們把必須從新平衡的節點叫作α。由於平衡條件是高度最多相差1,那麼出現不平衡就是α點的高度相差爲2。容易看出這種不平衡可能出如今下面這四種狀況下:性能
1和4,2和3 是關於α點的鏡像對稱。所以理論上講只有兩種狀況,固然編程上仍是四種狀況。學習
第一種狀況是插入發生在外邊的狀況(即左-左的狀況或者右-右的狀況),該狀況是經過對樹的一次單旋轉來完成操做。this
第二種狀況是插入發生在內部的情形(即左-右的狀況或者右-左的狀況),該狀況經過稍微複雜點的雙旋轉操做來處理。scala
下圖顯示了單旋轉如何調整情形1。旋轉前的圖在左邊,旋轉後的圖在右邊。
讓咱們來分析具體的作法。節點K2不知足平衡條件, 由於它的左子樹比右子樹深兩層(圖中的虛線表示樹的各層).
爲使樹恢復平衡,咱們把節點X向上移一層,並把Z像下移一層,爲此咱們從新安排節點以造成一顆等價的樹。如上圖的右邊部分。抽象的形容就是,把把樹想象成一棵柔軟靈活的樹,抓住子節點K1,閉上眼睛使勁的搖動它,這樣因爲重力的做用,K1就變成了新的根。二叉樹的性質告訴咱們,在原樹中K2>K1,這樣在新樹中,K2變成了K1的右兒子,Y變成了K2的左子樹,而X、Z依然是K1的左子樹和K2的右子樹。
讓咱們演示一個更長的例子,假設從初始的空的AVL樹開始依次插入三、二、1,而後再依次插入4-7.
在插入關鍵字1的時候第一個問題就出現了,AVL性質在根處被破壞,咱們在根和其左兒子之間施加單旋轉操做來修正問題。下圖是旋轉以前和以後的兩棵樹。
圖中虛線鏈接的兩個節點,它們是旋轉的主體。下面咱們插入關鍵字4這沒有問題,在咱們插入關鍵字5的時候,問題又出現了,平衡條件在關鍵字3處被破壞,而經過單旋轉再次將問題修復。
接下來插入6,平衡條件在根節點處被打破,所以咱們在根處,在二、4之間施加一次單旋轉操做。
咱們插入最後的關鍵字7,它致使另外的旋轉。
單旋轉對情形二、3無效願因在於子樹Y太深。單旋轉沒有下降它的深度。
對於子樹Y咱們能夠假設他有一個根和兩棵子樹(對應上圖的K二、B、C)。
爲了平衡期間,咱們不能再把K3當成根了,而如上圖所示K3和K1之間旋轉又解決不了問題,惟一的選擇是把K2當成根,這迫K1成爲K2的左子樹,K3成爲K1的右子樹,而K2的左子樹成爲K1的右子樹,K2的右子樹成爲K3的左子樹。容易看出最後獲得的樹知足AVL樹的特徵。
咱們繼續在前面例子的基礎上以倒序插入10-16,接着插入8,再插入9.插入16很容易這並不破壞樹的平衡,插入15會引發節點7處的高度不平衡,這屬於情形3,須要經過右-左雙旋轉來解決。如圖:
下面咱們來插入14,它也須要一個雙旋轉。此時修復樹的旋轉仍是右-左雙旋轉
若是如今插入13那麼在根處就會出現不平衡,因爲13不在4-7之間,咱們知道只要一次單旋轉就行.
插入12也須要一次雙旋轉
插入十一、10都須要進行單旋轉,接着咱們插入8不須要進行旋轉,這樣就建成了一顆近乎理想的平衡樹
最後咱們插入9,在節點10發生不平衡,這裏知足情形2,對左兒子的右子樹進行一次,須要一次雙旋轉。
如今讓咱們對上面的討論作出總結,除幾種情形外,編程的細節是至關簡單的。爲將節點X插入AVL樹T中,咱們遞歸的將X插入到T的子樹中。若是子樹的高度不變,那麼插入完成;若是出現高度不平衡,那麼找到不平衡點,作適當的單旋轉或者雙旋轉,更新這些高度,從而完成插入。
sealed trait AVLTree[+A] extends Serializable { def balance: Int def depth: Int def contains[B >: A](x: B)(implicit ordering: Ordering[B]): Boolean def insert[B >: A](x: B)(implicit ordering: Ordering[B]): AVLTree[B] def rebalance[B >: A]: AVLTree[B] } /** * 葉子節點 */ case object Leaf extends AVLTree[Nothing] { override val balance: Int = -1 override val depth: Int = 0 override def contains[B >: Nothing](x: B)(implicit ordering: Ordering[B]): Boolean = false override def insert[B >: Nothing](x: B)(implicit ordering: Ordering[B]): AVLTree[B] = { Node(x, Leaf, Leaf) } override def rebalance[B >: Nothing]: AVLTree[B] = this } case class Node[A](value: A, left: AVLTree[A], right: AVLTree[A]) extends AVLTree[A] { override def balance: Int = right.depth - left.depth override def depth: Int = math.max(left.depth, right.depth) override def contains[B >: A](x: B)(implicit ordering: Ordering[B]): Boolean = ??? override def insert[B >: A](x: B)(implicit ordering: Ordering[B]): AVLTree[B] = { val cmp = ordering.compare(x,value) if (cmp < 0){ Node(value, left.insert(x),right).rebalance } else if (cmp > 0){ Node(value, left, right.insert(x)).rebalance } else { this } } override def rebalance[B >: A] = { if (-2 == balance){ if (1 == left.balance){ doubleRightRotation } else { rightRotation } } else if(2 == balance) { if (-1 == right.balance){ doubleLeftRotation }else { leftRotation } } else { this } } /* * 5 * \ 6 * 6 ---- 左單旋轉 ---> / \ * \ 5 7 * 7 * * 在節點5 發生不平衡 5的右節點成爲新的根節點 */ private def leftRotation[B >: A] = { if (Leaf != right) { val r = right.asInstanceOf[Node[A]] Node(r.value, Node(value, left, r.left), r.right) } else { sys.error("should not happen.") } } /* * 7 * / 6 * 6 ---- 右單旋轉 ---> / \ * / 5 7 * 5 * * 在節點7 發生不平衡 7的左節點成爲新的根節點 */ private def rightRotation[B >: A] = { if (Leaf != left) { val l = left.asInstanceOf[Node[A]] Node(l.value, l.left, Node(value, l.right, right)) } else { sys.error("should not happen.") } } /* * 左雙旋轉 * * 5 5 * \ \ 6 * 7 ----step1 ---> 6 ---step2---> / \ * / \ 5 7 * 6 7 * * 在節點5處不平衡 * step1 : 節點5的右節點 作一次 右旋轉 * step2 : 左旋轉 * */ private def doubleLeftRotation[B >: A] = { if (Leaf != right) { val r = right.asInstanceOf[Node[A]] val rightRotated = r.rightRotation Node(rightRotated.value, Node(value, left, rightRotated.left), rightRotated.right) } else { sys.error("should not happen.") } } /* * 右雙旋轉 * * 7 7 * / / 6 * 5 ----step1 ---> 6 ---step2---> / \ * \ / 5 7 * 6 5 * * 在節點7處不平衡 * step1 : 節點7的左節點 作一次 左旋轉 * step2 : 右旋轉 * */ private def doubleRightRotation[B >: A] = { if (Leaf != left) { val l: Node[A] = left.asInstanceOf[Node[A]] val leftRotated = l.leftRotation Node(leftRotated.value, leftRotated.left, Node(value, leftRotated.right, right)) } else sys.error("Should not happen.") } }
《數據結構與算法分析java語言描述》 AVL tree (維基百科)