1 AVL树:平衡二叉树,一般是用平衡因子差值决定并通过旋转来实现,左右子树树高差不超过1,那么和红黑树比较它是严格的平衡二叉树,平衡条件非常严格(树高差只有1),只要插入或删除不满足上面的条件就要通过旋转来保持平衡。由于旋转是非常耗费时间的。我们可以推出AVL树适合用于插入删除次数比较少,但查找多的情况。
2 红黑树:平衡二叉树,通过任何一条从根到叶子的简单路径上各个节点的颜色进行约束,确保没有一条路径会比其他路径长2倍,因而是近似平衡的。所以相对于严格要求平衡的AVL树来说,它的旋转保持平衡次数较少。用于搜索时,插入删除次数多的情况下我们使用红黑树来取代AVL。(现在部分场景使用跳表来替换红黑树)
红黑树应用:c++ STL
epoll 在内核中的实现,用红黑树来管理事件块
nginx中,用红黑树来管理timer等
Java中的TreeMap实现
著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块
3 B树 B+树:他们的特点是一样的,是多路查找树,一般用于数据库系统,为什么?因为他们分支多层数少,都知道磁盘IO是非常耗时的,而像大量数据存储在磁盘中所以我们要有效的减少磁盘IO次数避免磁盘频繁的查找。B+树是B树的变种,数据都保存在叶子节点。是为文件系统而生的。
4 Tire树:又名单词查找树,一种树型结构,常用来操作字符串。它是不同字符串的相同前缀只保存一份。相对直接保存字符串肯定是节省空间的,但是它保存大量字符串时会很耗费内存(是内存)。类似的有前缀树,后缀树,radix tree(patricia tree, compact prefix tree)) ,crit-bit tree(解决耗费内存问题),以及前面说的double array trie。简单的补充下我了解应用的前缀树:字符串快速检索,字符串排序,最长公共前缀,自动匹配前缀显示后缀。后缀树:查找字符串s1 在s2 中,字符串s1在s2中出现的次数,字符串s1,s2最长公共部分,最长回文串。radix tree:linux 内核,nginx。
PS:Redis 中使用跳表,而不是红黑树来存储管理其中的元素(应该说的是一级元素-直接的Key,里面的value应该是有不同的数据结构)
首先,条表示SkipList 不是ZipList .ZipList 在redis中是有一个非常省内存的链表(代价是性能略低),所以在hash元素的个数很少(比如只有几十个),那么用这个结构来存储则可以性能损失很少的情况下节约很多内存(Redis 是内存数据库,能省还是要省)
在server端,对并发和性能有要求的情况下,如何选择合适的数据结构(这里是跳跃表和红黑树)。如果在单纯比价性能,跳跃表和红黑树可以说相差不打,但是加上并发的环境就不一样了,如果要更新数据,跳跃表需要更新的部分就比较少,锁的东西也就比较少,所以不同线程争锁的代价就相对少了,而在红黑树有个平衡的过程,牵涉到大量的节点,争锁的代价就相对高了。性能也就不如前者。在并发环境下skiplist的操作显然更加局部性一些,锁需要盯住的节点更少,因此这样的情况下性能好一些。