【漫畫】以後在有面試官問你AVL樹,你就把這篇文章扔給他。
背景
西天取經的路上,一樣上演著程式設計的樂趣…..
1、若它的左子樹不為空,則左子樹上所有的節點值都小於它的根節點值。
2、若它的右子樹不為空,則右子樹上所有的節點值均大於它的根節點值。
3、它的左右子樹也分別可以充當為二叉查詢樹。
例如:
例如,我現在想要查詢數值為14的節點。由於二叉查詢樹的特性,我們可以很快著找到它,其過程如下:
1、和根節點9比較
2、由於 14 > 9,所以14只可能存在於9的右子樹中,因此檢視右孩子13
3、由於 14 > 13,所以繼續檢視13的右孩子15
4、由於 14 < 15,所以14只可能存在於15的左孩子中,因此查詢15的左孩子14
5、這時候發現14正是自己查詢的值,於是查詢結束。
這種查詢二叉樹的查詢正是二分查詢的思想,可以很快著找到目的節點,查詢所需的最大次數等同於二叉查詢樹的高度。
在插入的時候也是一樣,通過一層一層的比較,最後找到適合自己的位置。
初始的二叉查詢樹只有三個節點:
然後我們按照順序陸續插入節點 4,3,2,1,0。插入之後的結構如下:
這是一種比查詢二叉樹還特別的樹哦,這種樹就可以幫助我們解決二叉查詢樹剛才的那種所有節點都傾向一邊的缺點的。具有如下特性:
具有二叉查詢樹的全部特性。
每個節點的左子樹和右子樹的高度差至多等於1。
例如:圖一就是一顆AVL樹了,而圖二則不是(節點右邊標的是這個節點的高度)。
對於圖二,因為節點9的左孩子高度為2,而右孩子高度為0。他們之間的差值超過1了。
這種樹就可以保證不會出現大量節點偏向於一邊的情況了。
聽起來這種樹還不錯,可以對於圖1,如果我們要插入一個節點3,按照查詢二叉樹的特性,我們只能把3作為節點4的左子樹插進去,可是插進去之後,又會破壞了AVL樹的特性,那我們那該怎麼弄?
右旋
我們在進行節點插入的時候,可能會出現節點都傾向於左邊的情況,例如:
我們把這種傾向於左邊的情況稱之為 左-左型。這個時候,我們就可以對節點9進行右旋操作,使它恢復平衡。
即:順時針旋轉兩個節點,使得父節點被自己的左孩子取代,而自己成為自己的右孩子
再舉個例子:
節點4和9高度相差大於1。由於是左孩子的高度較高,此時是左-左型,進行右旋。
這裡要注意,節點4的右孩子成為了節點6的左孩子了
我找了個動圖,儘量這個動圖和上面例子的節點不一樣。
左旋
左旋和右旋一樣,就是用來解決當大部分節點都偏向右邊的時候,通過左旋來還原。例如:
我們把這種傾向於右邊的情況稱之為 右-右型。
我也找了一張動圖。
例子講解
初始狀態如下:
然後我們主鍵插入如下數值:1,4,5,6,7,10,9,8
插入 1
左-左型,需要右旋調整。
插入4
繼續插入 5
右-右型,需要左旋轉調整。
繼續插入6
右-右型,需要進行左旋
繼續插入7
右-右型,需要進行左旋
繼續插入10
繼續插入9
出現了這種情況怎麼辦呢?對於這種 右-左型 的情況,單單一次左旋或右旋是不行的,下面我們先說說如何處理這種情況。
這種我們就把它稱之為 右-左 型吧。處理的方法是先對節點10進行右旋把它變成右-右型。
然後在進行左旋。
所以對於這種 右-左型的,我們需要進行一次右旋再左旋。
同理,也存在 左-右型的,例如:
對於左-右型的情況和剛才的 右-左型相反,我們需要對它進行一次左旋,再右旋。
回到剛才那道題
對它進行右旋再左旋。
到此,我們的插入就結束了。
總結一下
在插入的過程中,會出現一下四種情況破壞AVL樹的特性,我們可以採取如下相應的旋轉。
1、左-左型:做右旋。
2、右-右型:做左旋轉。
3、左-右型:先做左旋,後做右旋。
4、右-左型:先做右旋,再做左旋。
不知道大家發現規律沒,這個規則還是挺好記。
程式碼實現
//定義節點class AvlNode {intdata; AvlNode lchild;//左孩子AvlNode rchild;//右孩子intheight;//記錄節點的高度}//在這裡定義各種操作publicclass AVLTree{//計算節點的高度staticintheight(AvlNode T) {if(T ==null) {return-1; }else{returnT.height; } }//左左型,右旋操作staticAvlNode R_Rotate(AvlNode K2) { AvlNode K1;//進行旋轉K1 = K2.lchild; K2.lchild = K1.rchild; K1.rchild = K2;//重新計算節點的高度K2.height= Math.max(height(K2.lchild),height(K2.rchild)) +1; K1.height= Math.max(height(K1.lchild),height(K1.rchild)) +1;returnK1; }//進行左旋staticAvlNode L_Rotate(AvlNode K2) { AvlNode K1; K1 = K2.rchild; K2.rchild = K1.lchild; K1.lchild = K2;//重新計算高度K2.height= Math.max(height(K2.lchild),height(K2.rchild)) +1; K1.height= Math.max(height(K1.lchild),height(K1.rchild)) +1;returnK1; }//左-右型,進行右旋,再左旋staticAvlNode R_L_Rotate(AvlNode K3) {//先對其孩子進行左旋K3.lchild = R_Rotate(K3.lchild);//再進行右旋returnL_Rotate(K3); }//右-左型,先進行左旋,再右旋staticAvlNode L_R_Rotate(AvlNode K3) {//先對孩子進行左旋K3.rchild = L_Rotate(K3.rchild);//在右旋returnR_Rotate(K3); }//插入數值操作staticAvlNode insert(intdata, AvlNode T) {if(T ==null) { T =newAvlNode(); T.data = data; T.lchild = T.rchild =null; }elseif(data < T.data) {//向左孩子遞迴插入T.lchild = insert(data, T.lchild);//進行調整操作//如果左孩子的高度比右孩子大2if(height(T.lchild) -height(T.rchild) ==2) {//左-左型if(data < T.lchild.data) { T = R_Rotate(T); }else{//左-右型T = R_L_Rotate(T); } } }elseif(data > T.data) { T.rchild = insert(data, T.rchild);//進行調整//右孩子比左孩子高度大2if(height(T.rchild) -height(T.lchild) ==2)//右-右型if(data > T.rchild.data) { T = L_Rotate(T); }else{ T = L_R_Rotate(T); } }//否則,這個節點已經在書上存在了,我們什麼也不做//重新計算T的高度T.height= Math.max(height(T.lchild),height(T.rchild)) +1;returnT; }}
提示:可以左右拉動
希望通過這種漫畫的形式,能夠讓你們更加容易讀懂一些演算法或資料結構。
歡迎工作一到五年的Java工程師朋友們加入Java填坑之路:860113481
群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用”沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
相關文章
- 【漫畫】以後在有面試官問你平衡(AVL)樹,你就把這篇文章扔給他。面試
- 以後有面試官問你跳躍表,你就把這篇文章扔給他面試
- 以後有面試官問你「跳躍表」,你就把這篇文章扔給他面試
- 面試官問你B樹和B+樹,就把這篇文章丟給他面試
- 再有人問你分散式鎖,這篇文章扔給他分散式
- 再有人問你synchronized是什麼,就把這篇文章發給他。synchronized
- 再有人問你volatile是什麼,就把這篇文章發給他
- 再有人問你synchronized是什麼,就把這篇文章發給他synchronized
- 面試官問你MyBatis SQL是如何執行的?把這篇文章甩給他面試MyBatisSQL
- 如果有人再問你 Java 的反射,把這篇文章扔給他Java反射
- Spring註解驅動開發第16講——面試官再問你BeanPostProcessor的執行流程,就把這篇文章甩給他!Spring面試Bean
- 面試官問:“在專案中用過多執行緒嗎?”你就把這個案例講給他聽!面試執行緒
- 再有人問你volatile是什麼,就把這篇文章發給他,讓他啞口無言
- 再有人問你Java記憶體模型是什麼,就把這篇文章發給他。Java記憶體模型
- 再有人問你Java記憶體模型是什麼,就把這篇文章發給他Java記憶體模型
- 面試官出的MySQL索引問題,這篇文章全給你解決!面試MySql索引
- 再有人問你分散式事務,把這篇扔給他分散式
- 當面試官問你Vue響應式原理,你可以這麼回答他面試Vue
- 如果再有人問你分散式 ID,這篇文章丟給他分散式
- 如果有人給你撕逼Java記憶體模型,就把這些問題甩給他Java記憶體模型
- 誰再說學不會 MySQL 資料庫,就把這個給他扔過去!MySql資料庫
- 當面試官問你這個問題的時候,他想聽到什麼?面試
- 面試時,面試官問:你以後的規劃是怎樣的 如何回答呢面試
- 一篇文章帶你搞定經典面試題之扔雞蛋問題面試題
- 面試官問你基本型別時他想知道什麼面試型別
- 還有人不懂分散式鎖的實現就把這篇文章丟給他分散式
- 當面試官問出“Unsafe”類時,我就知道這場面試廢了,祖墳都能給你問出來!面試
- 面試官,你再問我 Bit Operation 試試?面試
- 以後再有人說程式設計師懶,請把這篇文章給他看!程式設計師
- BATJ面試redis靈魂36問,你這麼回答,面試官一定對你刮目相看BAT面試Redis
- 騰訊面試官:兄弟,你說你會Webpack,那說說他的原理?面試Web
- 面試官:註解五問你怕了嗎?面試
- 當面試官問你如何進行效能優化時,你該這麼回答(一)面試優化
- 面試官:你能回答這兩個簡單的問題嗎面試
- 面試官:給你一段有問題的SQL,如何最佳化?面試SQL
- 面試官問:你瞭解HTTP2.0嗎?面試HTTP
- 如果有人再問你怎麼實現分散式延時訊息,這篇文章丟給他分散式
- 面試官這樣問你:為什麼MySQL新增索引後就可以提高查詢速度面試MySql索引