紅黑樹、B(+)樹、跳表、AVL等數據結構,應用場景及分析,以及一些英文縮寫


在網上學習了一些材料。

這一篇:https://www.zhihu.com/question/30527705

AVL樹:最早的平衡二叉樹之一。應用相對其他數據結構比較少。windows對進程地址空間的管理用到了AVL樹

紅黑樹:平衡二叉樹,廣泛用在C++的STL中。map和set都是用紅黑樹實現的。我們熟悉的STL的map容器底層是RBtree,當然指的不是unordered_map,后者是hash。

B/B+樹用在磁盤文件組織 數據索引和數據庫索引

Trie樹 字典樹,用在統計和排序大量字符串

------

AVL是一種高度平衡的二叉樹,所以通常的結果是,維護這種高度平衡所付出的代價比從中獲得的效率收益還大,故而實際的應用不多,
更多的地方是用追求局部而不是非常嚴格整體平衡的紅黑樹。當然,如果場景中對插入刪除不頻繁,只是對查找特別有要求,AVL還是優於紅黑的。 紅黑樹的應用就很多了,除了上面同學提到的STL,還有 epoll在內核中的實現,用紅黑樹管理事件塊 nginx中,用紅黑樹管理timer等 Java的TreeMap實現 著名的linux進程調度Completely Fair Scheduler,用紅黑樹管理進程控制塊 B和B
+主要用在文件系統以及數據庫中做索引等,比如Mysql:B-Tree Index in MySql trie 樹的一個典型應用是前綴匹配,比如下面這個很常見的場景,在我們輸入時,搜索引擎會給予提示 還有比如IP選路,也是前綴匹配,一定程度會用到trie ------ 跳表:Redis中就使用跳表,而不是紅黑樹來存儲管理其中的元素(應該說的是一級元素-直接的Key,里面的value應該是有不同的數據結構)。 首先,跳表是skiplist?不是ziplist。ziplist在redis中是一個非常省內存的鏈表(代價是性能略低),所以在hash元素的個數很少(比如只有幾十個),
那么用這個結構來存儲則可以在性能損失很小的情況下節約很多內存(redis是內存數據庫啊,能省還是要省的)。好這個問題清楚了。 在server端,對並發和性能有要求的情況下,如何選擇合適的數據結構(這里是跳躍表和紅黑樹)。 如果單純比較性能,跳躍表和紅黑樹可以說相差不大,但是加上並發的環境就不一樣了,
如果要更新數據,跳躍表需要更新的部分就比較少,鎖的東西也就比較少,所以不同線程爭鎖的代價就相對少了,
紅黑樹有個平衡的過程,牽涉到大量的節點,爭鎖的代價也就相對較高了。性能也就不如前者了。 在並發環境下skiplist有另外一個優勢,紅黑樹在插入和刪除的時候可能需要做一些rebalance的操作,這樣的操作可能會涉及到整個樹的其他部分
skiplist的操作顯然更加局部性一些,鎖需要盯住的節點更少,因此在這樣的情況下性能好一些。

另外Redis作者描述的使用跳表的原因:

請看開發者說的,他為什么選用skiplist The Skip list

There are a few reasons:
1) They are not very memory intensive. It's up to you basically. 
Changing parameters about the probability of a node to have a given number of levels will make then less memory intensive
than btrees.
注:跳表的一個缺點是耗內存(因為要重復分層存節點),但是作者也說了,可以調參數來降低內存消耗,和那些平衡樹結構達到差不多。
2) A sorted set is often target of many ZRANGE or ZREVRANGE operations, that is, traversing the skip list as a linked list.
With this operation the cache locality of skip lists is at least as good as with other kind of balanced trees.
注:redis經查有范圍操作,這樣利用跳表里面的雙向鏈表,可以方便地操作。另外還有緩存區域化(
cache locality)不會比平衡樹差。
3) They are simpler to implement, debug, and so forth. For instance thanks to the skip list simplicity I received a patch 
(already in Redis master) with augmented skip lists implementing ZRANK in O(log(N)). It required little changes to the code.
注:實現簡單。zrank操作能夠到O(log(N)).
About the Append Only durability
& speed, I don't think it is a good idea to optimize Redis at cost of more code
and more complexity for a use case that IMHO should be rare for the Redis target (fsync() at every command).
Almost no one is using this feature even with ACID SQL databases, as the performance hint is big anyway.
About threads: our experience shows that Redis is mostly I/O bound. I'm using threads to serve things from Virtual Memory.
The long term solution to exploit all the cores, assuming your link is so fast that you can saturate a single core,
is running multiple instances of Redis (no locks, almost fully scalable linearly with number of cores),
and using the "Redis Cluster" solution that I plan to develop in the future.

上面文章中有一些英文縮寫,整理如下:

imho, imo(in my humble opinion, in my opinion):在我看來,常見於論壇。

idk(I don’t know):我不知道。

rofl(rolling on the floor laughing):笑到摔到地上。

roflmao(rolling on the floor laughing my ass of):前兩個的結合版,也就是超級搞笑的意思。

sth(something):某事某物。

nth(nothing):什么也沒有。

plz(please):請。please 字尾是z 音,所以按照讀音縮寫為plz。

thx(thanks):謝謝。按照發音來看,thanks字尾的ks可以用字母X代替。

紅黑樹與B(+)樹工程實現的比較:

已有的幾個答案都是從算法角度分析的,我嘗試分析下從工程角度區分紅黑樹與b+樹的應用場景,紅黑樹一個node只存一對kv,因此可以使用類似嵌入式鏈表的方式實現,
數據結構本身不管理內存,比較輕量級,使用更靈活也更省內存,比如一個node可以同時存在若干個樹或鏈表中,內核中比較常見。

而b+樹由於每個node要存多對kv,node結構的內存一般就要由數據結構自己來管,是真正意義上的container,相對嵌入式方法實現的紅黑樹,
好處是用法簡單,自己管理內存更容易做lockfree,一個node存多對kv的方式cpu cache命中率更高,所以用戶態實現的高並發索引一般還是選b+樹。

再說b樹與b+樹,btree的中間節點比b+樹多存了value,同樣出度的情況下,node更大,相對來說cpu cache命中率是不如b+樹的。
另外再提一句,b+樹的掃描特性(鏈表串起來的葉子節點)在無鎖情況下是很難做的(我還沒見到過解法),因此我目前見到的無鎖b+樹葉子節點都是不串起來的。

從各自特點特征角度,分析各種數據結構的應用場景:

紅黑樹,AVL樹簡單來說都是用來搜索的唄
AVL樹:平衡二叉樹,一般是用平衡因子差值決定並通過旋轉來實現,左右子樹樹高差不超過1,那么和紅黑樹比較它是嚴格的平衡二叉樹,平衡條件非常嚴格(樹高差只有1),
只要插入或刪除不滿足上面的條件就要通過旋轉來保持平衡。由於旋轉是非常耗費時間的。我們可以推出AVL樹適合用於插入刪除次數比較少,但查找多的情況。 紅黑樹:平衡二叉樹,通過對任何一條從根到葉子的簡單路徑上各個節點的顏色進行約束,確保沒有一條路徑會比其他路徑長2倍,因而是近似平衡的。
所以相對於嚴格要求平衡的AVL樹來說,它的旋轉保持平衡次數較少。用於搜索時,插入刪除次數多的情況下我們就用紅黑樹來取代AVL。 (現在部分場景使用跳表來替換紅黑樹,可搜索“為啥 redis 使用跳表(skiplist)而不是使用 red
-black?”) B樹,B+樹:它們特點是一樣的,是多路查找樹,一般用於數據庫系統中,為什么,因為它們分支多層數少唄
都知道磁盤IO是非常耗時的,而像大量數據存儲在磁盤中所以我們要有效的減少磁盤IO次數避免磁盤頻繁的查找。 B
+樹是B樹的變種樹,有n棵子樹的節點中含有n個關鍵字,每個關鍵字不保存數據,只用來索引,數據都保存在葉子節點。是為文件系統而生的。 Trie樹: 又名單詞查找樹,一種樹形結構,常用來操作字符串。它是不同字符串的相同前綴只保存一份。 相對直接保存字符串肯定是節省空間的,但是它保存大量字符串時會很耗費內存(是內存)。
類似的有 前綴樹(prefix tree),后綴樹(suffix tree),radix tree(patricia tree, compact prefix tree),crit
-bit tree(解決耗費內存問題),
以及前面說的double array trie。 簡單的補充下我了解應用 前綴樹:字符串快速檢索,字符串排序,最長公共前綴,自動匹配前綴顯示后綴。 后綴樹:查找字符串s1在s2中,字符串s1在s2中出現的次數,字符串s1,s2最長公共部分,最長回文串。 radix tree:linux內核,nginx。

紅黑樹的介紹可以看這兩篇文章:史上最清晰的紅黑樹講解(上)+(下)

http://mt.sohu.com/20161014/n470317653.shtml

http://mt.sohu.com/20161018/n470610910.shtml

當查找樹的結構發生改變時,紅黑樹的條件可能被破壞,需要通過調整使得查找樹重新滿足紅黑樹的條件。
調整可以分為兩類: 一類是顏色調整,即改變某個節點的顏色; 另一類是結構調整,集改變檢索樹的結構關系。結構調整過程包含兩個基本操作:左旋(Rotate Left),右旋(RotateRight)

記住,無論有多少情況,具體的調整操作只有兩種:1.改變某些節點的顏色,2.對某些節點進行旋轉。

另開一文分析字符串相關的各種算法,以及用到的各種數據結構,包括前綴樹后綴樹等各種樹。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM