一步一步写二叉查找树
?一步一步寫二叉查找樹
作者:C小加 ?更新時(shí)間:2012-8-9
二叉查找樹(BST)是二叉樹的一個(gè)重要的應(yīng)用,它在二叉樹的基礎(chǔ)上加上了這樣的一個(gè)性質(zhì):對(duì)于樹中的每一個(gè)節(jié)點(diǎn)來說,如果有左兒子的話,它的左兒子的值一定小于它本身的值,如果有右兒子的話,它的右兒子的值一定大于它本身的值。
二叉查找樹的操作一般有插入、刪除和查找,這幾個(gè)操作的平均時(shí)間復(fù)雜度都為O(logn),插入和查找操作很簡單,刪除操作會(huì)復(fù)雜一點(diǎn),除此之外,因?yàn)槎鏄涞闹行虮闅v是一個(gè)有序序列,我就額外加上了一個(gè)中序遍歷操作。
二叉查找樹的應(yīng)用不是很多,因?yàn)樗顗牡臅r(shí)候跟線性表差不多,大部分會(huì)應(yīng)用到它的升級(jí)版,平衡二叉樹和紅黑樹,這兩棵樹都能把時(shí)間復(fù)雜度穩(wěn)定在O(logn)左右。雖然不會(huì)用到,但是二叉查找樹是一定要學(xué)好的,畢竟它是平衡二叉樹和紅黑樹的基礎(chǔ)。
接下來一步一步寫一個(gè)二叉查找樹模板。
第一步:節(jié)點(diǎn)信息
二叉查找樹的節(jié)點(diǎn)和二叉樹的節(jié)點(diǎn)大部分是一樣的,不同的是,二叉查找樹多了一個(gè)值出現(xiàn)的次數(shù)。如圖1顯示了二叉查找樹的節(jié)點(diǎn)信息。
代碼如下:
第二步:二叉查找樹類的聲明
代碼如下:
?
第三步:插入
根據(jù)二叉查找樹的性質(zhì),插入一個(gè)節(jié)點(diǎn)的時(shí)候,如果根節(jié)點(diǎn)為空,就此節(jié)點(diǎn)作為根節(jié)點(diǎn),如果根節(jié)點(diǎn)不為空,就要先和根節(jié)點(diǎn)比較,如果比根節(jié)點(diǎn)的值小,就插入到根節(jié)點(diǎn)的左子樹中,如果比根節(jié)點(diǎn)的值大就插入到根節(jié)點(diǎn)的右子樹中,如此遞歸下去,找到插入的位置。重復(fù)節(jié)點(diǎn)的插入用值域中的freq標(biāo)記。如圖2是一個(gè)插入的過程。
二叉查找樹的時(shí)間復(fù)雜度要看這棵樹的形態(tài),如果比較接近一一棵完全二叉樹,那么時(shí)間復(fù)雜度在O(logn)左右,如果遇到如圖3這樣的二叉樹的話,那么時(shí)間復(fù)雜度就會(huì)恢復(fù)到線性的O(n)了。
平衡二叉樹會(huì)很好的解決如圖3這種情況。
插入函數(shù)的代碼如下:
?
?
第四步:查找
查找的功能和插入差不多一樣,按照插入那樣的方式遞歸下去,如果找到了,就返回這個(gè)節(jié)點(diǎn)的地址,如果沒有找到,就返回NULL。
代碼如下:
?
?
第五步:刪除
刪除會(huì)麻煩一點(diǎn),如果是葉子節(jié)點(diǎn)的話,直接刪除就可以了。如果只有一個(gè)孩子的話,就讓它的父親指向它的兒子,然后刪除這個(gè)節(jié)點(diǎn)。圖4顯示了一棵初始樹和4節(jié)點(diǎn)被刪除后的結(jié)果。先用一個(gè)臨時(shí)指針指向4節(jié)點(diǎn),再讓4節(jié)點(diǎn)的地址指向它的孩子,這個(gè)時(shí)候2節(jié)點(diǎn)的右兒子就變成了3節(jié)點(diǎn),最后刪除臨時(shí)節(jié)點(diǎn)指向的空間,也就是4節(jié)點(diǎn)。
刪除有兩個(gè)兒子的節(jié)點(diǎn)會(huì)比較復(fù)雜一些。一般的刪除策略是用其右子樹最小的數(shù)據(jù)代替該節(jié)點(diǎn)的數(shù)據(jù)并遞歸的刪除掉右子樹中最小數(shù)據(jù)的節(jié)點(diǎn)。因?yàn)橛易訕渲袛?shù)據(jù)最小的節(jié)點(diǎn)肯定沒有左兒子,所以刪除的時(shí)候容易一些。圖5顯示了一棵初始樹和2節(jié)點(diǎn)被刪除后的結(jié)果。首先在2節(jié)點(diǎn)的右子樹中找到最小的節(jié)點(diǎn)3,然后把3的數(shù)據(jù)賦值給2節(jié)點(diǎn),這個(gè)時(shí)候2節(jié)點(diǎn)的數(shù)據(jù)變?yōu)?/span>3,然后的工作就是刪除右子樹中的3節(jié)點(diǎn)了,采用遞歸刪除。
我們發(fā)現(xiàn)對(duì)2節(jié)點(diǎn)右子樹的查找進(jìn)行了兩遍,第一遍找到最小節(jié)點(diǎn)并賦值,第二遍刪除這個(gè)最小的節(jié)點(diǎn),這樣的效率并不是很高。你能不能寫出只查找一次就可以實(shí)現(xiàn)賦值和刪除兩個(gè)功能的函數(shù)呢?
如果刪除的次數(shù)不是很多的話,有一種刪除的方法會(huì)比較快一點(diǎn),名字叫懶惰刪除法:當(dāng)一個(gè)元素要被刪除時(shí),它仍留在樹中,只是多了一個(gè)刪除的標(biāo)記。這種方法的優(yōu)點(diǎn)是刪除那一步的時(shí)間開銷就可以避免了,如果重新插入刪除的節(jié)點(diǎn)的話,插入時(shí)也避免了分配空間的時(shí)間開銷。缺點(diǎn)是樹的深度會(huì)增加,查找的時(shí)間復(fù)雜度會(huì)增加,插入的時(shí)間可能會(huì)增加。
刪除函數(shù)代碼如下:
?
?
第六步:中序遍歷
遍歷的方法和二叉樹的方法一樣,寫這個(gè)方法的目的呢,是輸出這個(gè)二叉查找樹的有序序列。
代碼如下:
?
?
到此,整個(gè)代碼就完成了,代碼中肯定有很多不完善的地方請(qǐng)指出,我會(huì)加以完善,謝謝。
?
對(duì)于二叉查找樹不穩(wěn)定的時(shí)間復(fù)雜度的解決方案有不少,平衡二叉樹、伸展樹和紅黑樹都可以解決這個(gè)問題,但效果是不一樣的。
轉(zhuǎn)載于:https://blog.51cto.com/lwxcy/959522
總結(jié)
以上是生活随笔為你收集整理的一步一步写二叉查找树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux下Makefile的简单例子及
- 下一篇: 2012年08月13日