數據結構與算法-二叉查找樹

瞭解二叉樹的定義以及二叉樹遍歷以後,咱們繼續探討二叉樹的使用。二叉樹是一種數據結構,是用來處理數據的。數據處理最簡單的需求是查找、添加、刪除,有一種二叉查找樹能夠知足以上需求。
二叉查找樹也能夠稱之爲有序二叉樹。二叉查找樹具備以下特性:
對於樹中的每一個節點n,其左子樹中的值都小於節點n中的值,其右子樹中的值都大於節點n中的值。
就像這樣:
  • 查找
二叉查找樹中查找某個元素的算法至關直觀。對於每一個節點,算法將要定位的值與當前所指節點中存儲的值進行比較,若是該值小於存儲值則轉向左子樹;若是該值大於存儲值,則轉向右子樹。若是二者相同,很明顯查找過程結束了。若是沒有其餘能夠查找的節點,查找過程也終止,這表示該值不在樹中。舉個例子,在上圖中查找22。從根節點開始,首先22大於根節點15,轉向右子樹,發現23大於查找節點22,隨後轉向左子樹,發現22等於查找節點22,查找完畢。
動態圖以下:
  • 添加
要插入鍵值爲el的新節點,必須找到樹中的一個終端節點,並將新節點與該節點鏈接。要找到這樣一個終端節點,可使用與查找樹相同的技術:在掃描樹的過程當中,比較鍵值el與當前檢查的節點的鍵值。若是el小於該鍵值,就測試當前節點的左子樹,不然,就測試當前節點的右子樹。若是要測試的p的子節點爲空,就中止掃描,新節點將成爲p的子節點。舉個例子,在上圖中插入24。從根節點開始,首先24大於根節點15,轉向右子樹,發現23小於插入節點24,轉向右子樹,發現26大於插入節點24,轉向左子樹,發現爲空,將24添加爲26節點的左子樹,插入完畢。
動態圖以下:
  • 刪除
另外一個維護二叉查找樹所必不可少的操做是刪除節點。執行該操做的複雜度取決於要刪除的節點在樹中的位置。刪除有兩個子樹的節點比刪除葉子節點困可貴多,刪除算法的複雜度與被刪除節點的子節點數目成正比。從二叉查找樹中刪除節點有三種狀況:
一、刪除葉節點
刪除葉節點比較簡單,由於葉節點沒有子樹,只要將父節點的相應指針設置爲空便可。
動態圖以下:
二、刪除度爲1的節點
刪除度爲1的節點也不復雜,只要將父節點中指向該節點的指針從新設置爲指向被刪除節點的子節點。這樣,被刪除節點的子節點提高一個層次,其後的全部後裔節點根據家族關係依次提高一個層次。
動態圖以下:
三、刪除度2節點
要刪除的節點有兩個子節點。在這種狀況下,沒法一步完成刪除操做,由於父節點的右指針或者左指針不能同時指向被刪除節點的兩個子節點。下面討論這一問題的兩種不一樣解決方案。
  • 合併刪除
該解決方案從被刪除節點的兩顆子樹中獲得一棵樹,而後將這顆樹鏈接到被刪除節點的父節點處。這種技術稱爲合併刪除。但如何合併這些子樹呢?根據二叉查找樹的本質,右子樹的每一個值都比左子樹的值大,因此最好的方法是找到左子樹中具備最大值的節點,使它成爲右子樹的父節點。一樣,還能夠在右子樹中找到具備最小值的節點,使之成爲左子樹的父節點。
動態圖以下:
上圖演示的是將右子樹合併到左子樹中成爲一顆新的子樹,而後將被刪除節點的父節點從新指向子樹。固然也能夠將左子樹合併到右子樹,動態圖以下:
刪除有兩個子樹的節點比較麻煩,緣由在於兩個子樹怎麼處理?上面介紹的合併刪除是一種解決方案,就是說將兩顆子樹合併成一顆新樹,該樹依然知足二叉查找樹定義,而後將新樹提高到刪除節點的位置。合併刪除關鍵邏輯是如何合併子樹,若是咱們決定將右子樹掛在左子樹上,那麼掛在哪一個節點比較合適呢?咱們假設刪除節點爲p,p的左子樹爲m,右子樹爲n。那麼,n中全部節點大於p,p大於m中全部節點。咱們再假設m的根節點爲m1,n的根節點爲n1,那麼n1比m中全部節點都大。也就是說,若是將n掛在m下,那麼從m1到n1的路徑中不能出現左指針,由於一旦出現左指針,就表明着n1成了一個 比它還小的節點的左子樹,這就破壞了二叉查找樹。所以,只要m1到n1的路徑中沒有左指針便可,最方便的作法就是使n1成爲m樹中最大節點的右子樹。這正是上面動圖中展現的內容。將左子樹合併到右子樹也是同理。看到這裏,也許讀者會產生一個疑問。假設m樹中最大節點爲m2,從m1到m2的路徑中存在節點m3,那麼使n1成爲m3的右子樹能夠嗎?這固然是能夠的,可是若是這樣作,就須要處理m3原有的右子樹了。方法就是將m3原有右子樹掛在n樹上,要求是從n1到m3原有右子樹根節點的路徑中不能存在右指針,原理和上面相似。你會發現這樣太麻煩了,應該直接將n樹掛在m2下的,這樣m2原來就沒有右子樹,因此就省去了後面的步驟。
合併刪除是一種優秀的刪除解決方案,可是它有一個缺陷,由於使用合併刪除以後,會使二叉查找樹的高度變大,通過屢次的合併刪除後,二叉查找樹會退化爲鏈表,這固然是不能容忍的。
爲了規避合併刪除的缺陷,還有一種叫作複製刪除的解決方案。
  • 複製刪除
複製刪除設計的很是巧妙。對於刪除,咱們直觀的邏輯是刪除某個節點,而後將該節點的子節點經過某種調整,而後提高到被刪除節點的位置。複製刪除不是這種邏輯,複製刪除主張在被刪除節點的兩顆子樹中,找到某個節點來替換被刪除節點,這樣就規避了提高子樹的邏輯,而且不會破壞二叉查找樹的高度。如今問題來了,被刪除節點的兩顆子樹中,哪些節點能夠用來替換被刪除節點呢?答案就是被刪除節點的直接前驅或者直接後繼,直接前驅是其左子樹中最右側的節點(與此相似,其直接後繼是右子樹中最左側的節點)。你會發現,直接前驅是左子樹中最大的值,直接後繼是右子樹中最小的值,只有這兩個節點能夠替換被刪除節點。你也許會問,爲何左右子樹中其餘節點不能夠呢?由於若是找了其餘節點p來替換被刪除節點,那麼就沒法保證p大於左子樹中全部節點,或者p小於右子樹中全部節點,這就破壞了二叉查找樹。所以,咱們能夠選擇被刪除節點的直接前驅或者直接後繼來替換該節點,而咱們知道,直接前驅或者直接後繼要麼是葉子節點,要麼是隻有一個子樹。那麼問題就變得簡單了。使用直接前驅或者直接後繼替換被刪除節點以後,咱們再把直接前驅或者直接後繼刪除掉,刪除它們的邏輯比較簡單,就是刪除葉子節點或者刪除度1節點,這在上面已經介紹過了。
動態圖以下:
二叉查找樹的查找、添加、刪除邏輯到目前爲止已經探討完畢,更加深刻的內容須要實踐中摸索。下一節一塊兒學習二叉樹的平衡。

數據結構與算法-二叉查找樹平衡(DSW)
算法

相關文章
相關標籤/搜索