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]; }
    }
}