优化建议(HashMap)

时间:2017-05-22 15:05:57

标签: java list optimization hashmap

我有一个很大的坐标列表(这个表格):

    if(x == 1055 && y == 63 && z == 1117)
        return blackwood;
    if(x == 1053 && y == 63 && z == 1117)
        return blackwood;
    if(x == 1049 && y == 64 && z == 1113)
        return blackwood;
    if(x == 1054 && y == 63 && z == 1112)
        return blackwood;
    if(x == 1058 && y == 63 && z == 1112)
        return blackwood;
    if(x == 1062 && y == 64 && z == 1117)
        return blackwood;
    if(x == 1050 && y == 64 && z == 1117)
        return blackwood;
    if(x == 1062 && y == 64 && z == 1118)
        return glass;
    if(x == 1050 && y == 64 && z == 1118)
        return andesite;

(比这长得多)

但是,当我调用执行这些指令的方法时,我有一个滞后(不是很长,但足以在游戏中产生冻结印象)。

所以,我的问题是,我该如何优化呢?

我正在考虑在HashMap中存储这些内容并使用HashMap.get(key),但HashMap.get(key)是否会重复列表以找到它?

4 个答案:

答案 0 :(得分:1)

您确实可以使用Map作为关键字,将自定义类用作这3个数据的组件值:xyz

公平地实施hashCode()方法,它应该是一个恒定的时间[O(1)]或非常接近。

如果你需要经常重新创建地图,那么使用地图可能会让人感到无助,因为从一方面你可以放松你从另一方获得的东西。

因此,创建此自定义类并通过考虑这3个字段来覆盖hashCode()equals()

public class Coordinate {

    private int x;
    private int y;
    private int z;

    public Coordinate(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        result = prime * result + z;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!(obj instanceof Coordinate))
            return false;

        Coordinate other = (Coordinate) obj;
        if (x == other.x && y == other.y && z == other.z)
            return true;

        return false;
    }


}

然后,您可以使用预期的键值初始化地图:

Map<Coordinate, MyValue> mapValuesByCoord = new HashMap<>();
mapValuesByCoord.put(new Coordinate(1055,63,1117), blackwood);
mapValuesByCoord.put(new Coordinate(1053,63,1117), blackwood);
mapValuesByCoord.put(new Coordinate(1062, 64, 1118), glass);

...

以这种方式使用地图:

MyValue value = mapValuesByCoord.get(new Coordinate(1055,63,1117));

答案 1 :(得分:1)

这里有一个问题,常用的是“#34; map&#34;”,就像在一张纸上显示一块土地的缩影,而不是程序员或数学家&#39 ;使用&#34; map&#34;,其中的值与其他值相关联。

如果几乎​​每个3D坐标都有相应的返回值,那么最好使用直接查找表。您可以使用3D数组执行此操作,即阵列数组:

 Rock[][][] rockMap =  ... // Google for guidance on initialising a 3D array

 ...
 rockMap[1054][63][1112] = blackwood;
 // etc.

这里&#34; rockMap&#34;更接近于'#34; map&#34;这个词的常用用法。如果您绘制了3D阵列,它将是您的世界地图&#34;。

然后你的查询是:

 return rockMap[x][y][z];

或者,您可以使用1D数组并从x,y,z计算索引:

 Rock[] rockMap = new Rock[SIZE_X * SIZE_Y * SIZE_Z];

 rockMap[1054 * SIZE_Y * SIZE_Z + 63 * SIZE_Z + 1112] = blackwood;

查找类似于作业:

 return rockMap[x * SIZE_Y * SIZE_Z + y * SIZE_Z + z];

如果你没有为每个坐标设置摇滚,这种方法仍然有用(你在所有空插槽中只有一个空值或其他缺席标记)。但这会浪费太多空间。

在这种情况下,创建Coordinate类型并构建Map<Coordinate>可能更有效。

 Map<Coordinate> rockMap = ...;
 rockMap.put(new Coordinate(x,y,z), blackwood);

 ...

 return rockMap.get(new Coordinate(x,y,z));

您应该进行自己的测试,以了解哪种类型的Map最适合您的计划 - HashMapTreeMap?测试它们。

要使这些工作正常,Coordinate需要实现某些方法 - 检查Javadoc并确保它。

答案 2 :(得分:0)

HashMap很少迭代从其结构中获取元素。正确的实现很少迭代,人们通常不会提及该部分存在。因此O(1)的复杂性。

想象一下你的元素表(每个元素都有一个键)。理想情况下,HashMap会将每个元素放在一个唯一的行中(因此每行只有1个元素)。当给定获取元素的键时,HashMap将计算键的哈希(int)并找出其适当值位于哪一行。可能会出现一行中的多个元素,因为有时两个不同的键可以具有相同的哈希值,然后您迭代该行以查找您的元素。

我认为您可以在问题上使用HashMap来加快速度(x,y和z应该是唯一键)。

答案 3 :(得分:0)

我会创建具有check(x,y,z)方法的黑木,玻璃和安山岩对象。

修改

也许我应该补充一点,为了提高效率,你可以像这样实现blackwood.check(x,y,z):

  public boolean check(int x, int y, int z){
      if ( y == 63 || y == 64){
          if (z == 1117 || z == 1113 || z == 1112){
              if (x == 1055 || x == 1053 || x == 1049 || x = 1054 || 
                  x == 1058 || x == 1062 || x == 1050){
                  return true;
              }
          }
      }
    return false;
}

你将从中获得什么:

1)每种类型的逻辑被封装到单独的类中,你不会有一个带有长“ifs”的巨大方法。添加新类型很容易。

2)通过将“y”检查移到顶部,如果它不是63或64,则会快速退出。同样适用于z。由于Java中的“或”检查不会检查其余部分,因此如果x为1055,则不会检查所有“x”值,因此会购买一些性能。

3)使用Map或Set方法,您必须在每次调用方法时创建X,Y,Z包装密钥对象。通过非常频繁地调用该方法,您可能会遇到垃圾收集器无法以足够快的速度清理它们的问题。