算法效率分析
最近,在有关算法效率,数据结构性能的精彩演讲中,该演讲确实具有一些很好的性能内容。
在此博客中,我将分享上述谈话中的一些想法以及我学到的一些东西。
预处理
这是非常常见的技巧,这是在实际请求到来时所需的处理与预先计算某些事物所需的时间之间进行权衡的,其中一些很好的例子是。
指数
这是非常常见的字符串操作,几乎所有应用程序都需要此算法,java具有蛮力算法来解决此问题,但这很快就会成为瓶颈,因此最好使用Knuth–Morris–Pratt_algorithm算法,该算法会预先计算表以获取更好的性能。
搜索
顺序搜索与二进制搜索是在搜索时间或预处理(即排序)时间之间进行权衡的,如果所需比较数超过0(log n),它将开始返回
二进制搜索是许多算法的核心,这减少了昂贵的搜索操作。
使用此方法可以解决许多字符串排列搜索问题。
当添加具有相同哈希码的许多键时,Java中的Hashmap具有很好的优化,以改善影响,当键为Comparable时,此类可以使用键之间的比较顺序来帮助打破关系
指标
查找是昂贵的操作,并且二进制搜索无法回答所有类型的查询,因此您应该构建专门的索引以进行快速搜索,其中一些选项包括键/值,前缀/后缀,位图索引,倒排索引等。
预分配
这是经典的方法,因此,如果您知道数据结构将有多大,那么最好预先分配它,而不是使其保持多次扩展并招致分配和复制的成本。
每次需要重新分配时,基于数组的数据结构都会使容量增加一倍,这是通过摊销分配成本来完成的,因此它们的分配频率越来越高,在Java世界中,ArrayList,HashMap等就是很好的例子。
许多设计模式都基于此,例如对象池/飞行权重等。
减少昂贵/重复的操作
每种算法都有一些昂贵的运算,为了使其高效,应该减少那些昂贵的运算,一些常见的示例是
哈希码
哈希码计算是一项昂贵的操作,因此对于给定的密钥,不应多次对此进行计算。 一种方法是一次对其进行计算,然后将其传递给其他函数,因此不需要重新计算,也无需为Java中的String类预先计算它,即可预先计算哈希码以节省时间。
模量/分度
这是昂贵的算术运算之一,位图运算可用于执行相同的操作,但成本较低。
如果数据结构是圆形的(例如,圆形数组)并想将值放入空闲插槽,则需要进行模运算,并且如果数组的容量为2的幂,则可以使用按位运算(即index&(capacity-1) )来获取模值,这将以增加额外的内存为代价显着提高性能。 Java中的HashMap使用此技术
同样,可以使用右移(>>)操作进行除法以获得更好的性能,但是现在天编译器很聪明,因此您可以免费获取它,而无需编写它。
减少复印开销
基于数组的数据结构通过将容量增加2倍来分摊调整大小的成本,这很好,但是复制的开销也随之而来,另一种方法是数组链,因此您只分配了一个大块,却没有要复制旧值,只需将此新的内存块添加到分配的块链中即可。
gs-collection具有使用此方法构建的CompositeFastList 。
批处理
应该批处理昂贵的操作,例如写入文件/网络/数据库等,以获得最佳性能。
共置数据
根据处理器的工作方式,将所有必需的数据放在一起可获得很好的性能,但这是许多应用程序中无法解决的一件事。
迈克·阿克顿(Mike Acton)在面向数据的设计中谈到了这一点, 并在C ++中进行了详细讨论。
基于列的存储是非常好的分析/聚合用例,因为在大多数情况下,需要所有行的单列数据来回答分析/聚合请求。
线性探测哈希表也是数据共置的一个很好的例子。
位打包是使所需数据保持非常接近的另一种选择。 但应格外小心,因为这会使代码变得复杂。
不必要的工作
受此问题困扰的一些算法最常见的是递归算法,例如阶乘或斐波那契等,这两者都有重复的工作问题,可以通过备忘技术来解决。
在效率提高过程中,不应失去代码的简单性和可读性,因为下一个人必须维护它:-)
翻译自: https://www.javacodegeeks.com/2015/07/efficiency-with-algorithms.html
算法效率分析