Language agnostic 什么样的数据结构可以有效地存储二维数据;网格“;数据?
我正在尝试编写一个在数字网格上执行操作的应用程序,其中每次函数运行时,每个单元格的值都会发生变化,并且每个单元格的值取决于它的邻居。每个单元格的值都是一个简单的整数 在这里存储数据的最佳方式是什么?我考虑过平面列表/数组结构,但这似乎没有效果,因为我必须反复计算出哪个单元格“高于”当前单元格(当存在任意网格大小时)和嵌套列表,这似乎不是表示数据的很好方法 我忍不住觉得,为了达到这种目的,必须有更好的方法在内存中表示这些数据。有什么想法吗Language agnostic 什么样的数据结构可以有效地存储二维数据;网格“;数据?,language-agnostic,data-structures,Language Agnostic,Data Structures,我正在尝试编写一个在数字网格上执行操作的应用程序,其中每次函数运行时,每个单元格的值都会发生变化,并且每个单元格的值取决于它的邻居。每个单元格的值都是一个简单的整数 在这里存储数据的最佳方式是什么?我考虑过平面列表/数组结构,但这似乎没有效果,因为我必须反复计算出哪个单元格“高于”当前单元格(当存在任意网格大小时)和嵌套列表,这似乎不是表示数据的很好方法 我忍不住觉得,为了达到这种目的,必须有更好的方法在内存中表示这些数据。有什么想法吗 (注意,我不认为这是一个主观的问题-但堆栈溢出似乎认为是.
(注意,我不认为这是一个主观的问题-但堆栈溢出似乎认为是..我有点希望这类数据有一种可接受的存储方式)动态分配的数组使指向当前单元格上方的单元格变得很简单,并且还支持任意网格大小。如果查找时间对您很重要,那么二维数组可能是您的最佳选择,因为在给定单元格的(x,y)坐标的情况下,查找单元格的邻居是一个恒定的时间操作。以下是一些方法。我将(尝试)用3x3网格的表示来说明这些示例 平面阵列 要访问左侧或右侧的元素,请减去或添加1(注意行边界)。要访问上面或下面的元素,请减去或添加行大小(在本例中为3) 二维数组(适用于支持此功能的C或FORTRAN等语言) 访问相邻元素只是增加或减少行数或列数。编译器仍在执行与平面数组中完全相同的算法 数组的数组(如Java) 在这个方法中,“行指针”列表(在左边表示)每个都是一个新的独立数组。与二维数组一样,通过调整适当的索引来访问相邻元素 全链接单元格(二维双链接列表)
+--++--++---+
| 0 |-->| 1 |-->| 2 |
| || 5 |
| || 8 |
||在我的评论之后,您可能会发现算法很有趣
基本上(如果我理解正确的话),您可以将数据存储在一个四叉树中,其中一个哈希表指向树的节点。这里的想法是,相同的模式可能在网格中出现多次,并且每个副本将散列到相同的值,因此您只需计算一次
这对生活来说是真实的,它是一个由虚假的布尔人组成的网格。我不知道你的问题是否属实。你应该从存储数据的方式中提取信息。
如果您需要在数组中执行相对操作,Slice是执行此操作的常用模式。
你可以有这样的东西:
public interface IArray2D<T>
{
T this[int x, int y] { get; }
}
public class Array2D<T> : IArray2D<T>
{
readonly T[] _values;
public readonly int Width;
public readonly int Height;
public Array2D(int width, int height)
{
Width = width;
Height = height;
_values = new T[width * height];
}
public T this[int x, int y]
{
get
{
Debug.Assert(x >= 0);
Debug.Assert(x < Width);
Debug.Assert(y >= 0);
Debug.Assert(y < Height);
return _values[y * Width + x];
}
}
public Slice<T> Slice(int x0, int y0)
{
return new Slice<T>(this, x0, y0);
}
}
public class Slice<T> : IArray2D<T>
{
readonly IArray2D<T> _underlying;
readonly int _x0;
readonly int _y0;
public Slice(IArray2D<T> underlying, int x0, int y0)
{
_underlying = underlying;
_x0 = x0;
_y0 = y0;
}
public T this[int x, int y]
{
get { return _underlying[_x0 + x, _y0 + y]; }
}
}
公共接口IArray2D
{
T这个[intx,inty]{get;}
}
公共类数组2d:IArray2D
{
只读T[]_值;
公共只读整型宽度;
公共只读int高度;
公共阵列2d(整数宽度、整数高度)
{
宽度=宽度;
高度=高度;
_值=新T[宽度*高度];
}
公共T这个[int x,int y]
{
得到
{
断言(x>=0);
Assert(x=0);
断言(y<高度);
返回_值[y*宽度+x];
}
}
公共切片(int x0,int y0)
{
返回新切片(this,x0,y0);
}
}
公共类切片:IArray2D
{
只读IArray2D\u底层;
只读int_x0;
只读int_y0;
公共切片(IArray2D底层、int x0、int y0)
{
_潜在的=潜在的;
_x0=x0;
_y0=y0;
}
公共T这个[int x,int y]
{
获取{return}
}
}
+1超过John的答案,这也是正确的,但取决于语言,二维数组和数组数组数组(锯齿数组)之间存在差异。在大多数直接支持二维数组的语言中,数组数组的使用是一件很痛苦的事情。+1-您为“确定当前单元格上方的单元格”所做的计算量很小-它与取消引用指针没有太大区别,而且数组的开销也没有其他更广泛链接的结构那么大。在大多数情况下,询问“最佳”的方法是主观的。但我认为在这种情况下,这是非常明确的。你所做的很像细胞自动机。你可以用你最喜欢的语言追踪康威生活的开源实现,看看他们在做什么。哇,这就是答案。你非常努力地回答这个问题+1.
+-----+-----+-----+
| 0,0 | 0,1 | 0,2 |
+-----+-----+-----+
| 1,0 | 1,1 | 1,2 |
+-----+-----+-----+
| 2,0 | 2,1 | 2,2 |
+-----+-----+-----+
a[row,column]
a[row][column]
+---+ +---+---+---+
| 0 |-->| 0 | 1 | 2 |
+---+ +---+---+---+
| 1 |-->| 0 | 1 | 2 |
+---+ +---+---+---+
| 2 |-->| 0 | 1 | 2 |
+---+ +---+---+---+
a[row][column]
+---+ +---+ +---+
| 0 |-->| 1 |-->| 2 |
| |<--| |<--| |
+---+ +---+ +---+
^ | ^ | ^ |
| v | v | v
+---+ +---+ +---+
| 3 |-->| 4 |-->| 5 |
| |<--| |<--| |
+---+ +---+ +---+
^ | ^ | ^ |
| v | v | v
+---+ +---+ +---+
| 6 |-->| 7 |-->| 8 |
| |<--| |<--| |
+---+ +---+ +---+
public interface IArray2D<T>
{
T this[int x, int y] { get; }
}
public class Array2D<T> : IArray2D<T>
{
readonly T[] _values;
public readonly int Width;
public readonly int Height;
public Array2D(int width, int height)
{
Width = width;
Height = height;
_values = new T[width * height];
}
public T this[int x, int y]
{
get
{
Debug.Assert(x >= 0);
Debug.Assert(x < Width);
Debug.Assert(y >= 0);
Debug.Assert(y < Height);
return _values[y * Width + x];
}
}
public Slice<T> Slice(int x0, int y0)
{
return new Slice<T>(this, x0, y0);
}
}
public class Slice<T> : IArray2D<T>
{
readonly IArray2D<T> _underlying;
readonly int _x0;
readonly int _y0;
public Slice(IArray2D<T> underlying, int x0, int y0)
{
_underlying = underlying;
_x0 = x0;
_y0 = y0;
}
public T this[int x, int y]
{
get { return _underlying[_x0 + x, _y0 + y]; }
}
}