在C语言中获取多维数组列的最有效方法

在C语言中获取多维数组列的最有效方法,c,performance,matrix,C,Performance,Matrix,我正在尝试用C创建一个矩阵数据结构。我有一个结构,并且有一个二维的void指针数组(大小在堆中动态定义),用于这个结构中的货物部分(数据) 给定一个列索引,我想得到一维数组中该列的值。使用一个for或while循环很容易实现这一点。但是如果这个矩阵中的行数是N,那么获取列向量需要O(N)个时间。我能用memcpy这样的内存操作更有效地实现这一点吗?否则,我如何提高性能(我的数据是非常结构化的,我需要将其存储在某种矩阵中)。如果列中的行数为N,则无法在少于O(N)的时间内复制、读取或以其他方式操作

我正在尝试用C创建一个矩阵数据结构。我有一个结构,并且有一个二维的void指针数组(大小在堆中动态定义),用于这个结构中的货物部分(数据)


给定一个列索引,我想得到一维数组中该列的值。使用一个for或while循环很容易实现这一点。但是如果这个矩阵中的行数是N,那么获取列向量需要O(N)个时间。我能用memcpy这样的内存操作更有效地实现这一点吗?否则,我如何提高性能(我的数据是非常结构化的,我需要将其存储在某种矩阵中)。

如果列中的行数为N,则无法在少于O(N)的时间内复制、读取或以其他方式操作整个列。这是一个确定的下限;必须考虑每个元素,其中有N个元素

所以不,你不能使它比O(N)快

请注意,对于已知大小的2D数组,编译器会将
x[3][5]
转换为
x+((3*num\u cols)+5)*元素的大小。因此,提高阵列速度的一种方法是删除其动态大小调整


另一个重要的一点是,对内存的顺序访问并不总是最快的——因此,仅将阵列旋转90度并不一定能获得最佳结果。将阻塞视为一种优化技术。底线:最佳内存布局取决于访问模式和硬件参数,如缓存线长度和缓存大小。

如果列中的行数为N,则无法在少于O(N)的时间内复制、读取或以其他方式操作整个列。这是一个确定的下限;必须考虑每个元素,其中有N个元素

所以不,你不能使它比O(N)快

请注意,对于已知大小的2D数组,编译器会将
x[3][5]
转换为
x+((3*num\u cols)+5)*元素的大小。因此,提高阵列速度的一种方法是删除其动态大小调整


另一个重要的一点是,对内存的顺序访问并不总是最快的——因此,仅将阵列旋转90度并不一定能获得最佳结果。将阻塞视为一种优化技术。一句话:什么样的内存布局最好取决于您的访问模式和硬件参数,如缓存线长度和缓存大小。

正如Borelid所说,您无法改进O(N)。但是,如果对数据重新排序,使行为列,列为行,则可以加快复制操作。这将允许您使用memcpy来复制数据。

正如Borealid所说,您无法改进O(N)。但是,如果对数据重新排序,使行为列,列为行,则可以加快复制操作。这将允许您使用memcpy复制数据。

我的解决方案:

  • 不要使用多维数组。它们在C99之前是不灵活的(不能改变所有的维度),并且妨碍执行以下高效操作。相反,只需使用一维数组并自己执行元素索引算法即可

  • 现在,您可以设置一个指针
    src
    ,指向列的第一个元素(
    src=&matrix[row*ncols+col];
    ),并使用:
    为(i=0;i我的解决方案:

  • 不要使用多维数组。它们在C99之前是不灵活的(不能改变所有维度),无法执行以下高效操作。相反,只需使用一维数组并自己执行元素索引算法即可


  • 现在,您可以设置一个指针
    src
    ,指向列的第一个元素(
    src=&matrix[row*ncols+col];
    ),并使用:
    for(i=0;i复制列如果要复制矩阵中的数据,则不能在少于O(N)的时间内完成时间,无论是行还是列,除了硬件功能可能有帮助的小N

    但是,如果矩阵是不可变的,则可以使用烟雾和镜像来产生具有单独列向量的错觉

    下面的代码直接输入到“答案”文本框中,甚至尚未编译。使用时请自行承担风险!

    矩阵类型定义为结构,因此:

    typedef struct 
    {
        unsigned int refCount;  // how many Matrixes are referencing this data ref
        size_t lineWidth;       // number of doubles between element at row = n, col = 0 and row = n +1, col = 0 
        double* data;           // the actual data
    } DataRef;
    
    typedef struct
    {
        size_t rows;            // num rows in matrix
        size_t cols;            // num cols in matrix
        size_t dataOffset;      // offset in doubles from the start of data of element at row = 0, col = 0
        DataRef* data;
    } Matrix;
    
    创建一个全新的矩阵(为了简化,我省略了所有的错误处理)

    访问元素(同样没有错误处理,例如边界错误)

    从另一个矩阵的矩形区域创建新矩阵(同样,需要错误处理)

    要从另一个矩阵中的列创建新矩阵,请执行以下操作:

    Matrix* vector = matrix_createFromRegion(aMatrix, 0, colYouWant, matrix_numRows(aMatrix), 1);
    
    释放矩阵

    void matrix_free(Matrix* aMatrix)
    {
        if (aMatrix->data->refCount == 1)
        {
            free(aMatrix->data->data);
            free(aMatrix->data);
        }
        else
        {
            aMatrix->data->refCount--;
        }
        free(aMatrix);
    }
    
    如果需要可变矩阵,则在任何时候修改元素时,检查refCount,如果大于1,则在修改之前复制DataRef(减少旧DataRef上的refCount),否则就地修改DataRef


    现在,上述方法使用了大量malloc,因此可能比小矩阵的简单实现效率更低。但是,您可以维护一个未使用的DataRef结构和矩阵结构的列表,而不是在完成时释放它们,而是将它们放在自由列表中。分配新的结构时,从自由列表中获取结构,除非它们是空的。这样,获取表示现有矩阵的列的矩阵通常需要固定的时间。

    如果要复制矩阵中的数据,无论是行还是列,都不能在少于O(N)的时间内完成,但硬件功能可能会有所帮助的小N除外

    但是,如果矩阵是不可变的,则可以使用烟雾和镜像来产生具有单独列向量的错觉

    下面的代码直接输入到“答案”文本框中,甚至尚未编译。使用时请自行承担风险!

    矩阵类型定义为结构,因此:

    typedef struct 
    {
        unsigned int refCount;  // how many Matrixes are referencing this data ref
        size_t lineWidth;       // number of doubles between element at row = n, col = 0 and row = n +1, col = 0 
        double* data;           // the actual data
    } DataRef;
    
    typedef struct
    {
        size_t rows;            // num rows in matrix
        size_t cols;            // num cols in matrix
        size_t dataOffset;      // offset in doubles from the start of data of element at row = 0, col = 0
        DataRef* data;
    } Matrix;
    
    创建一个全新的矩阵(I
    Matrix* vector = matrix_createFromRegion(aMatrix, 0, colYouWant, matrix_numRows(aMatrix), 1);
    
    void matrix_free(Matrix* aMatrix)
    {
        if (aMatrix->data->refCount == 1)
        {
            free(aMatrix->data->data);
            free(aMatrix->data);
        }
        else
        {
            aMatrix->data->refCount--;
        }
        free(aMatrix);
    }