赞
踩
合适的数据结构,对代码的性能提升非常明显。针对数据结构,我们不需要可以做到白板手写的程度。只要熟知其特点,然后推导出其应用场景,等到了真正需要时,再查找示例代码来修改应用即可。
一个分层的数据结构,其每个节点可以有多个子节点。树有比数组更好的插入删除性能,有比链表更好的随机访问性能。针对树的特性,又进一步进行了优化,不同的树有不同的应用重点。
为了解决二叉搜索树退化导致性能降低的极端情况,出现了平衡二叉搜索树,其避免出现某一个分支过长的情况,操作性能较二权搜索树更加均衡。但是在数据量巨大时,其树高比较高,导致对根节点的操作性能较差。
AVL树和红黑树都是平衡二权搜索树,红黑树相对于AVL树规则更简单,所以平衡二叉树多使用红黑树。C++中的std::map即采用红黑树实现。
为了优化平衡二叉树在大量数据时容易根节点过深的问题,将平衡二叉树的每个节点存放更多数据。在数据量较小的时候,红黑树的平衡性能更优。在数据量比较大的时候,B树的平衡性能比红黑树更优。并且B树引入了更复杂的节点数据,每个非根节点存放3类数据,Key-Data-Pointer。这样就可以应对更复杂的数据存储查询删除需求。
B+树优化了B树,将Key和数据统一放到根节点存储,子节点只用来存放Key和指针。相较于B树,B+在操作性能上更稳定起伏小。另外,B+树更容易顺序指定范围从前后往后扫描所有数据。B+树的这种特性非常适用于管理文件系统,现代文件系统NTFS和Ext4均使用B+树来实现。大型的关系型数据MySQL、SQL Serve、Oracle、PostgreSQL均使用B+树来存储管理其主要数据。
跳表是对传统的有序链表进行优化,添加多层索引来加速搜索操作,简单来说它是一个空间换时间的策略。针对数据量的大小,以及对性能的要求,可以相应地设计索引层数。
跳表相比红黑树,算法更简单,在索引层级足够的前提下,可以实现更好的搜索性能。在索引层级较多时,其空间相比红黑树会占用更大,具体取决于跳表层级的设计。
跳表需要预先分配空间,红黑树可以更好的动态扩大缩小。
算法复杂度上,跳表比较红黑树要简单,更容易理解。
红黑树的数据是有序的,缓存一致上能够做到比较好。跳表如果数据量比较大,其过多的层级索引和数据之间可能导致缓存一致性降低。
综合来讲,在40MB(对应1000万int类型数据)数据量以下,跳表的性能要略优于红黑树。如果数据量更多,跳表的性能因为其层级索引缓存一致性问题,性能逐渐不如缓存一致性更好的红黑树。所以相对于复杂的大型文件系统或是大型数据库,更适合使用B+树,数据量少一些的数据管理,更适合红黑树或跳表。内存数据库Redis、键值存储数据库LevelDB都是用跳表来实现主要数据的管理。
块状链表更数组属性,局部随机性表现会比跳表好,但是整体随机性比跳表差。综合来讲,在数据量1K以下,块状链表和跳表性能相当,在更大数据量,跳表性能更优。
索引是加快查找的重要方法,针对数据量,可以使用多级索引。根据数据类型,可以使用不同类型的索引。一个大型的数据管理系统一般会根据需求,针对性地创建不同的索引来加快查找、增删的性能。
位图索引(Bitmap Index),即用比特来映射数据的状态。为了更好的数据管理实时性能,一般数据删除时,只是在另外的数据结构中标记其是否删除,并不执行真正的删除操作。等到下次需要添加数据时,只需要通过标记找到无效数据节点覆盖新数据即可。这样可以提高性能。更高效,更节省空间的标记数据结构就是位图索引。大型文件系统、数据库都有使用位图索引。
哈希表是一个存储Key-Value的数据结构。哈希表通过哈希函数将Key映射到存储数据的下标索引,这样就可以快速根据Key来访问对应的数据。哈希函数生成的哈希值下标有可能重复,那么可以用一个链表来记录哈希值相同的Key和数据以便二次查找,所以其空间消耗比红黑树高。但是其搜索性能远高于红黑树。哈希表的算法实现也比较红黑树简单。哈希表有大量的开源算法,可以根据数据类型、数据量、算法复杂度和性能综合选择哈希算法。
图是由节点和连接节点的边组成的非线性数据结构,用于表示多个对象之间的关系。如果有多对多的复杂关系,且有最短路径这类需求的,可以考虑使用图数据结构。
一个大型的存储系统,一般会使用多种数据结构协调工作,甚至根据实际情况会在标准数据结构上进行变形优化。重点是要明白数据结构的特点和和其对应性能的表现,这样指导我们使用和优化数据结构。
参考资料:
Stack Data Structure and Implementation in Python, Java and C/C++
顺序查找,适用于数据量较小的无序数据集。
二分查找,适用于有序的数据集。
针对有均匀分布的有序数据集,可以优化二分查找法,可以通过公式估算采样位置进行查找。在数据量较小时,公式估算的性能开销会抵消插值查找优化的效果。
针对有均匀分布的有序数据集,采用斐波那契数(黄金分割点分割,而不像二分法平分)分割数据进行查找,相比二分法能够更快地找到目标。针对不均匀的数据集,其效果也会远远好于插值查找。数据量较小时,算法额外开销会抵消其部分性能优势。
如果数据是以平衡二叉树存储的,那么就使用二叉查找树查找法来查找。
数据有序存储的开销较大,无序存储的查找开销大。分块查找,就是部分有序,将数据按大小分成几堆,每一堆中的数据不要求有序。这样初始的存储开销较有序存储低,查找性能较无序存储的高。分块查找要求能够比较准确地将数据分为大小相近的几堆。如果分类不够准确,加大了存储开销,却不能提升多少查找性能。
哈希查找通过存储数据时建立哈希映射表,查找时通过哈希值来查找。因为哈希表存在冲突,所以哈希表需要存储额外的信息,导致空间消耗较大。所以哈希查找,适用于空间足够,且数据量较大,对查找性能追求的场景。
表查找,利用位图索引来查找,速度非常快,但是空间消耗大,且要求数据唯一。针对需要重复快速查询的场景非常有效。如果手机号码是否使用等。如果有相关对应数据需求,可以建立索引表存储内容地址。
布隆过滤器根据要查询的数据建立一个相应的位图,存储数据时,将数据经过8个哈希算法,生成8个哈希索引,并在位图8个对应的索引上置1。存储其他数据时,也依次如此操作。我们知道哈希索引有冲突的概率,但是8个哈希索引都同时冲突的概率其实不大,但是依然有完全冲突的存在性。所以布隆过滤查找的结果为不存在时,就一定不存在。存在时,就有概率是误差。通过调整哈希算法的个数,可以减少冲突的概率。如邮件服务系统的垃圾邮件一般会使用布隆过滤器查找是否为垃圾邮件。
算法是一种思想,不必熟练到手写算法的程序。知道什么场景用什么算法,具体算法用的时候去查询即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。