我如何根据 c++ 中的行合并两个 2D 数组

How I can merge two 2D arrays according to row in c++

本文关键字:两个 数组 2D 合并 何根 c++      更新时间:2023-10-16

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

第一个阵列 ->

1 2 
3 4 
5 6 
7 8 
9 10

第 2 个阵列>

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

发布的代码中有三个主要问题

  • abans被声明为可变长度数组(它们的大小在编译时是未知的(,这是一些编译器提供的非标准扩展。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
    }
    }
    

在以下代码片段中,演示了一个替代实现,其中矩阵使用类建模,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';
}

所以你有 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;
}
}

这里有一种方法可以做到这一点...我已经使它足够通用,以至于它可以处理行数不相等的数组。 未填充的点初始化为零。

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'object' 的源文件

#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 arean");
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 %dn", 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 %dn", result);
free(retHandle->data);
free(retHandle);
return (result);
}
}
}
*newHandlePtr = retHandle;
return (0);
}

matrix-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 *) = %dn", sizeof(void *));
printf("sizeof(int) = %dnn", 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 %dn", 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("nnTrying same thing using MATRIX objectnn");
result = MATRIX_Create(&leftMatrix, sizeof(int), leftRows, leftCols);
if (result != 0) {
printf("ERROR -- MATRIX_Create(leftMatrix) returned %dn", result);
return (result);
}
result = MATRIX_Create(&rightMatrix, sizeof(int), rightRows, rightCols);
if (result != 0) {
printf("ERROR -- MATRIX_Create(rightMatrix) returned %dn", 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,%dn", 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 %dn", 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 函数中。

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