树的分类:
1.二叉树:如果不对其中的元素进行排序,则不利于查找
2.二叉查找树(Binary Search Tree)
节点按照一定的顺序排列:对于二叉查找树中的所有结点X, 它的左子树的所有项的值小于X中的项,而它的右子树中的所有项大于X中的项。
查找效率更高,但因为根节点是固定的,所以受数据的分布规律影响会不平衡,造成复杂度的方差太大。比如可能会退化为成链表形式,比如一个二叉树删除了部分之后变长下面这样。
3. AVL树(AV和L分别是两个人的名字)
满足二叉查找树的要求,但增加了平衡条件(Balance Condition): 每个结点的左子树和又子树的高度最多差1的二叉查找树(空树高度定义为-1)
在插入和删除结点后,为了达到平衡条件,需要通过旋转(rotation)操作。
AVL树的缺点:插入和删除操作很容易打破其平衡条件,为了维持其平衡条件代价很高。
4. 红黑树(Red-black tree)
摘自维基百科
红黑树仍属于二叉查找树,但节点带有颜色,分为红色和黑色。
在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
1)节点是红色或者黑色
2)根节点为黑色
3)所有叶子都是黑色(叶子是NIL空节点)
4)每个红色节点必须有两个黑色节点(从每个叶子到根的所有路径上不能够有连续的两个红色节点出现)
5)从任一节点到其叶子的所有简单路径都包含相同数目的黑色节点
通过4)可以知道不能有连个连续的红色节点,故对于某路径上有固定的黑色节点的情况下,最短的路径为全黑色,最长的路径为红黑交替。再结合5)就能知道没有那一条的路径上的节点能够多于其他路径的两倍,这是红黑树最关键的特征。避免了AVL树的缺点
5.伸展树
属于二叉查找树,会将查找频率高的节点通过旋转操作移动到靠近根节点的地方。
手写其实现的时候,不需要去记忆每一种情况应该怎样去移动对应的节点,通过图示即可得到,对于所有的数据结构的编程几乎都可以这样理解。通过图示可以知道编写的时候应该:
1. "旋转"操作分为哪几种不同的情况,节点应该怎样移动(画图即可知道应该分为L, R, LL, RR, LR, RL几种不同的情况)。
2. 对于伸展树需要实现哪些增删查找的操作,划分成对应的函数
3. 对2中的函数实现的时候需要考虑怎么使用1中的不同的旋转函数,找到对应的条件。
具体可参考:https://blog.csdn.net/u014634338/article/details/49586689
6.B树
计算机硬件中,CPU的运算速度远快于磁盘等外设。磁盘的访问速度是非常慢的,所以需要尽量减少程序中对磁盘的访问次数。(在CPU和外设同时存在时,此时使用O(...)的方式来表征计算的复杂度就没有多少意义了)。CPU和内存的速度较快,所以使用二叉树的方式在内存中存储数据是合适的,但对于磁盘,因为使用二叉树的检索时间会很长,这就产生了M叉查找树(M-ary search tree).分支变多了,所以深度会降低。完全二叉树高度(log2)N, 完全M叉树高度(logM)N
而B树就是一类M叉树:
需要注意B树在插入数据的时候需要进行节点的分裂,特殊情况下需要一直向上进行分裂,最后将根节点分裂为两个节点,形成一个新的根。这也是在特征(3)中根可以只有2个儿子的原因。
/*********************************************************************************************************************************************/
散列表(哈希表, hash table)
通过key-value键值对的方式来实现快速的查找。
通过哈希函数计算出当前的查找关键字key所对应的value值,这个值对应了一个数组Index[XXX]中的元素,比如索引到数组的下标i,而Index[i]中存放了对应的数据或者其地址(指针),然后就可以根据key查找到对应的数据。
但需要注意多个key值映射为同一个value的时候,产生冲突的情况。
可以:
a. 分离链接法: 就是如上图中使用链表的方式添加冲突的数据。
b. 探测散列表(probing hash tables): 前一次计算得到的value, 结合冲突解决函数,重新计算,直到不冲突为止。通过参数装填因子 来看放的数据的比例, 一般要求
< 0.5
可扩展散列:
hash_map并没有引入到C++ STL中,而是属于STL的ext部分。还需要注意和STL中的map的区别,采用红黑树来实现。具体可见:
https://blog.csdn.net/u010025211/article/details/46653519
/******************************************************************************************************************************/
堆的分类:
1. 二叉堆
需要满足:
1). 是完全二叉树: 对于一个深度为n的二叉树,必须保证前n-1层被全部填满,第n层按照从左到右进行元素的填充。
2). 对于每一个节点X, X中的键小于(或等于)其任意子节点的键
故"最小元素"总能在根节点处。
支持的操作:
a. 插入: 在下一个空闲位置创建一个节点,然后和其父节点比较优先级是否要向上移动。直到比其某个父节点大才停止。(或自己比根节点还要小,就和根节点互换) , 此过程成为上滤(percolate up)
b. 删除:只能删除根节点,删除之后需要将之前的最后一个节点放到新的根节点上循环和其最小的子节点比较以确定是否进行下移操作,最后就重新合并成了一个新的二叉堆。(称为下滤(percolate down))
和完全二叉树一样,二叉堆一般可以使用数组来在内存中实现。
对于数组中的任一位置i上的元素,其左儿子在在位置2i上,其右儿子在左儿子后的单元(2i+1)中,它的父亲则在位置(i/2)上(注意i为奇数时是向上还是向下取整)。
2. d堆
和二叉堆类似,但每个节点有d个儿子。
堆的缺点:
1. 不能执行find查找操作
2. 将两个堆merge比较困难
排序:
1. 插入排序
对于每一个元素和他前面已经排序的元素进行比较,插入到合适的位置即可
2. 希尔排序
需要选择一个增量序列,然后分组进行(插入)排序
https://www.cnblogs.com/chengxiao/p/6104371.html