摘要:在二叉查找樹上執(zhí)行基本操作的時間與樹的高度成正比。不同的二叉查找樹可以表示同一組值。紅黑樹樹二叉查找樹,紅黑樹,樹紅黑樹
雖是讀書筆記,但是如轉(zhuǎn)載請注明出處 http://segmentfault.com/blog/exploring/
.. 拒絕伸手復(fù)制黨
關(guān)于二叉樹的基本知識,可以參見:Java 實現(xiàn)基本數(shù)據(jù)結(jié)構(gòu) 2(樹)
以下是算法導(dǎo)論第十二章的學(xué)習(xí)筆記
二叉查找樹 BST查找樹是一種數(shù)據(jù)結(jié)構(gòu),支持動態(tài)集合操作。在二叉查找樹上執(zhí)行基本操作的時間與樹的高度成正比。對已n個節(jié)點的完全二叉樹,各種操作的最壞情況運行時間O(logn). 但是如果二叉查找樹退化成含n個節(jié)點的線性鏈,各種操作的最壞情況運行時間O(n)。 一顆隨機構(gòu)造的二叉查找樹的操作平均時間是O(logn).
對于任何節(jié)點x,其左子樹的關(guān)鍵字最大不超過key[x],其右子樹的關(guān)鍵字最小不小于key[x]. 因此可以使用中序遍歷算法,輸出有序的樹的所有關(guān)鍵字。
不同的二叉查找樹可以表示同一組值。
查找二叉查找樹的時間可以在O(h) = O(logn)的時間內(nèi)完成。
關(guān)于二叉樹的一些數(shù)學(xué)性質(zhì):
1. 在二叉樹的第i層上至多有2(i-1)個節(jié)點(i>=1)
2. 深度為k的二叉樹至多有2k-1個節(jié)點
3. 對于任何一棵二叉樹T,如果其葉子節(jié)點數(shù)為n0,度為2的節(jié)點數(shù)為n2,則n0=n2+1.
// 返回指向包含關(guān)鍵字k的節(jié)點的指針 public TreeNode search(TreeNode root, int k){ if(root==null){ return null; } if(root.val == k) return root; if(root.val > k){ return search(root.left,k); } else return search(root.right,k); } //非遞歸 - 返回指向包含關(guān)鍵字k的節(jié)點的指針 public TreeNode searchIterative(TreeNode root, int k){ while(root!=null){ if(root==null || root.val == k){ return root; } if(root.val>k) { root = root.left; } else root = root.right; } return root; } // 返回最小值節(jié)點 public TreeNode minimal(TreeNode root){ if(root ==null){ return null; } while(root.left!=null){ root = root.left; } return root; } // 返回最大值節(jié)點 public TreeNode maximal(TreeNode root){ if(root ==null){ return null; } while(root.right!=null){ root = root.right; } return root; }查找前驅(qū)和后繼:
所謂前驅(qū)和后繼是指,指定元素在所有元素順序排列模式下的前一個元素或后一個元素。
要獲取一個二叉搜索樹中指定結(jié)點的后繼的直觀的辦法是,找到所有比指定結(jié)點大的結(jié)點中最小的。根據(jù)二叉搜索樹的屬性,找比某結(jié)點大的元素,可以往兩個兩個方向走:
往右子樹方向走,結(jié)點右子樹的元素都不小于本身;
往父結(jié)點方向走,指定的結(jié)點有可能處于其它結(jié)點的左子樹中。
當(dāng)指定結(jié)點擁有右子樹時,那么其后繼必存在于其右子樹中。因往父結(jié)點方向找到的比指定結(jié)點大的元素大于指定結(jié)點右子樹的所有元素。如果指定結(jié)點沒有右孩子呢?那么沿著父結(jié)點的方向找到第一個節(jié)點的左子樹包含指定結(jié)點的結(jié)點,這個結(jié)點就是指定結(jié)點的后繼。
// 尋找前驅(qū)后繼 public TreeNode successor(TreeNode root){ if(root ==null || root.right == null){ return null; } // 如果該節(jié)點有右孩子,則輸出右孩子的最左 -- minimal if(root.right != null){ return minimal(root.right); } else{ TreeNode y = root.parent; while(y!=null && root == y.right){ root = y; y = y.parent; } return y; } }插入
插入:從根結(jié)點開始,沿樹下降。指針 x 跟蹤這條路徑,而 y 始終指向 x 的父結(jié)點。根據(jù) key[z] 與 key[x] 的比較結(jié)果,決定向左向右轉(zhuǎn)。直到 x 成為 NIL 為止。這個 NIL 所占位置及我們想插入 z 的地方,y 即為 z 的父結(jié)點。
// 插入 public TreeNode insert (TreeNode root, TreeNode x){ TreeNode p = root; TreeNode y = new TreeNode(); if(p==null){ root = x; return root; } while(p!=null) { if(p.val >= x.val){ y = p; p = p.left; } else{ y = p; p =p.right; } } // 樹本來沒有節(jié)點的時候 x.parent = y; if(x.val <= y.val){ y.left = x; } else{ y.right = x; } return root; }刪除:
一個規(guī)律:如果BST的某個節(jié)點有兩個子女,則其后繼沒有左子女,其前驅(qū)沒有右子女。
以指向 z 的指針為參數(shù),考慮三種情況。
youtu20分鐘短視頻講解
1. 若 z 沒有子女,則修改其父結(jié)點 p[z],是 NIL 為其子女;
2. 如果結(jié)點 z 只有一個子女,則可以通過在其子結(jié)點與父結(jié)點之間建立一條鏈來刪除 z;
3. 如果結(jié)點 z 有兩個子女,先刪除 z 的后繼 y(它沒有左子女),再用 y 的內(nèi)容來替代 z 的內(nèi)容。
以下是刪除操作的偽碼:
注意:偽碼中的 TRANSPLANT,只修改 v 與 u 的父親之間的關(guān)系,而不修改與 u 孩子的關(guān)系。
TREE-DELETE(T,z) if z.left == NIL TRANSPLANT(T,z,z.right) else if z.right == NIL TRANSPLANT(T,z,z.left) else y = TREE-MINIMUM(z.right) if y.p ≠ z TRANSPLANT(T,y,y.right) y.right = z.right y.right.p = y TRANSPLANT(T,z,y) y.left = z.left y.left.p = y TRANSPLANT(T,u,v) if u.p == NIL T.root = v else if u == u.p.left u.p.left = v else u.p.right = v if v ≠ NIL v.p = u.p
對于高度為h的二叉查找樹,動態(tài)集合操作 INSERT 和DELETE 的運行時間為 O(h)。
實際用途stackoverflow的解答
在搜索應(yīng)用中使用,尤其是數(shù)據(jù)頻繁插入和刪除等等更改操作。比如set和map。
雖然BST的操作用數(shù)組完全可以實現(xiàn),但是數(shù)組只適合那種write once, read many times的操作。
然而當(dāng)要進(jìn)行操作諸如 插入,刪除,交換的時候,BST的性能遠(yuǎn)遠(yuǎn)超過了數(shù)組。BST 是 node based 數(shù)據(jù)結(jié)構(gòu),
而數(shù)組是 contiguous chunk of memory, 即基于連續(xù)內(nèi)存的數(shù)據(jù)結(jié)構(gòu),插入,刪除,交換要BST更好。
舉個例子
BST和哈希表有何區(qū)別? 存儲手機上的通訊錄用哪個數(shù)據(jù)結(jié)構(gòu)好?
哈希表可以O(1)時間進(jìn)行搜索和插入。
BST 可以O(nlogn)時間進(jìn)行搜索和插入。 在這一點BST稍慢。
但是二者最大的區(qū)別是哈希表是一個無序的DS,while, BSTs 是有序的DS。
當(dāng)設(shè)計手機通訊錄這種對內(nèi)存要求很高的應(yīng)用時候,需要考慮存儲空間而且手機通訊錄需要元素有序。哈希表無序,需要額外的空間和時間去排序,而BST就不需要額外的空間去
排序,而且在n<5000條記錄的時候,BST的O(nlogn)足夠快。
所以應(yīng)該采用BST。
紅黑樹 樹 - (二叉查找樹,紅黑樹,B 樹)- 紅黑樹文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64283.html
摘要:需要執(zhí)行的操作依次是首先,將紅黑樹當(dāng)作一顆二叉查找樹,將該節(jié)點從二叉查找樹中刪除然后,通過旋轉(zhuǎn)和重新著色等一系列來修正該樹,使之重新成為一棵紅黑樹。 雖是讀書筆記,但是如轉(zhuǎn)載請注明出處 http://segmentfault.com/blog/exploring/ .. 拒絕伸手復(fù)制黨 關(guān)于二叉樹的基本知識,可以參見:Java 實現(xiàn)基本數(shù)據(jù)結(jié)構(gòu) 2(樹) 以下是算法導(dǎo)論第13章的學(xué)...
摘要:因此,根據(jù)題目給出的先序遍歷和中序遍歷,可以畫出二叉樹選參考數(shù)據(jù)結(jié)構(gòu)與算法描述實現(xiàn)二叉樹算法淺談數(shù)據(jù)結(jié)構(gòu)二叉樹慕課網(wǎng)實現(xiàn)二叉樹算法前端樹控件騰訊軟件開發(fā)面試題 內(nèi)容銜接上一章 數(shù)據(jù)結(jié)構(gòu)與算法:常見排序算法 內(nèi)容提要 什么是樹 - 為什么使用樹 二叉樹 二叉查找樹 紅黑樹 B、B+樹 堆 伸展樹 樹 可以點擊鏈接感受下筆者用d3.js畫的tree https://codepen...
摘要:寫在前面紅黑樹,對很多童鞋來說,是既熟悉又陌生。每次需要查看紅黑樹內(nèi)容時都很難以更生動形象的方式來理解其內(nèi)容。 寫在前面 紅黑樹,對很多童鞋來說,是既熟悉又陌生。學(xué)校中學(xué)過,只了解大概;工作中不怎么使用,但面試又是重點。每次需要查看紅黑樹內(nèi)容時都很難以更生動形象的方式來理解其內(nèi)容。沒錯,本文內(nèi)容就是要解決這個問題,用簡單的語言,搭配靜圖和動圖(利用大腦圖形記憶方式),讓你對紅黑樹有更深...
摘要:是棧,它繼承于。滿二叉樹除了葉結(jié)點外每一個結(jié)點都有左右子葉且葉子結(jié)點都處在最底層的二叉樹。沒有鍵值相等的節(jié)點。這是數(shù)據(jù)庫選用樹的最主要原因。 在我們學(xué)習(xí)Java的時候,很多人會面臨我不知道繼續(xù)學(xué)什么或者面試會問什么的尷尬情況(我本人之前就很迷茫)。所以,我決定通過這個開源平臺來幫助一些有需要的人,通過下面的內(nèi)容,你會掌握系統(tǒng)的Java學(xué)習(xí)以及面試的相關(guān)知識。本來是想通過Gitbook的...
摘要:源碼剖析由于紅黑樹的操作我這里不說了,所以這里基本上也就沒什么源碼可以講了,因為這里面重要的算法都是,這里的是指,他們是算法導(dǎo)論的作者,也就是說里面算法都是參照算法導(dǎo)論的偽代碼。因為紅黑樹是平衡的二叉搜索樹,所以其包含操作的時間復(fù)雜度都為。 本文章首發(fā)于個人博客,鑒于sf博客樣式具有賞心悅目的美感,遂發(fā)表于此,供大家學(xué)習(xí)、批評。本文還在不斷更新中,最新版可移至個人博客。? 繼上篇文章...
閱讀 2086·2021-09-22 15:54
閱讀 1845·2021-09-04 16:40
閱讀 870·2019-08-30 15:56
閱讀 2635·2019-08-30 15:44
閱讀 2160·2019-08-30 13:52
閱讀 1133·2019-08-29 16:35
閱讀 3353·2019-08-29 16:31
閱讀 2573·2019-08-29 13:48