分配不带递归的多维数组

Allocate a multidimensional array without recursion

本文关键字:数组 递归 分配      更新时间:2023-10-16

>假设我有一个任意大小的整数值数组,该数组指定要分配的数组的每个维度(级别)的元素数,如何在不诉诸递归的情况下分配数组?最好在没有递归的情况下执行此操作,以避免堆栈溢出。

因此,例如,如何完成这样的函数:

template <typename Type>
void* allocMulti (int numDim, int* numElementsPerDim)
{
    // 'Type' if one-dimensional, should be 'void*' otherwise
    void* multiArray = new Type[numElementsPerDim[0]];
    // ...
    return multiArray;
}

我正在寻找一种通用算法,该算法可以涵盖没有直接内存访问的语言。

如果数组实际上是一个矩阵(例如长度 AxB 而不是不同长度的数组列表),那么您可以分配长度为 A*B 的单个数组,而不是长度为 A 的数组,其中每个位置都是指向长度为 B 的数组的指针。

这也可以提高性能,因为内存是连续的(较少的分页)。

不过,您必须使用 a[y * B + x] 而不是 a[y][x] 访问每个单元格(假设 dim(a,0) = A 和 dim(a,1) = B。

我的C++有点生疏,但是,我相信这种方法可能会奏效:

T* AllocateMatrix(int dims, int[] dimLengths)
{
    // Assert dims >= 1
    int length = dims[0];
    for (int d = 1; d < dims; d++)
        length *= dims[d];
    return new T[length];
}
*T AccessMatrix(T* matrix, int dims, int[] dimLengths, int[] pos)
{
    // Assert dims >= 1
    int p = pos[0];
    for (int d = 1; d < dims; d++)
    {
        p = p * dimLengths[d] + pos[d];
    }
    return &matrix[p];
}

这是一种方法:将数据值分配为块,然后将(int *)的所有行分配为块,然后将(int **)行分配为块,依此类推。

a) 将所有数据值分配为一个块。如果在数组elementsPerDim中有nDim维度,则有prod = product(elementsPerDim, nDim)数据值(您可以轻松计算),因此您需要分配:

int prod = product(elementsPerDim, nDim);
int * intblock = calloc(prod, sizeof(int));

b) 分配所有(int*)。它们的数量等于除最后一个维度之外的所有维度的乘积,因此您可以简单地调用长度为 nDim-1product() 函数。所以有product(elementsPerDim, nDim-1)这样的值,每个值的大小sizeof (int*).让我们分配它们:

int npointers = product(elementsPerDim, nDim-1);
int ** ptrblock = calloc(npointers, sizeof (int *));

现在,您必须初始化它们以指向上一步中的块。每个指针都得到一个不重叠的 elementsPerDim[nDim-2] 整数块,如下所示:

int rowlength = elementsPerDim[nDim-2];
for (int i=0; i < npointers; i++)
    ptrblock[i] = & intblock[i * rowlength];   /* a.k.a. intblock + i*rowlength */

c) 向后迭代步骤 b,直到用完尺寸。即,通过此循环跟进步骤(b):

void ** prev_block = (void **) ptrblock;
void ** curblock;
for (int d = nDim-2; d > 0; d--) {
    int npointers = product(elementsPerDim, d);
    curblock = calloc(npointers, sizeof (void **));
    int rowlength = elementsPerDim[d-1];
    for (int i=0; i < npointers; i++)
        curblock[i] = & prev_block[i * rowlength];
    prev_block = curblock;  /* get ready for the next round */
}

完成后,curblock将是一个指向二级指针块的指针数组,依此类推,指向整数块。您可以使用普通数组表示法来取消引用它们: ptrblock[3][2][15]等。

我可能在某个地方得到了一个索引,但这应该是算法。您会注意到这是在 C 中,并且使用 void ** 而不是堆叠取消引用的数量。你确实说过你对算法感兴趣,而不是对高尔夫类型感兴趣......(只要计算机上的所有指针具有相同的大小,它就应该可以工作。