2017-05-22 40 views
1

我有坐标的大名单(此表):优化建议(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)迭代列表中找到它呢?

+2

号包含HashMap返回* *基本恒定的时间AFAIK。这就是人们使用它们的原因。注意,虽然要将坐标置于HashMap中,您需要将数字分组到某个向量或其他东西中,并且反复散列容器也可能会慢一些;尽管可能比你现在的t方法更快。 – Carcigenicate

+1

'HashMap.get()'是恒定时间(加上冲突解决方案 - 取决于列表大小与列表中项目之间的比例) – Achilles

+0

做你自己的研究什么是哈希表。下面是开始的一些事情:[哈希表如何工作](https:// stackoverflow。COM /问题/ 730620 /如何-做的那样 - 一个哈希表工作) –

回答

1

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

通过公平的实施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)); 
0

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

想象一下你的元素表(每个元素都有一个键)。理想情况下,HashMap将把你的每一个元素放在一个唯一的行中(所以每行只有一个元素)。当给定一个键来获取一个元素时,HashMap将计算该键的散列(int)并找出哪一行是它的合适值。一行中可能会出现多个元素,因为有时两个不同的键可以具有相同的散列,然后您迭代该行以找到您的元素。

我想你可以使用你的问题,一个HashMap加快步伐位(其中x,y和z应该是唯一的键)。

1

这里有一个问题在这里与“地图”一词共同使用,就像在一张纸上显示一幅土地的微型表示,而程序员或数学家使用“地图”,其中的值与其他值相关联。

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

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

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

这里“rockMap”更靠近共同使用的词语“地图”的。如果你画出这个3D阵列,那将是你的“世界地图”。

那么你的查找是:

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

或者,您也可以使用一维数组,并计算出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]; 

如果你对每个坐标都没有石头,这种方法仍然可行(你只需要一个nu在所有的空插槽中,或者其他缺席标记)。但是这太浪费了。

在这种情况下,创建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并确保它。

-1

我将创建具有检查(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包装器关键对象。随着该方法被频繁调用,您可能会遇到垃圾收集器无法快速清理它们的问题。