平衡二叉樹,是一種二叉排序樹,其中每個結點的左子樹和右子樹的高度差至多等於1。它是一種高度平衡的二叉排序樹。高度平衡?意思是說,要麼它是一棵空樹,要麼它的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的深度之差的絕對值不超過1。
將二叉樹上結點的左子樹深度減去右子樹深度的值稱爲平衡因子BF,那麼平衡二叉樹上的所有結點的平衡因子只可能是-1、0和1。只要二叉樹上有一個結點的平衡因子的絕對值大於1,則該二叉樹就是不平衡的。
平衡二叉樹的前提是它是一棵二叉排序樹。
距離插入結點最近的,且平衡因子的絕對值大於1的結點爲根的子樹,稱爲最小不平衡子樹。如下圖所示,當插入結點37時,距離它最近的平衡因子的絕對值超過1的結點是58。
1、平衡二叉樹實現原理
平衡二叉樹構建的基本思想就是在構建二叉排序樹的過程中,每當插入一個結點時,先檢查是否因插入而破壞了樹的平衡性,若是,則找出最小不平衡子樹。在保持二叉排序樹特性的前提下,調整最小不平衡子樹中各結點之間的鏈接關係,進行相應的旋轉,使之成爲新的平衡子樹。 下面講解一個平衡二叉樹構建過程的例子。現在又a[10] = {3, 2, 1, 4, 5, 6, 7, 10, 9, 8}需要構建二叉排序樹。在沒有學習平衡二叉樹之前,根據二叉排序樹的特性,通常會將它構建成如下左圖。雖然完全符合二叉排序樹的定義,但是對這樣高度達到8的二叉樹來說,查找是非常不利的。因此,更加期望構建出如下右圖的樣子,高度爲4的二叉排序樹,這樣纔可以提供高效的查找效率。
現在來看看如何將一個數組構成出如上右圖的樹結構。 對於數組a的前兩位3和2,很正常地構建,到了第個數“1”時,發現此時根結點“3”的平衡因子變成了2,此時整棵樹都成了最小不平衡子樹,需要進行調整,如下圖圖1(結點左上角數字爲平衡因子BF值)。因爲BF爲正,因此將整個樹進行右旋(順時針),此時結點2成了根結點,3成了2的右孩子,這樣三個結點的BF值均爲0,非常的平衡,如下圖圖2所示。
然後再增加結點4,平衡因子沒有改變,如上圖圖3。增加結點5時,結點3的BF值爲-2,說明要旋轉了。由於BF是負值,對這棵最小平衡子樹進行左旋(逆時針旋轉),如下圖圖4,此時整個樹又達到了平衡。
繼續增加結點6時,發現根結點2的BF值變成了-2,如下圖圖6所示。所以對根結點進行了左旋,注意此時本來結點3是結點3的左孩子,由於旋轉後需要滿足二叉排序樹特性,因此它成了結點2的右孩子,如圖7所示。
增加結點7,同樣的左旋轉,使得整棵樹達到平衡,如下圖8和9所示。
當增加結點10時,結構無變化,如圖10所示。再增加結點9,此時結點7的BF變成了-2,理論上只需要旋轉最小不平衡樹7、9、10即可,但是,如果左旋轉後,結點9變成了10的右孩子,這是不符合二叉排序樹的特性的,此時不能簡單的左旋。如圖11所示。
仔細觀察圖11,發現根本原因在於結點7的BF是-2,而結點10的BF是1,也就是說,它們兩個一正一負,符號並不統一,而前面的幾次旋轉,無論左還是右旋,最小不平衡子樹的根結點與它的子結點符號都是相同的。這就是不能直接旋轉的關鍵。 不統一,不統一就把它們先轉到符號統一再說,於是先對結點9和結點10進行右旋,使得結點10成了9的右子樹,結點9的BF爲-1,此時就與結點7的BF值符號統一了,如圖12所示。
這樣再以結點7爲最小不平衡子樹進行左旋,得到如下圖13。接着,插入8,情況與剛纔類似,結點6的BF是-2,而它的右孩子9的BF是1,如圖14,因此首先以9爲根結點,進行右旋,得到圖15,此時結點6和結點7的符號都是負,再以6爲根結點左旋,最終得到最後的平衡二叉樹,如圖16所示。
通過這個例子,可以發現,當最小不平衡樹根結點的平衡因子BF是大於1時,就右旋,小於-1時就左旋,如上例中的結點1、5、6、7的插入等。插入結點後,最小不平衡子樹的BF與它的子樹的BF符號相反時,就需要對結點先進行一次旋轉以使得符號相同後,再反向旋轉一次才能夠完成平衡操作,如上例中結點9、8的插入時。
下面兩個圖講解了插入時所要做的旋轉操作的例子。《來自:http://www.cnblogs.com/guyan/archive/2012/09/03/2668399.html》
2、平衡二叉樹算法的實現
首先是需要改進二叉排序樹的結點結構,增加一個bf,用來存儲平衡因子。
1 2 3 4 5 6 |
|
然後對於右旋(順時針)操作,代碼如下:
1 2 3 4 5 6 7 8 |
|
此函數代碼的意思是說,當傳入一個二叉排序樹t,將它的左孩子結點定義爲s,將s的右子樹變成t的左子樹,再將t改爲s的右子樹,最後將s替換爲t的根結點。這樣就完成了一次右旋操作。如下圖示,圖中三角形代表子樹,N代表新增的結點。
上面的例子中新增加了結點N,就是右旋操作。
左旋代碼如下所示。
1 2 3 4 5 6 7 8 |
|
下面看左旋轉平衡(使左邊平衡)的處理代碼。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
首先,定義三個常數變量,分別代碼1、0、-1。
(1)函數被調用,傳入一個需調整平衡型的子樹T。由於LeftBalance函數被調用時,其實是已經確認當前子樹是不平衡的狀態,且左子樹的高度大於右子樹的高度。換句話說,此時T的根結點應該是平衡因子BF的值大於1的數。
(2)將T的左孩子賦值給L。
(3)然後是分支判斷。
(4)當L的平衡因子爲LH,即爲1時,表明它與根結點的BF值符號相同,因此,將它們的BF值都改爲0,並進行右旋(順時針)操作,操作方式如圖所示。
(5)當L的平衡因子爲RH時,即爲-1時,表明它與根結點的BF值符號相反,此時需要做雙旋操作。針對L的右孩子的BF作判斷,修改結點T和L的BF值。將當前的Lr的BF改爲0。
(6)對根結點的左子樹進行左旋,如下圖第二圖所示。
(7)對根結點進行右旋,如下圖第三圖所示,完成平衡操作。
右平衡(使右邊平衡)旋轉處理的函數代碼如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
插入數據操作如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
說明:
(1)程序開始執行時,如果T爲空時,則申請內存新增一個結點。
(2)如果表示當存在相同結點,則不需要插入。
(3)當新結點e小於T的根結點時,則在T的左子樹查找。
(4)遞歸調用本函數,直到找到則返回FALSE,否則說明插入結點成功,執行下面語句。
(5)當taller爲TRUE時,說明插入結點,此時需要判斷T的平衡因子,如果是1,說明左子樹高於右子樹,需要調用LeftBalance函數進行左平衡旋轉處理。如果爲0或-1,則說明新插入的結點沒有讓整棵二叉排序樹失去平衡性,只需修改相關BF值即可。
(6)說明結點e大於T的根結點的值,在T的右子樹查找。與上面類似。
刪除結點的代碼如下所示。
3、C語言實現
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
|