【问题标题】:How I can merge two 2D arrays according to row in c++如何根据 C++ 中的行合并两个二维数组
【发布时间】:2020-05-24 05:33:42
【问题描述】:

我面临一个问题,两个二维数组需要根据给定条件合并,其中n=5k=3

第一个数组->

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

结果数组->

 1 2 11 12 13 
 3 4 14 15 16 
 5 6 17 18 19
 7 8 20 21 22
 9 10 23 24 25

我解决这个问题的方法是首先取一个上述两个数组维度的空二维数组,然后将两个数组元素按索引放入ans 数组中。我可以将第一个数组放入ans 数组中,但未能将第二个数组放入结果数组中。它显示插入第二个数组的运行时错误。我需要帮助。

#include <iostream>
using namespace std;

int main()
{
    int n, k;
    cin >> n >> k;
    int p = n - k + 1, q = n - k;
    int a[n + 1][q + 1], b[n + 1][p + 1], ans[n + 1][n + 1];
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= q; ++j)
            a[i][j] = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= p; ++j)
            b[i][j] = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            ans[i][j] = 0;

    int x = 1;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= q; ++j)
            a[i][j] = x++;
    }
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= p; ++j)
            b[i][j] = x++;
    }
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= q; ++j)
            ans[i][j] = a[i][j];
    }
    int I = 1, J = 0;
    for (int i = 1; i <= n; ++i)
    {
        I += 2, J++;
        for (int j = 1; j <= p; ++j)
        {
            ans[I][J] = b[i][j];
            I++;
        }
    }
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= q; ++j)
            cout << a[i][j] << " ";
        cout << endl;
    }
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= p; ++j)
            cout << b[i][j] << " ";
        cout << endl;
    }
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= n; ++j)
            cout << ans[i][j] << " ";
        cout << endl;
    }

    return 0;
}

【问题讨论】:

  • C++ 中的数组是从 0 开始的。不要再试图通过浪费第一个元素来假装它们是从 1 开始的。
  • 请注意abq 被声明为可变长度数组(它们的大小在编译时未知),这是一些编译器提供的non-standard 扩展。你应该使用像std::vector这样的标准容器或者实现一个类。

标签: c++ arrays matrix multidimensional-array


【解决方案1】:

贴出的代码主要存在三个问题

  • abans 被声明为可变长度数组(它们的大小在编译时未知),一些编译器提供了 non-standard 扩展。 OP 可以使用像 std::vector 这样的标准容器或用户定义的类。

  • 所有循环都从 1 开始,而在 C++ 中,数组索引从 0 开始。这段代码的作者似乎知道这一事实,但出于某种原因,他更愿意在所有数组中分配额外的(未使用的)空间并相应地适应终止条件。

  • 试图将值从b 复制到ans 的嵌套循环是错误的,会导致多次访问越界。

    int I = 1, J = 0;                     // --->  I = 0, keeping OP's convention
    for (int i = 1; i <= n; ++i)
    {
        I += 2, J++;                      // --->  ++I, J = q
        for (int j = 1; j <= p; ++j)
        {
            ans[I][J] = b[i][j];
            I++;                          // ---> ++J
        }
    }
    

在下面的 sn-p 中显示了另一种实现,其中矩阵使用类建模,merge 函数执行所需的操作。

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <vector>

template <class T>
class Matrix
{
    size_t rows_{};
    size_t cols_{};
    std::vector<T> m_;
public:
    Matrix() = default;
    Matrix(size_t r, size_t c)
        : rows_{r}, cols_{c}, m_(r * c)
    {}

    auto rows() const noexcept {
        return rows_;
    }
    auto columns() const noexcept {
        return cols_;
    }
    auto operator[] (size_t i) noexcept {
        return m_.begin() + cols_ * i;
    }
    auto operator[] (size_t i) const noexcept {
        return m_.cbegin() + cols_ * i;
    }
    auto begin() noexcept {
        return m_.begin();
    }
    auto end() noexcept {
        return m_.end();
    }
};

template <class T>
std::ostream& operator<< (std::ostream& os, Matrix<T> const& m)
{
    for (size_t i{}; i < m.rows(); ++i)
    {
        for (size_t j{}; j < m.columns(); ++j)
            os << m[i][j] << ' ';
        os << '\n';
    }
    return os;
}

template<class T>
auto merge(Matrix<T> const& a, Matrix<T> const& b)
{
    if (a.rows() != b.rows())
        throw std::runtime_error{"Number of rows mismatch"};

    Matrix<T> result(a.rows(), a.columns() + b.columns());

    for (size_t i{}; i < a.rows(); ++i)
    {
        auto it = std::copy(a[i], a[i] + a.columns(), result[i]);
        std::copy(b[i], b[i] + b.columns(), it);
    }

    return result;
}


int main()
{
    int n, k;
    std::cin >> n >> k;
    int p = n - k + 1, q = n - k;

    Matrix<int> a(n, q);
    std::iota(a.begin(), a.end(), 1);
    std::cout << a << '\n';

    Matrix<int> b(n, p);
    std::iota(b.begin(), b.end(), n * q + 1);
    std::cout << b << '\n';

    auto c = merge(a, b);
    std::cout << c << '\n';
}

【讨论】:

    【解决方案2】:

    所以你有 3 个矩阵,每个矩阵都有 n 行。

    第一个矩阵有m=2 列。

    第二个矩阵有k=3 列。

    第三个矩阵(合并后的)有m+k 列。

    你的代码应该是这样的:

    #include <iostream>
    using namespace std;
    
    int main()
    {
      const int k=3;
      const int m=2;
      const int n=5;
    
      int arr1[n][m];
      int arr2[n][k];
      int arr3[n][m+k];
    
      for(int i=0; i<n; i++)
        for (int j=0; j<m; j++)
          arr1[i][j]=1+2*i+j;
    
      for(int i=0; i<n; i++)
        for (int j=0; j<k; j++)
          arr2[i][j]=11+3*i+j;
    
      for(int i=0; i<n; i++)
        for (int j=0; j<n; j++){
          if(j<m)
            arr3[i][j]=arr1[i][j];
          else
            arr3[i][j]=arr2[i][j-m];
        }
    
      for(int i=0; i<n; i++){
        for (int j=0; j<n; j++)
          cout<< arr3[i][j]<<" ";
        cout<<endl;
      }
    }
    

    【讨论】:

      【解决方案3】:

      这是一种实现方式...我已经将它变得足够通用,以至于它可以处理行数不相等的数组。未填充的点被初始化为零。

      MATRIX.h -- MATRIX“对象”的头文件

      #ifndef _MATRIX_H_
      #define _MATRIX_H_
          typedef struct matrix {
              int   rows;
              int   cols;
              int   elemSize;
              void  *data;
          } *MATRIX;
      
          int   MATRIX_Create( MATRIX *handlePtr, int initElemSize,
                               int initRows, int initCols );
          int   MATRIX_Close( MATRIX *handlePtr );
          int   MATRIX_Set( MATRIX handle, int row, int col, void *data );
          void  *MATRIX_GetAddr( MATRIX handle, int row, int col );
          int   MATRIX_Get( MATRIX handle, int row, int col, void *retData );
          int   MATRIX_Merge( MATRIX *newHandlePtr, MATRIX leftHandle, MATRIX rightHandle );
      #endif
      

      MATRIX.c -- MATRIX“对象”的源文件

      #include <stdio.h>
      #include <malloc.h>
      #include <memory.h>
      #include "MATRIX.h"
      
      #define MAX(x,y) ((x > y) ? x : y)
      
      int  MATRIX_Create( MATRIX *handlePtr, int initElemSize, int initRows, int initCols )
      {
          MATRIX  handle;
      
          if (handlePtr == NULL)
              return (-1);
      
          handle = calloc(sizeof(struct matrix), 1);
          if (handle == NULL)
              return (-2);
      
          handle->data = calloc(initElemSize, initRows * initCols);
          if (handle->data == NULL) {
              printf("ERROR -- Could not create MATRIX data area\n");
              free(handle);
              return (-3);
          }
      
          handle->rows = initRows;
          handle->cols = initCols;
          handle->elemSize = initElemSize;
      
          *handlePtr = handle;
      
          return (0);
      }
      
      int  MATRIX_Close( MATRIX *handlePtr )
      {
          if (handlePtr == NULL)
              return (-1);
      
          free(*handlePtr);
          *handlePtr = NULL;
      
          return (0);
      }
      
      int  MATRIX_Set( MATRIX handle, int row, int col, void *data )
      {
          unsigned char  *addr;
          int            addrOffset;
      
          if ((handle == NULL) || (data == NULL))
              return (-1);
      
          addr = handle->data;
          addrOffset = row * handle->cols * handle->elemSize + (col * handle->elemSize);
          addr += addrOffset;
      
          memcpy(addr, data, handle->elemSize);
      
          return (0);
      }
      
      void  *MATRIX_GetAddr( MATRIX handle, int row, int col )
      {
          unsigned char  *addr;
          int            addrOffset;
      
          if (handle == NULL)
              return (NULL);
      
          addr = handle->data;
          addrOffset = row * handle->cols * handle->elemSize + (col * handle->elemSize);
          addr += addrOffset;
      
          return (addr);
      }
      
      int MATRIX_Get( MATRIX handle, int row, int col, void *retData )
      {
          unsigned char  *addr;
          int            addrOffset;
      
          if ((handle == NULL) || (retData == NULL))
              return (-1);
      
          addr = MATRIX_GetAddr(handle, row, col);
      
          memcpy(retData, addr, handle->elemSize);
      
          return (0);
      }
      
      int  MATRIX_Merge( MATRIX *newHandlePtr, MATRIX leftHandle, MATRIX rightHandle )
      {
          int     i;
          int     j;
          MATRIX  retHandle;
          int     retCols;
          int     retRows;
          int     result;
      
          if ((newHandlePtr == NULL) || (leftHandle == NULL) || (rightHandle == NULL))
              return (-1);
      
          /* Ensure that the element sizes for the two matrices to be merged are the same */
          if (leftHandle->elemSize != rightHandle->elemSize)
              return (-2);
      
          retCols = leftHandle->cols + rightHandle->cols;
          retRows = MAX(leftHandle->rows, rightHandle->rows);
      
          result = MATRIX_Create(&retHandle, leftHandle->elemSize, retRows, retCols);
          if (result != 0)
              return (-3);
      
          /* First copy the left matrix into the merged array */
          for (i = 0; i < leftHandle->rows; i++) {
              for (j = 0; j < leftHandle->cols; j++) {
                  result = MATRIX_Set(retHandle, i, j, MATRIX_GetAddr(leftHandle, i, j));
                  if (result != 0) {
                      printf("ERROR -- MATRIX_Set() returned %d\n", result);
                      free(retHandle->data);
                      free(retHandle);
                      return (result);
                  }
              }
          }
      
          /* And then copy the right matrix into the merged array */
          for (i = 0; i < rightHandle->rows; i++) {
              for (j = 0; j < rightHandle->cols; j++) {
                  result = MATRIX_Set(retHandle, i, j+leftHandle->cols, MATRIX_GetAddr(rightHandle, i, j));
                  if (result != 0) {
                      printf("ERROR -- MATRIX_Set() returned %d\n", result);
                      free(retHandle->data);
                      free(retHandle);
                      return (result);
                  }
              }
          }
      
          *newHandlePtr = retHandle;
      
          return (0);
      }
      

      ma​​trix-test.c -- 测试代码的主程序文件

      #include <stdio.h>
      #include <malloc.h>
      #include <memory.h>
      #define MAX(x,y) ((x > y) ? x : y)
      
      int  MergeArray2D( int **retArrayPtr, int *retRowsPtr, int *retColsPtr,
                         int *leftArray, int leftRows, int leftCols,
                         int *rightArray, int rightRows, int rightCols )
      {
          int  *retArray;
          int  i;
          int  j;
          int  retCols;
          int  retRows;
      
          if ((retArrayPtr == NULL) || (retColsPtr == NULL) || (retRowsPtr == NULL) || (leftArray == NULL))
              return (-1);
      
          retCols = leftCols + rightCols;
          retRows = MAX(leftRows, rightRows);
      
          retArray = calloc(sizeof(int), retRows * retCols);
          if (retArray == NULL)
              return (-2);
      
          /* First copy the left array into the merged array */
          for (i = 0; i < leftRows; i++) {
              for (j = 0; j < leftCols; j++) {
                  retArray[i * retCols + j] = leftArray[i * leftCols + j];
              }
          }
      
          /* And then copy the right array into the merged array */
          for (i = 0; i < rightRows; i++) {
              for (j = 0; j < rightCols; j++) {
                  retArray[i*retCols + j + leftCols] = rightArray[i * rightCols + j];
              }
          }
      
          *retArrayPtr = retArray;
          *retColsPtr = retCols;
          *retRowsPtr = retRows;
      
          return (0);
      }
      
      void  PrintArray2D( int *array, int numRows, int numCols )
      {
          int  i;
          int  j;
      
          for (i = 0; i < numRows; i++) {
              for (j = 0; j < numCols; j++) {
                  printf(" %5d", array[i * numCols + j]);
              }
              printf("\n");
          }
      }
      
      int  main( int argc, char **argv )
      {
          int     leftRows = 5;
          int     leftCols = 2;
          int     leftArray[5][2];
          int     rightRows = 6;
          int     rightCols = 3;
          int     rightArray[6][3];
          int     i;
          int     j;
          int     count;
          int     result;
          int     *newArray;
          int     newRows;
          int     newCols;
          MATRIX  leftMatrix;
          MATRIX  rightMatrix;
          MATRIX  newMatrix;
      
          printf("sizeof(void *) = %d\n", sizeof(void *));
          printf("sizeof(int) = %d\n\n", sizeof(int));
          count = 0;
      
          /* Initialize the left array */
          for (i = 0; i < leftRows; i++) {
              for (j = 0; j < leftCols; j++) {
                  count++;
                  leftArray[i][j] = count;
              }
          }
      
          /* Initialize the right array */
          for (i = 0; i < rightRows; i++) {
              for (j = 0; j < rightCols; j++) {
                  count++;
                  rightArray[i][j] = count;
              }
          }
      
          /* Print out the left array */
          printf("Left Array:\n");
          PrintArray2D((int *) leftArray, leftRows, leftCols);
      
          /* Print out the right array */
          printf("\nRight Array:\n");
          PrintArray2D((int *) rightArray, rightRows, rightCols);
      
          /* Merge the two arrays */
          result = MergeArray2D(&newArray, &newRows, &newCols, (int *) leftArray, leftRows, leftCols, (int *) rightArray, rightRows, rightCols);
          if (result != 0) {
              printf("ERROR -- MergeArrays2D() returned %d\n", result);
          }
      
          /* Print out the merged array */
          printf("\nMerged Array:\n");
          PrintArray2D(newArray, newRows, newCols);
      
          /* Clean up the allocated merged array when through using it */
          free(newArray);
      
          /* And now for a way of doing the same thing with the MATRIX object */
          printf("\n\nTrying same thing using MATRIX object\n\n");
          result = MATRIX_Create(&leftMatrix, sizeof(int), leftRows, leftCols);
          if (result != 0) {
              printf("ERROR -- MATRIX_Create(leftMatrix) returned %d\n", result);
              return (result);
          }
      
          result = MATRIX_Create(&rightMatrix, sizeof(int), rightRows, rightCols);
          if (result != 0) {
              printf("ERROR -- MATRIX_Create(rightMatrix) returned %d\n", result);
              return (result);
          }
      
          /* Initialize the left matrix */
          count = 0;
          for (i = 0; i < leftMatrix->rows; i++) {
              for (j = 0; j < leftMatrix->cols; j++) {
                  count++;
                  result = MATRIX_Set(leftMatrix, i, j, &count);
                  if (result != 0)
                      printf("ERROR -- Could not set element %d,%d\n", i, j);
              }
          }
      
          /* Print out the left matrix */
          printf("\nLeft Matrix[rows=%d,cols=%d,elemSize=%d]:\n", leftMatrix->rows, leftMatrix->cols, leftMatrix->elemSize);
          PrintArray2D(leftMatrix->data, leftMatrix->rows, leftMatrix->cols);
      
          /* Initialize the right matrix */
          for (i = 0; i < rightMatrix->rows; i++) {
              for (j = 0; j < rightMatrix->cols; j++) {
                  count++;
                  result = MATRIX_Set(rightMatrix, i, j, &count);
              }
          }
      
          /* Print out the right matrix */
          printf("\nRight Matrix[rows=%d,cols=%d,elemSize=%d]:\n", rightMatrix->rows, rightMatrix->cols, rightMatrix->elemSize);
          PrintArray2D(rightMatrix->data, rightMatrix->rows, rightMatrix->cols);
      
          /* Merge the two matrices */
          result = MATRIX_Merge(&newMatrix, leftMatrix, rightMatrix);
          if (result != 0) {
              printf("ERROR -- MATRIX_Merge() returned %d\n", result);
              return (result);
          }
      
          /* Print out the new matrix */
          printf("\nMerged Matrix[rows=%d,cols=%d,elemSize=%d]:\n", newMatrix->rows, newMatrix->cols, newMatrix->elemSize);
          PrintArray2D(newMatrix->data, newMatrix->rows, newMatrix->cols);
      
          /* Cleanup the newMatrix when finished */
          result = MATRIX_Close(&newMatrix);
      }
      

      测试程序的输出:

      sizeof(void *) = 4
      sizeof(int) = 4
      
      Left Array:
           1     2
           3     4
           5     6
           7     8
           9    10
      
      Right Array:
          11    12    13
          14    15    16
          17    18    19
          20    21    22
          23    24    25
          26    27    28
      
      Merged Array:
           1     2    11    12    13
           3     4    14    15    16
           5     6    17    18    19
           7     8    20    21    22
           9    10    23    24    25
           0     0    26    27    28
      
      
      Trying same thing using MATRIX object
      
      
      Left Matrix[rows=5,cols=2,elemSize=4]:
           1     2
           3     4
           5     6
           7     8
           9    10
      
      Right Matrix[rows=6,cols=3,elemSize=4]:
          11    12    13
          14    15    16
          17    18    19
          20    21    22
          23    24    25
          26    27    28
      
      Merged Matrix[rows=6,cols=5,elemSize=4]:
           1     2    11    12    13
           3     4    14    15    16
           5     6    17    18    19
           7     8    20    21    22
           9    10    23    24    25
           0     0    26    27    28
      

      为了使其成为通用解决方案,我将 2D 数组视为 1D 数组,因为这就是它们在内存中的布局方式。如果你不想要一个通用的解决方案,你应该很容易修改代码,你不会有太多的参数需要传递给 MergeArray2D 函数。

      编辑: 我通过创建矩阵“对象”的“C”版本添加了一个更通用的解决方案,就像我通过休斯顿的一个航空航天承包商为 NASA 工作时在后面实现“对象”一样。我还将“对象”的头文件和源文件拆分为单独的代码窗口,以便于阅读。对于任何 C++ 人来说,将其转换为 C++ 类可能都是一件小事,但我认为从教学的角度来看,直接使用“C”会更好。这个“对象”允许使用不同于第一个示例中使用的“int”的不同基本元素数据大小来“实例化”它。我已经在 PC 上使用 gcc 测试了代码,它实际上可以正确编译和运行。希望这会有所帮助...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多