检查二维数组中每个邻居的最快方法
Fastest way to check each neighbor in 2D array
我正在开发随机地牢生成器只是为了好玩/作为学习一些新事物的辅助项目。我已经编写了一个函数,该函数 returns 是任何给定单元格的整数哈希值,它为您提供有关它应该是什么类型的游戏对象的信息。即如果它是一堵墙,面对什么方向,它是一个角落,等等。这是函数目前的样子。
private int CellHashValue(int xIndex, int yIndex, char centerTile)
{
int hashValue = 0;
if (dungeon2DArray[xIndex - 1, yIndex + 1] == centerTile)
{
hashValue += 1;
}
if (dungeon2DArray[xIndex, yIndex + 1] == centerTile)
{
hashValue += 2;
}
if (dungeon2DArray[xIndex + 1, yIndex + 1] == centerTile)
{
hashValue += 4;
}
if (dungeon2DArray[xIndex - 1, yIndex] == centerTile)
{
hashValue += 8;
}
if (dungeon2DArray[xIndex + 1, yIndex] == centerTile)
{
hashValue += 16;
}
if (dungeon2DArray[xIndex - 1, yIndex - 1] == centerTile)
{
hashValue += 32;
}
if (dungeon2DArray[xIndex, yIndex - 1] == centerTile)
{
hashValue += 64;
}
if (dungeon2DArray[xIndex + 1, yIndex - 1] == centerTile)
{
hashValue += 128;
}
return hashValue;
}
我的问题是,是否有一种我可能没有想到的更有效、更快速的方法来进行这些检查?地牢数组的大小范围为 100x100 到 1000x1000,但不会在每个单元格上调用该函数。我有一个单独的列表,其中包含房间,并且每个方向都有开始和结束索引,我迭代这些索引以实例化对象。
由于您使用数组构建地图,因此由于直接访问,访问时间是恒定的。因此,检查每个数组索引的过程很快。
有几件小事可以加快功能。
- Return 相应
if
语句中的 hashValue。这将删除几行代码。
- 通过删除
hashValue
变量并返回 hard-coded 值,将从进程中删除变量初始化。这比看起来更重要。创建和删除对象需要时间,大量时间。
xIndex
和 yIndex
可以成为对象的全局变量。 实施这个想法时要小心。 由于在检查特定条件时 xIndex 和 yIndex 没有改变,因此可以在对象中将它们设为全局。这减少了传入的参数数量。由于 Java 不通过引用传递,因此会创建一个大小相等的对象并将其传递给函数。一个简单的 int
不会对速度产生太大影响,但如果您有一个包含许多变量的对象,则需要更多时间来构建另一个具有同等价值的对象。
- 每项检查都可以移到一个单独的函数中。这主要有助于以后的可读性和调试。有一些速度优势,但它们取决于项目。通过观察对象 initialized/manipulated 的情况,通常可以强制某些条件为真。当不需要检查逻辑,不需要检查就可以得出结论时,需要的时间就更少了。
只是一些想法。如果你有时间研究,第二点和第三点使用来自 low latency/high frequency
的概念。另外,请注意其中一些概念未被视为最佳实践。
您所做的实际上是应用一种卷积形式。如果没有关于如何调用您的方法或如何使用返回的哈希值的更多上下文,您所做的似乎接近于迭代 3x3 网格的最有效方法。假设你的 dungeon2dArray 是一个 char[][] 并且是全局的,我认为这是更清晰和更简洁的(你必须根据迭代顺序调整如何解释结果总和)。
private int CellHashValue(int x, int y) {
int hashSum = 0; // Hash sum to return
int hashValue = 1; // Increases as power of 2 (1,2,4,8,...128)
char centerTile = dungeon2DArray[x, y]; // Cache center tile
for (int r = -1; r <= 1; r++) {
for (int c = -1; c <= 1; c++) {
if (r == 0 && c == 0) continue; // Skip center tile
if (dungeon2DArray[x + c, y + r] == centerTile) {
hashSum += hashValue;
}
hashValue *= 2; // Next power of two
//could also bit shift here instead
// hashValue <<= 1
}
}
return hashSum;
}
注意:此方法不进行任何边界检查,因此如果 x 或 y 索引沿边,索引将失败。
每次访问数组的时间复杂度为 O(1),遍历整个地牢数组的时间复杂度为 O(n^2),因此提高效率的唯一方法是合并每个单元格的方法调用,但这是仍然只是一个常数因子,所以并没有真正提高效率,但是根据计算可以稍微提高性能。
我正在开发随机地牢生成器只是为了好玩/作为学习一些新事物的辅助项目。我已经编写了一个函数,该函数 returns 是任何给定单元格的整数哈希值,它为您提供有关它应该是什么类型的游戏对象的信息。即如果它是一堵墙,面对什么方向,它是一个角落,等等。这是函数目前的样子。
private int CellHashValue(int xIndex, int yIndex, char centerTile)
{
int hashValue = 0;
if (dungeon2DArray[xIndex - 1, yIndex + 1] == centerTile)
{
hashValue += 1;
}
if (dungeon2DArray[xIndex, yIndex + 1] == centerTile)
{
hashValue += 2;
}
if (dungeon2DArray[xIndex + 1, yIndex + 1] == centerTile)
{
hashValue += 4;
}
if (dungeon2DArray[xIndex - 1, yIndex] == centerTile)
{
hashValue += 8;
}
if (dungeon2DArray[xIndex + 1, yIndex] == centerTile)
{
hashValue += 16;
}
if (dungeon2DArray[xIndex - 1, yIndex - 1] == centerTile)
{
hashValue += 32;
}
if (dungeon2DArray[xIndex, yIndex - 1] == centerTile)
{
hashValue += 64;
}
if (dungeon2DArray[xIndex + 1, yIndex - 1] == centerTile)
{
hashValue += 128;
}
return hashValue;
}
我的问题是,是否有一种我可能没有想到的更有效、更快速的方法来进行这些检查?地牢数组的大小范围为 100x100 到 1000x1000,但不会在每个单元格上调用该函数。我有一个单独的列表,其中包含房间,并且每个方向都有开始和结束索引,我迭代这些索引以实例化对象。
由于您使用数组构建地图,因此由于直接访问,访问时间是恒定的。因此,检查每个数组索引的过程很快。
有几件小事可以加快功能。
- Return 相应
if
语句中的 hashValue。这将删除几行代码。 - 通过删除
hashValue
变量并返回 hard-coded 值,将从进程中删除变量初始化。这比看起来更重要。创建和删除对象需要时间,大量时间。 xIndex
和yIndex
可以成为对象的全局变量。 实施这个想法时要小心。 由于在检查特定条件时 xIndex 和 yIndex 没有改变,因此可以在对象中将它们设为全局。这减少了传入的参数数量。由于 Java 不通过引用传递,因此会创建一个大小相等的对象并将其传递给函数。一个简单的int
不会对速度产生太大影响,但如果您有一个包含许多变量的对象,则需要更多时间来构建另一个具有同等价值的对象。- 每项检查都可以移到一个单独的函数中。这主要有助于以后的可读性和调试。有一些速度优势,但它们取决于项目。通过观察对象 initialized/manipulated 的情况,通常可以强制某些条件为真。当不需要检查逻辑,不需要检查就可以得出结论时,需要的时间就更少了。
只是一些想法。如果你有时间研究,第二点和第三点使用来自 low latency/high frequency
的概念。另外,请注意其中一些概念未被视为最佳实践。
您所做的实际上是应用一种卷积形式。如果没有关于如何调用您的方法或如何使用返回的哈希值的更多上下文,您所做的似乎接近于迭代 3x3 网格的最有效方法。假设你的 dungeon2dArray 是一个 char[][] 并且是全局的,我认为这是更清晰和更简洁的(你必须根据迭代顺序调整如何解释结果总和)。
private int CellHashValue(int x, int y) {
int hashSum = 0; // Hash sum to return
int hashValue = 1; // Increases as power of 2 (1,2,4,8,...128)
char centerTile = dungeon2DArray[x, y]; // Cache center tile
for (int r = -1; r <= 1; r++) {
for (int c = -1; c <= 1; c++) {
if (r == 0 && c == 0) continue; // Skip center tile
if (dungeon2DArray[x + c, y + r] == centerTile) {
hashSum += hashValue;
}
hashValue *= 2; // Next power of two
//could also bit shift here instead
// hashValue <<= 1
}
}
return hashSum;
}
注意:此方法不进行任何边界检查,因此如果 x 或 y 索引沿边,索引将失败。
每次访问数组的时间复杂度为 O(1),遍历整个地牢数组的时间复杂度为 O(n^2),因此提高效率的唯一方法是合并每个单元格的方法调用,但这是仍然只是一个常数因子,所以并没有真正提高效率,但是根据计算可以稍微提高性能。