【问题标题】:Delete any number of Columns in 2D dynamic array and resize the matrix size after column deletion删除二维动态数组中的任意数量的列,并在列删除后调整矩阵大小
【发布时间】:2018-04-05 16:38:32
【问题描述】:

我正在尝试从我的 3D 动态数组的每个切片中删除前 20 列。我猜想尝试为 2D 动态数组编写一个函数将解决我将遍历 3D 数组的每个级别的问题。我在 stackoverflow 中有一个示例,我正在尝试使其工作。

但问题是函数不能删除整列。相反,它只删除一个元素。谁能告诉我如何从二维动态数组中删除整列?

void removeColumn(int** matrix, int col){ 
  MATRIX_WIDTH--;   
   for(int i=0;i<MATRIX_HEIGHT; i++)   {
    while(col<MATRIX_WIDTH)
    {
      //move data to the left
      matrix[i][col]=matrix[i][col+1];
      col++;
    }   matrix[i] = realloc(matrix[i], sizeof(double)*MATRIX_WIDHT);   }

我的预期输出就像 示例输入:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

样本输出:

1 3 4
5 7 8
9 11 12
13 15 16

更新:这是使用@frslm 建议后完全删除列的代码 但矩阵没有调整大小。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>


int** fill(size_t rows, size_t cols, int input[][cols])
{
    int i,j,count=1;
    int** result;
    result = malloc((rows)*sizeof(int*));
    for(i=0;i<rows;i++)
    {
        result[i]=malloc(cols*sizeof(int));
        for(j=0;j<cols;j++)
        {
            result[i][j]=count++;
        }
    }

    return result;
}


void printArray2D(size_t rows, size_t cols,int** input)
{
    int i,j;
    for(i=0;i<rows;i++)
    {
        for(j=0;j<cols;j++)
        {
            printf(" %4d",input[i][j]);
        }
        printf("\n");
    }
}

void removeColumn(int** matrix, int col2del , int rows, int cols){ 
    int MATRIX_WIDTH = cols;
    int MATRIX_HEIGHT = rows;

    MATRIX_WIDTH--;   
    for(int i=0;i<MATRIX_HEIGHT; i++) {
        int curr_col = col2del; 
        while(curr_col<MATRIX_WIDTH)
        {
            //move data to the left
            matrix[i][curr_col]=matrix[i][curr_col+1];
            curr_col++;
        }
        //matrix[i] = realloc(matrix[i], sizeof(int)*MATRIX_WIDTH); // <- int, not double
        matrix[i] = realloc(matrix[i], sizeof (matrix[i][0])*MATRIX_WIDTH); 
    }
}

int main()
{
    int arRow,arCol;
    arRow =8;
    arCol = 9;
    int ar[arRow][arCol];
    int **filled;
    filled = fill(arRow, arCol, ar);
    printArray2D(arRow,arCol,filled);
    removeColumn(filled, 3,arRow,arCol);
    printf("After 3rd Column Delete.......\n");
    printArray2D(arRow,arCol,filled);
    return(0);
}

输出:最后一列重复

    1    2    3    4    5    6    7    8    9
   10   11   12   13   14   15   16   17   18
   19   20   21   22   23   24   25   26   27
   28   29   30   31   32   33   34   35   36
   37   38   39   40   41   42   43   44   45
   46   47   48   49   50   51   52   53   54
   55   56   57   58   59   60   61   62   63
   64   65   66   67   68   69   70   71   72
After 3rd Column Delete.......
    1    2    3    5    6    7    8    9    9
   10   11   12   14   15   16   17   18   18
   19   20   21   23   24   25   26   27   27
   28   29   30   32   33   34   35   36   36
   37   38   39   41   42   43   44   45   45
   46   47   48   50   51   52   53   54   54
   55   56   57   59   60   61   62   63   63
   64   65   66   68   69   70   71   72   72

【问题讨论】:

  • int input[][cols] 未在 fill(size_t rows, size_t cols, int input[][cols]) 中使用。为什么要有那个参数?
  • @chux 有什么不同吗?但是,我实际上是在尝试学习传递数组的不同方法。
  • 它确实有所作为。在没有解释的情况下将未使用的参数传递给函数会减损和混淆问题。因此,需要澄清的问题。
  • MATRIX_WIDTH--; 应仅在 cols &lt; MATRIX_WIDTH 时出现。

标签: c


【解决方案1】:

您递增 col 直到它到达第一行的末尾,但您永远不会为后续行重置它,这就是您最终只删除第一行的列的原因。

确保在每次迭代开始时重置 col

void removeColumn(int** matrix, int col){ 
    MATRIX_WIDTH--;   
    for(int i=0;i<MATRIX_HEIGHT; i++) {
        int curr_col = col; // <- use a temporary `col` variable for each row
        while(curr_col<MATRIX_WIDTH)
        {
            //move data to the left
            matrix[i][curr_col]=matrix[i][curr_col+1];
            curr_col++;
        }
        matrix[i] = realloc(matrix[i], sizeof(int)*MATRIX_WIDTH); // <- int, not double
    }
}

编辑(响应 OP 的编辑):

确保removeColumn()在调整矩阵大小后更新列数(cols);一种方法是使用指针:int *cols 作为参数而不是int cols(调用此函数时不要忘记传入地址&amp;arCol)。另外,我建议去掉不必要的MATRIX_HEIGHT 变量:

void removeColumn(int** matrix, int col2del, int rows, int *cols){
    int MATRIX_WIDTH = --(*cols);

    for(int i=0;i<rows; i++) {
        int curr_col = col2del; 
        while(curr_col<MATRIX_WIDTH)
        {
            //move data to the left
            matrix[i][curr_col]=matrix[i][curr_col+1];
            curr_col++;
        }
        matrix[i] = realloc(matrix[i], sizeof(matrix[i][0])*MATRIX_WIDTH); 
    }
}

【讨论】:

  • 谢谢你:)。是的,现在它完全删除了整个列。但是还是有问题。整个 matrix_width 应该减少 1。这里最后一列正在复制自身。我怎样才能防止这种情况发生?
  • @Makau 您的realloc() 呼叫会调整您的行大小。由于您在函数开始时将 MATRIX_WIDTH 减 1,因此 realloc() 应该已经为您提供了少一列的行。如果您仍在访问该重复列的元素,那么您可能会访问超出范围的元素 - 此时您实际上遇到了未定义的行为。在这种情况下,不要访问重复的列;反正你是不允许的。
  • 而不是realloc(matrix[i], sizeof(int)*MATRIX_WIDTH)和希望代码使用正确的匹配类型,代码realloc(matrix[i], sizeof matrix[i][0] * MATRIX_WIDTH)来消除OP的编码错误,让代码更容易查看和维护。
  • @frslm 是的,我没有访问最后一列。但是正如你所说的那样,我们在开始时将 MATRIX_WIDTH 减少了 1,我应该得到最终矩阵的减小大小。但它没有发生。
  • @chux 我使用了你的代码块。但没有发生任何变化。
【解决方案2】:

如果传递宽度和高度,并更新宽度会更容易:

void removeColumn(int** matrix, int col, int* width, int height)
{
    int j, i;
    for (j = 0; j < height; ++j) {
        if (col == *width-1) {
            continue;
        }
        for (i = col; i < *width; ++i) {
            matrix[j][i] = matrix[j][i+1];
        }
        // this is not necessary, but I'm adding as requested
        matrix[j] = realloc(
            matrix[j],
            sizeof(int) * (*width - 1)
        );
    }
    --(*width);
}

您还可以避免动态内存分配,避免内存碎片整理:

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    int max_width, max_height;
    int width, height;
    int* values;
} matrix;

void removeColumn(matrix* matrix, int col)
{
    int y, i;
    for (y = 0; y < matrix->height; ++y) {
        if (col == matrix->width-1) {
            continue;
        }
        i = col + matrix->height * y;
        while (i < matrix->width) {
            matrix->values[i] = matrix->values[++i];
        }
    }
    --matrix->width;
}

void printMatrix(matrix* matrix)
{
    int y, x;
    for (y = 0; y < matrix->height; ++y) {
        for (x = 0; x < matrix->width; ++x) {
            printf("%d ", matrix->values[x + matrix->width * y]);
        }
        printf("\n");
    }
}

int main ()
{
    int y, x = 0;
    matrix matrix;
    matrix.max_width = 4;
    matrix.max_height = 4;
    matrix.width = 4;
    matrix.height = 4;
    int values[4][4];
    matrix.values = &values;
    for (y = 0; y < matrix.height; ++y) {
        for (x = 0; x < matrix.width; ++x) {
            int i = x + matrix.width * y;
            matrix.values[i] = i % 10;
        }
    }

    printMatrix(&matrix);
    removeColumn(&matrix, 1);
    printf("===\n");
    printMatrix(&matrix);
}

测试使用:https://www.tutorialspoint.com/compile_c_online.php

添加

但是当数组大小太大时,我们还有其他选择吗 但使用动态数组

如果你想创建一个可调整大小的数组,你可以在分配数组时使用单个malloc,当width 大于max_widthheight 大于时使用reallocmax_height.

尽管如此,我认为我们应该尽量避免使用 mallocrealloc 进行大量动态分配,因为它们很慢(尽管大多数时候你不会注意到),它们会严重地整理内存并且你这样做的方式会产生很多不必要的缓存未命中。

如果您不知道需要多次调整数组的大小,您还应该将它们扩大到超出要求的范围,例如以指数方式增长。这就是通常(正确)实现散列和动态数组的方式。

例如,您可能会发现一些没有动态内存的 JSON、XML 和 HTML C 库以避免其陷阱,并且在许多专业视频游戏中,可能会使用巨大的malloc 来避免其中的许多陷阱,而简单的数组是大量使用。

当然,您可以使用动态内存,但最好了解它的陷阱以便做出更好的决策。

【讨论】:

  • 谢谢。我会试试。但是当数组大小太大时,除了使用动态数组之外我们还有其他选择吗?像 1680*16*12 大小的 3D 数组。
  • 感谢您的时间和详细的回答:)
  • 不客气,@Makau。顺便说一句,使用简单指针(而不是双指针)和单个 malloc,您还可以允许具有任何指定维数的矩阵。这将需要更多的工作,但不会假设矩阵只有二维而不需要为每个维数实现一个函数。
猜你喜欢
  • 2018-07-10
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 2020-01-25
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多