Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 索引列表时的最佳HashMap初始容量_Java_Algorithm_Dictionary_Hashmap - Fatal编程技术网

Java 索引列表时的最佳HashMap初始容量

Java 索引列表时的最佳HashMap初始容量,java,algorithm,dictionary,hashmap,Java,Algorithm,Dictionary,Hashmap,我有一个列表(list list),我想使用一个映射(HashMap)根据对象的ID对其对象进行索引。我总是使用list.size()作为HashMap构造函数中的初始容量,如下所示。这是在这种情况下使用的最佳初始容量吗 注意:我永远不会向地图添加更多项目 List<T> list = myList; Map<Integer, T> map = new HashMap<Integer, T>(list.size()); for(T item : list) {

我有一个列表(
list list
),我想使用一个映射(
HashMap
)根据对象的ID对其对象进行索引。我总是使用
list.size()
作为
HashMap
构造函数中的初始容量,如下所示。这是在这种情况下使用的最佳初始容量吗

注意:我永远不会向地图添加更多项目

List<T> list = myList;
Map<Integer, T> map = new HashMap<Integer, T>(list.size());
for(T item : list) {
    map.put(item.getId(), item);
}
List List=myList;
Map Map=newhashmap(list.size());
对于(T项:列表){
map.put(item.getId(),item);
}

你现在做的很好。通过这种方式,您可以确保哈希映射至少有足够的容量用于初始值。如果您有关于哈希映射使用模式的更多信息(例如:是否经常更新?是否经常添加许多新元素?),您可能希望设置更大的初始容量(例如,
list.size()*2
),但决不降低。使用探查器确定初始容量是否过早不足

更新

感谢@PaulBellora建议将初始容量设置为
(int)Math.ceil(list.size()/loadFactor)
(通常,默认负载系数为0.75),以避免初始调整大小。

Guava使用此辅助方法计算默认负载系数
0.75
的初始容量,基于一些预期的值数:

/**
 * Returns a capacity that is sufficient to keep the map from being resized as
 * long as it grows no larger than expectedSize and the load factor is >= its
 * default (0.75).
 */
static int capacity(int expectedSize) {
    if (expectedSize < 3) {
        checkArgument(expectedSize >= 0);
        return expectedSize + 1;
    }
    if (expectedSize < Ints.MAX_POWER_OF_TWO) {
        return expectedSize + expectedSize / 3;
    }
    return Integer.MAX_VALUE; // any large value
}
/**
*返回一个容量,该容量足以防止将映射调整为
*只要其增长不超过预期大小且负载系数>=其
*默认值(0.75)。
*/
静态整数容量(整数预期大小){
如果(预期尺寸<3){
checkArgument(expectedSize>=0);
返回expectedSize+1;
}
if(预期尺寸<整数最大功率(共两个){
返回expectedSize+expectedSize/3;
}
返回Integer.MAX_VALUE;//任何大值
}
参考:

newHashMapWithExpectedSize
文档中:

创建一个
HashMap
实例,该实例具有足够高的“初始容量”,可以 它应该能容纳
expectedSize
元素而不增长。这种行为 不能广泛地保证,但观察到这一点对 OpenJDK1.6。也不能保证该方法不正确 无意中过大了返回的映射

根据报告:

在设置初始容量时,应考虑map中的预期条目数及其负载系数,以尽量减少再灰化操作次数。如果初始容量大于最大入口数除以负载系数,则不会发生再灰化操作

这意味着,如果您事先知道HashMap应该存储多少个条目,您可以通过选择适当的初始容量和负载因子来防止重新灰化。然而:

作为一般规则,默认负载系数(.75)在时间和空间成本之间提供了良好的折衷。较高的值会减少空间开销,但会增加查找成本(反映在HashMap类的大多数操作中,包括get和put)


如果您希望避免重新设置
HashMap
,并且您知道没有其他元素将被放入
HashMap
,则必须考虑负载系数以及初始容量。载荷系数

每当添加新条目时,即会进行计算以确定是否需要重新灰化,例如,
put
放置新的键/值。因此,如果您将初始容量指定为
list.size()
,负载系数指定为1,那么它将在最后一次
put
之后重新刷新。因此,为了防止重新灰化,请使用负载系数1和容量
list.size()+1

编辑

查看
HashMap
源代码,如果旧大小达到或超过阈值,它将重新刷新,因此不会在最后一次
put
上重新刷新。所以它的容量应该是
list.size()

HashMap<Integer, T> map = new HashMap<Integer, T>(list.size(), 1.0);

“capacity”关键字的定义不正确,未按通常预期的方式使用

默认情况下,HashMap的“加载因子”为0.75,这意味着当HashMap中的条目数达到提供容量的75%时,它将调整数组大小并重新加载

例如,如果我这样做:

Map<Integer, Integer> map = new HashMap<>(100);
这将返回list.size()+list.size()的25%,例如,如果我的列表大小为100,则返回133。然后,当地图的大小等于初始容量的75%时,我们会将1添加到地图中,因此如果我们有一个大小为100的列表,我们会将初始容量设置为134,这意味着从列表中添加所有100个条目不会导致地图的任何大小调整

最终结果:

Map<Integer, Integer> map = new HashMap<>(list.size() / 0.75 + 1);
Map Map=newhashmap(list.size()/0.75+1);

如果您不知道负载系数/容量内部构件,请遵循经验法则:

initialCapacityToUse = (Expected No. of elements in map / 0.75) + 1

有了这个初始容量值,在map中存储给定数量的元素时就不会发生重缓存。

我建议:1)将变量声明为
map
,而不是
HashMap
,2)如果您注意到一个分析器正在给您的性能带来影响,请将这种问题留给JVM,然后开始评估它。@LuiggiMendoza一般说来是的,同意,但这是一个非常常见的用例,我们最好不要重新调整大小“哈希映射至少有足够的容量用于初始值”-如果默认负载系数为0.75,我认为这是不正确的。@PaulBellora初始容量与
initialCapacity
参数中指定的大小相同。负载因子是在哈希表的容量(初始值或非初始值)自动增加之前,允许哈希表达到的满度的度量,因此当负载因子为
0.75
且初始容量为
n
时,将
n
Map<Integer, Integer> map = new HashMap<>(list.size() / 0.75 + 1);
initialCapacityToUse = (Expected No. of elements in map / 0.75) + 1