查找树(二级)
樹的查找,大家仔細看這個名詞,看這個單詞,叫查找樹,查找樹怎么理解,誰是動詞誰是名詞,主語是誰,那就是我要去查找這棵樹,查找是動詞,樹是賓語,你又可以理解這是個名詞,樹的名字叫查找樹,樹是主語,不是二叉樹,不是三叉樹,是查找樹,是這樣的,有一種概念叫二叉查找樹,他也叫二叉搜索樹,查找搜索吧,那不是一個含義嗎,但是他還叫二叉排序樹,那查找和排序是兩個截然不同的內容,這個樹怎么可能既是排序樹又是查找樹呢,兩個原因,一個原因,查找是search,排序是sort,首字母都是S,所以叫BST(binargy search tree),但是這個肯定不是最主要的原因,我們找一個以S開始的單詞,多的去了,不能隨便叫,最主要這棵樹既可以用來查找,并且他本身也是有序的,當往里面添加元素的話,它會自動變成有序的,按照某種規則來排列的,我們這幾個樹都是二叉查找樹,或者叫二叉排序樹,大家看一下他們有什么特點,我來跟大家說一下,看這一個,首先它是一棵二叉樹,這個是不是根,然后左邊所有的節點,都小于8,發現沒,右邊所有的元素都大于8,這是根,還是遞歸的定義,這又是一個根,左子樹小于根,右子樹大于根,里面這個樹根是4,左是4,右是7,是不是還是滿足,然后10是根,左邊沒有,右邊是他,那根是14,這是13,左小于根,如果我們這個時候來了一個數,它是15,你覺得他應該加在哪兒,我們是不是可以加到這個位置,加個15,這就叫二叉查找樹,其他的也是的,7都小于7,都大于7,遞歸定義,3大于3,小于3,遞歸定義的,一直到葉子節點,這紅色是不是也是二叉查找樹,為什么啊,根,右邊全部大于A,根,右邊全部大于B,實際上他也是一個二叉查找樹,或者是一顆空樹,或者具有以下的性質1. 如果他的左子樹不為空,左子樹的所有節點都小于根2. 如果他的右子樹所有的節點不為空,節點也都大于根節點,3. 他的左右節點也是二叉排序樹,是這么來的這是我們所說的一個內容
注意;大家想一下,滿足這個條件就怎么了,滿足這個條件想一下,如果我們對于二叉樹進行中序遍歷,什么叫中序遍歷,先遍歷左邊的,先遍歷小的,再遍歷根,再遍歷右邊的,因為我們剛才是二叉樹的特點,我們對他中序遍歷,先左,再根,后右,那一部分都是先左再根后右,二叉排序樹得到的中序遍歷得到的結果就是一個有序的數列,這是一個,他為什么叫做二叉排序樹,對他進行中序遍歷他就是有序的,他為什么叫二叉查找樹,當然了,大家想一下,我要在這里找一個樹16,我要怎么找,肯定是要從根開始吧,6小于8,右邊就全部排除了,就不可能在這兒了,6再和3比,左邊是不是又全部排除了,這個和二分法折半折半查找是不是差不多啊,一下子就可以拋棄一半了,這是我們所說的一個內容,最終和6比,找到了,我們要找一個5怎么找,先和8比,小于8,再和3比,再和6比,5是不是小于6啊,再和4比,大于4,再和右邊找,右邊有沒有,沒有,這說明什么,這說明不存在,所以查找的話,這棵樹是怎么構建的,大家想一下,我們最早講二叉樹的時候,我們是怎么來構建這棵樹的,看下我的代碼,我們的二叉樹是不是一個一個節點連接起來的,為什么,因為之前的二叉樹沒有規律,現在不用了,因為他已經有規律了,有規律了怎么辦,我們以這棵樹為例,我現在有一個值是9,因為這棵樹已經構建好了,我現在有個9,你給我加到這棵樹里面,你只要把這棵樹的根,同時這個8值給了,就可以把這個9加到指定的位置,為什么,因為他是有特點的嗎,因為他是有規律的,9和8比那應該是往右邊放,他和10比應該往左邊放,左邊是空白的,那好,就是你了,9是不是加到這兒了,這個二叉查找樹就涉及到了如何添加,可以通過算法來添加的,如何查找,查找是不是相當于折半查找啊,還有一個如何排序,中序遍歷他就是有序的,還有一個如何更新,如何修改,我們先做一個如何刪除,如何刪除呢,這個刪除和更新就稍微復雜一點,一堆完整的算法,叫我們來實現這一個,比如我們要把這個10刪除了,刪除完之后還得要保證它是一棵二叉查找樹,那我們怎么辦,你要是把10刪除了,那8指向14不就行了,你8指向14,9怎么辦啊,9加到這兒嗎,這事怎么辦,我把9移除了,9放到10這個位置,9放到這兒,8連9,9再連14,他還是滿足這個規律,但是他一共有多種情況,都是有完整的算法的,那更新的時候呢,我要把6更新成15,哪能隨便更新,你更新還叫二叉查找樹嗎,就不是了,對于二叉查找樹來說,他有一套完整的實現算法,以及代碼實現,這個問題該怎么解決,這個完整問題解決思路,這是我們講的二叉查找樹和二叉排序樹,二叉查找樹的好處我已經跟大家說了,但是他有沒有缺點,有,怎么又缺點,比如說,我現在給了大家幾個數,1,2,3,4,5,總共5個數,但是這個數我以不同的順序來給,3,2,5,4,1,是不同的順序,我們按照不同的順序來構建一個二叉查找樹,先來一個3來做根了,它是第一個,那2怎么辦,2應該放到這兒,5怎么辦,5應該放到這兒,再來一個4,4大于3小于5,再來個1,1是不是應該到這兒了,那這兒我如果再跟一個6呢,3,5,6,總體來看這棵樹比較平均的,左右是不是比較平衡的,左邊的節點和右邊的節點是不是差不多的,但是如果你是這么來給呢,1,2,3,4,5,6,按照這個順序來給,那就變成什么樣子了,先來個1,再來個2,再來個3,再來個4,再來個5,再來個6,這哪還是二叉樹啊,這純粹就是一個線性表,你覺得是這種方式好,還是這種方式好,哪種方式好啊,當然是這種方式好啊,比如說,我要查找6的話,每層數量就加倍,這個你相當于要找幾次,相當于你在這種極端的情況下,你要找一個數的話,時間復雜度是O(n),因為你一定是一個線性表的,花的時間是很多的,但是在這個里面呢,這個就相當于log2 n,因為每次增倍,越往下就比上一層增加2,如果滿的話,所以這個效率是可以大大提升的,雖然都是二叉查找樹,都是左邊小于根,根小于右子樹,但是如果排列規則不一樣的話,這是一種極端的,完全平衡的,這是一種完全不平衡的,我們希望得到哪一種啊,我希望得到這一種,為什么,這一種對什么有好處,對查找有好處,你添加的時候也好添加,這是一個
那我們在下邊再講一個名詞,這個詞叫平衡二叉樹,平衡的什么叫平衡二叉樹?他首先是一個二叉查找樹,這什么意思啊,左邊小于根,根小于右邊,并且他還是平衡的,一般我們叫平衡,別人是自平衡的,是這么來的,叫AVL樹,所以稱之為AVL算法,按照這個算法的叫AVL樹,他怎么了,這就是一顆平衡二叉樹,他為什么是一顆平衡二叉樹啊,為什么他是平衡的,這是一個根,右邊分幾層,右邊兩層吧,左邊幾層,左邊3層,做多相差不能差一層,然后你還是遞歸的,這是一個根吧,左邊幾層,左邊兩層,這是幾層,1層,7又是根,左邊幾層,1層,右邊幾層啊,1層,左邊右邊,左子樹右子樹他們的高度之差最多差一層,那基本上就相同了,最后一層有可能是不滿的,可能是不滿的,這就是循環二叉樹,那這個平衡二叉樹怎么辦呢,他就可以保證每層的節點盡可能的多一些,這樣來說是比較平衡的,是比較平均的,不會一會特別多,一會特別少,最大的好處是什么啊,就是為了減少二叉查找樹的層次,平衡不就是每層節點多,層數就少了嗎,他就不是可以避免出現這種情況的嗎,這是我們所說的一個內容,從而來提高查找速度,你告訴我上面的是不是二叉平衡樹,這個是不是,你仔細看哦,這是幾層,3層,這是3層,這是幾層,1層,右邊2層,根兩層,2層,這個是不是,根幾層,3層,右子樹3層,這沒有問題,10左邊0層,右邊2層,不是二叉平衡樹,怎么就是了,比如他把10寫成13,本來是10,把10放到這兒,如果這么一移的話,知道我們所說的一個意思,那你要這么來說的話,這個肯定不是平衡的,那是絕對不平衡的,那我們下邊再來做一個操作吧,[1,2,3,4,5,6],我就按照這個順序給你,如果底層是一棵平衡樹的話,這個該怎么來構建,第一個作為根,這是平衡的吧,就一個節點,他左邊是0,右邊也是0,再加上一個2,平衡嗎,為什么平衡,左邊是0,右邊是1高度,是平衡的,再加一個3,再加就不平衡了,算法可以保證,它會自平衡,怎么就自平衡了,根不是1嗎,我想拿2做根,怎么拿2做根啊,2的左孩子不是沒有嗎,讓2的左孩子變成1,把2的左孩子指向1,這部分就不存在了,然后這再加上一個3,然后他就又平衡了,那我們再加4呢,我們再這再加一個4,這樹還是平衡的,但是如果你要是再加一個5的話,又不平衡了,怎么辦,大家如果感興趣可以查詢更多的資料來看一下,它是有一套完整解決方案的,它會一直維持樹的平衡,保證左右是平衡的,可以保證以后查詢的效率,這是我們所說的,二叉平衡樹有什么好處,提高查詢的速度,減少查詢次數,是這么來的,二叉查找樹的特點在于什么,它是有規律的,這么一來呢,我們不便于添加,便于排序,是這么來的,而對于平衡二叉樹來說,便于查找再往下看,下一種樹叫紅黑樹,紅黑樹什么意思啊,首先記住它也是一種平衡二叉樹,有人說他也是一種平衡二叉樹,我們前面不是也有平衡二叉樹嗎,對啊,平衡二叉樹你要是想實現這個,特點是固定的,左右平衡,但是實際上方案可以有很多種,實現方案保證他左右平衡的,我們一般說的平衡二叉樹呢,叫AVL算法,是這種算法來保證平衡的,但是后來又出現了一種算法,后來又出現一種算法叫紅黑算法唄,他也可以保證這棵樹也是平衡的,那這就是一顆最簡單的紅黑樹的模型圖,首先我們看到他是平衡的,他把他的節點分別標記紅色和黑色,并且紅色和黑色基本上都有交替出現1. 比如每個節點不是黑色就是紅色2. 根節點第一個是黑色的3. 每個葉子節點他保證是黑色的,但是你要知道他的葉子節點不是10,也不是50,而是他的空的左子樹和空的右子樹,4. 這里面是這么來標記他的葉子節點的,總之它是通過一系列的規則來保證他最終的紅黑樹呢它是平衡的
紅黑樹的使用還是很廣泛的,像我們JAVA里面的TreeSet,TreeMap底層采用的都是紅黑樹,底層采用的都是紅黑樹,這個大家要明白,意味著我們JAVA里面的TreeSet是紅黑樹,這說明什么,大家想一下,第一個我們講TreeSet,第一個它是有序的,是不是說過它是有序的,他怎么成有序的了,你說TreeSet底層是紅黑樹就是有序的嗎,對啊紅黑樹首先是一個查找樹,對任何樹進行中序遍歷得到的就是有序了,他就是這么來實現的,另外他既然是紅黑樹,不管我們按照什么順序加這個數據,最終它會出現這個極端的情況嗎,不會,所以我們紅黑樹的查找效率,也是比較高的,多少啊,就是log2 n,就是我們說的一個平衡樹,一種是最早的AVL樹,還有一個叫紅黑樹,記住它是左右平衡的,TreeSet使用的就是紅黑樹我們再講一個B樹,B樹叫什么意思,Balanced Tree,B就是這個單詞唄Balanced,balanced什么意思,就是平衡,這個叫平衡樹,上面這個叫平衡二叉樹,這有什么區別嗎,有,這個是不是左右平衡了,但是他最多分兩個叉,那我最多讓他分三個叉或四個叉呢,這樣行不行呢,每個節點可以分更多的叉,你還是每個節點都平衡的,可以嗎,可以的,這就叫平衡樹,大家來看,這就叫一個平衡樹,他最多分了3個叉,他不是兩個叉,是分了3個叉,那么同一層就可以存更多的數據了,同樣的數據就可以有更少的層次了,他就可以有更少的層次了,這個也是有的,B樹他就叫平衡樹,它是多叉的,多叉的他就可以降低樹的深度,從而減少查詢的次數,提高查詢的效率,這個一般是用在什么地方的,這個一般是用來讀硬盤上數據的時候,比如讀我們數據庫里面的數據,索引的時候就可以用這個來做,比如硬盤里面的數據特別多,我們不能一次性的讀到內存里面,內存里面放不下,該怎么辦,就可以按照這種方式來,讀出一部分來,這是兩個節點的資料,讀了這兩個之后呢,比如我要讀的是9,我要找9這個數,所有的數據不可能全部都讀到內存里面,因為比較大,那我就采用這種平衡樹來存儲,那我就先讀這一層,或者先把這兩層讀出來,容量是比較少的,我找的是9,你不需要把所有的數據都讀出來再找9,那效率會比較低,我先把這兩個讀出來,9它是有序的,你看他還是保證左邊小于中間,中間小于右邊,還是滿足我們剛才的規律的,你看這是17,這是什么意思,這有兩個數,下邊有3個指針,我很奇怪,為什么兩個數下面有3個指針啊,因為這個指針指向的是小于17的,那這個指針指向的是大于35的,那中間這個指針指向的是17到35之間的,兩個數正好把整個樹分成3個區塊,同樣2個節點3個指針,這邊是小于8的,這邊是大于12的,當然大于12是有要求的,那這個指針指向的是8到12中間的,那大家想一下,我想在這里面找9,該怎么找,先和17比,小于17,那意味著什么啊,這一塊,這一塊一下子排除了,因為他是平衡的,所以他不是排除了二分之一,他排除了三分之二,這邊再來,拿著這個9和8進行比較,結果發現他大于8,大于8把8指向的排除了,然后再和12比,那不用說了,那就是在這兒,9找到了,就這么來就可以了,這是我們所說的B樹,他和我們的二叉平衡樹的區別,B樹首先是平衡的,他只不過是分了更多的叉,然后呢我們再看另外一個
B+樹:B+樹什么意思,B+樹是這么來的,我們看上面的樹,如果我想找17呢,如果我想找12呢,17是不是一下子就找到了,找12呢,是不是也能找到找13是不是在這兒呢,就是我們找的數據啊,他可能在第一層,也可能在第二層,是不是也可能在第三層,各層都是有數據的,各層都有數據那B+樹他做了一下變化,他是怎么變的呢,他變成什么樣子了,B+樹的一個變化,他變成這個樣子了,什么樣子啊,我們畫一條線,所有的數據都在最下面一層,你看5,28,65,是不是也有啊,就是真正的數據全部都在下一層,我們之前是每一層都存數據的,現在不是了,現在是所有的數據都放在這,都放在最下面這一層,我上面只是索引,上面的是索引,這是完整的索引數據,這個時候怎么辦呢,5,28,65,都對應指針的,5如果往左邊走,那就是包括5的,因為這個5只是索引的數據,不是真正的數據,真正的數據在這兒,有幾個數就有幾個指針,一一對應的,我們找一個數,我們找一個5,怎么找,5找到了沒有,5,沒找到,哪兒找到了,真正的數據在這兒呢,按照P1這個指針,往下來走,還是5啊,再往下走,這個指針找到這兒,真正的數據它是在這兒,他在這兒已經找到5了,那他這個怎么辦,就在這兒不行吧,如果整個5代表一個學生的話,5要是代表一個學生的話,這個地方存的也許是一個完整的學生,而這兒存的可能是一個學生的分數,或者學號啊,或者是年紀啊,這些排序的字段,是這么來的,這么就找到了,我們就再來找一個唄,再來找一個40吧,告訴我40該怎么找,從上面的一級索引,2級索引,數據是不是在這兒呢,我要找的是40,怎么辦,如果要是沒有我們這個索引的話,怎么找啊,是不是要逐個的查找啊,這個效率太低了吧,但是有了這個索引之后,最多也沒有幾次,為什么最多也沒有幾次,找40,先和5比,大于5,和28比,大于28,和65比,小于65,那就按照P2來找就可以了,一下子把左邊的排除了,一下子把右邊的也排除了,再來找40,和28比,大于28,那就不用考慮了,和35比,這下面都是大于35的,但是小于56了,那再和56比,小于56,這里顯示的是35到56之間的,和35比,不是,和38比,不是,和50比,不是,都已經大于40了,不用找了,干什么啊,不存在,所以他上面這幾級啦,是可以快速給你分到分支的,可以排除大量數據,一下子跳過大量的數據,提高效率,那到最后一塊就變成線性查找,一個一個找,但是數據是比較少的,這就是我們所說的B+樹,那么大家記住了,我們后面馬上就要學數據庫,數據庫的索引就是采用的B+樹,數據庫的索引就是采用的B+樹,可以分多個叉,但是你發現這個叉級別都是一樣層次都是一樣的,最后我們再來看一個樹B*樹:B*樹兩個再對比一下唄,你覺得這兩個有什么區別,有區別嗎,有什么區別嗎,B*樹的索引之間又相連了,這里面有沒有啊,它是沒有的,它是B+樹的變體,在B+樹的非根和非葉子節點,除了第一層和最后一層,中間各層之間,兄弟之間,是可以有指針的,這就是我們給大家講的相關的查找樹的相關觀念總結一下,我們一共講了幾個概念:第一個叫二叉查找樹,他有什么特點,左邊小于根,根小于右邊,他有什么好處,便于查找,便于排序,為什么還要出一個二叉平衡樹,一看這個就明白了,這是一個二叉查找樹,但是左右不平衡,結果都變成了線性表了,查找特別低效,所以我們希望他左右平衡,那我們要實現這個平衡二叉樹,或者二叉平衡樹,實現的方式有很多,比如AVL樹,或者還有一種采用紅黑算法實現的紅黑樹,這三種都是二叉樹,再往下就是B樹,B+樹,B*樹,B樹什么意思啊,B樹就是分了多個叉,B+樹呢,數據全部在最底層,B*樹是索引之間也可以有關聯
?
總結
- 上一篇: 顺序表查找+折半查找(二级)
- 下一篇: 哈希表(三级)