C++ 以不同方式乘以两个矩阵-can';我想不出怎么做

C++ 以不同方式乘以两个矩阵-can';我想不出怎么做,c++,arrays,algorithm,matrix,C++,Arrays,Algorithm,Matrix,作为家庭作业,我有一个问题,听起来像这样: We have a n*n square matrix. It is called 'subdiagonal' if all the elements above the main diagonal are null. a) Copy the useful elements (the ones which are not null, so basically all the elements from the main diagonal and b

作为家庭作业,我有一个问题,听起来像这样:

We have a n*n square matrix. It is called 'subdiagonal'
if all the elements above the main diagonal are null.

a) Copy the useful elements (the ones which are not null, so basically all the elements
 from the main diagonal and below) to an array. (I've done that)

b) Write an algorithm which takes two subdiagonal matrix A, B as an input.
 Those are transformed into arrays V_a and V_b with the algorithm from a),
 then they calculate C = A*B only using only V_a and V_b
e、 g

以下是我已经编写了一段时间的代码:

#include <iostream>
#include <algorithm>

void read(int& a, int**& matrix)
{
    std::cin >> a;
    matrix = new int*[a];
    for (int i = 0; i < a; i++)
    {
        for (int j = 0; j < a; j++)
        {
            matrix[i] = new int[a];
        }
    }
    for (int i = 0; i < a; i++)
    {
        for (int j = 0; j < a; j++)
        {
            std::cin >> matrix[i][j];
        }
    }
}

void showMatrix(int a, int** matrix)
{
    for (int i = 0; i < a; i++)
    {
        for (int j = 0; j < a; j++)
        {
            std::cout << matrix[i][j] << " ";
        }
        std::cout << std::endl;
    }
}

void showArray(int a, int* array)
{
    for (int i = 0; i < a; i++)
    {
        std::cout << array[i] << " ";
    }
}

void createArray(int a, int& arrayLength, int** matrix, int*& array)
{
    int nrDeElemente = a*a - (a * (a - 1)) / 2;
    array = new int[nrDeElemente+1];
    arrayLength = 0;
    for (int i = 0; i < a; i++)
    {
        for (int j = 0; j < i+1; j++)
        {
            array[arrayLength++] = matrix[i][j];
        }
    }
}

int* multiplyArrays(int a, int arrayLength, int* array1, int* array2)
{
    int* array3 = new int[arrayLength + 1];
    for (int i = 0; i < a; i++)
    {
        array3[i] = 0;
    }
    int t = 1;
    for (int i = 0; i < arrayLength; ++i)
    {
        for (int j = 0; j < t; ++j)
        {
            for (int p = j; p < a; p++)
            {
                array3[i] += array1[j] * array2[p];
            }
        }
        ++t;
    }
    return array3;
}

int main()
{
    int **matrix1, **matrix2;
    int *array1, *array2, *multiplyResult;
    int a, arrayLength;
    read(a, matrix1);
    read(a, matrix2);
    createArray(a, arrayLength, matrix1, array1);
    createArray(a, arrayLength, matrix2, array2);
    multiplyResult = multiplyArrays(a, arrayLength, array1, array2);
    showArray(arrayLength, multiplyResult);
}
#包括
#包括
无效读取(int&a、int**和矩阵)
{
标准:cin>>a;
矩阵=新整数*[a];
for(int i=0;i>矩阵[i][j];
}
}
}
无效显示矩阵(整数a,整数**矩阵)
{
for(int i=0;istd::cout矩阵乘法
C=A*B
C(i,j)=sum_k A(i,k)*B(k,j)
定义。矩阵
A
具有结构非零,其中
i>=k
,而
B
,其中
k>=j
。因此它足以进行迭代

  • (外循环)
    i
    0
    n-1
  • (中间)
    j
    0
    i
  • (内部)
    k
    j
    i

另一部分是将坐标
(i,j)
转换为相对于1D存储格式的偏移量。第一行
i
中的结构非零数量由
i
第三个三角形编号
(i+1)*i/2
给出。因此,此行中的
j
第四个元素位于(基于零的)索引
(i+1)*i/2+j
。您或您的编译器可以减少乘法运算。

要对矩阵进行乘法运算,需要找到数组中行的起始位置,例如,行[2]在数组中的索引
3
处开始,如下所示,

1 0 0 0 0
2 3 0 0 0
4 1 3 0 0 => row[2]
1 9 0 2 0
1 0 1 2 2
[1,2,3,
4,1,3
,1,9,0,2,1,0,1,2,2]

如果我们知道元素在它前面是如何出现的,就可以找到任何一行,就像上面的例子一样,如果我们知道三个元素在
行[2]
之前出现,那么我们就可以很容易地找到
行[2]


要在每行之前找到显示的元素数,需要计算一个大小等于行数的辅助数组,但要做到这一点,让我们首先再次查看矩阵,
如您所见,每行包含的元素等于行的
索引+1

1          element count = index + 1 = 0 + 1 = 1
2 3                                  = 1 + 1 = 2
4 1 3                                = 2 + 1 = 3
1 9 0 2                              ..
1 0 1 2 2                            ..
这意味着我们的辅助阵列将是,
辅助数组=
[0,1,2,3,4]
但如何设置?

正如我们所知,在
行[0]
之前没有元素,这就是为什么
辅助数组[0]=0
那么
行[1]
之前的元素只有一个元素可以通过上一行的索引找到,即
上一行索引+1
=>
0+1
,如上所示
辅助数组[1]=1
和所有行的类似值,
但它并没有完成!辅助数组的当前状态仅具有关于前一行中元素数量的信息,而不是所有前一行中的元素数量的信息,为此,我们必须计算所有前一行的和,这称为
部分和
,将按如下方式执行,

row[0] = row[0]
row[1] = row[0] + row[1]
row[2] = row[1] + row[2]
..
..
最终结果,
辅助数组=
[0,1,3,6,10]

因此,您可以看到
行[2]=auxiliaryArray[2]=3
之前的元素数
通过使用上述辅助数组,您可以找到任何行,如果您得到行的第一个元素,您可以找到所有列元素。
下一点需要理解的是,每行需要乘以多少个元素,也就是要乘以的元素数=索引+1,正如您在上面的矩阵
行[0]
中所看到的那样,只有一个元素对多个
索引+1
=>
0+1
,并且相同的规则适用于每行。
最后要考虑的是,当行乘以其他矩阵的COL时,它不会总是以<代码>行[0 ] < /代码>其他矩阵,如下面可以看到的<代码>其他矩阵[0 ] [1 ] < /代码>在其他矩阵的左对角线之外,

20
110
0112010
1 12 30
200 01 2

我们终于完成了

#include <iostream>

#include <vector>

#include <numeric>
#include <iterator>

using std::cout;

void printMatrixArray(std::size_t rowSize, const std::vector<int>& matArray){

    std::size_t elementCount = 1;
    std::vector<int>::const_iterator it = matArray.cbegin();

    for(std::size_t row = 0; row < rowSize; ++row){

        std::copy(it, it + elementCount, std::ostream_iterator<int>(cout, "\t"));
        cout<< '\n';

        it += elementCount;
        ++elementCount;
    }
}

std::vector<int> leftDiagonalBottomMatrix(const std::vector<std::vector<int>>& mat){

    std::vector<int> res;
    res.reserve(((1 + mat.size()) * mat.size()) / 2);

    std::vector<int>::size_type elementCount = 1;

    for(const std::vector<int>& row : mat){

        for(std::vector<int>::const_iterator it = row.cbegin(), endIt = row.cbegin() + elementCount; endIt != it; ++it){

            res.push_back(*it);
        }

        ++elementCount;
    }

    return res;
}

std::vector<int> multiplyMatrixArrays(const std::vector<int>& mat1Arr, const std::vector<int>& mat2Arr,
                                     std::vector<int>::size_type rowSize){

    std::vector<int> auxiliaryArray(rowSize);
    auxiliaryArray.front() = 0;

    std::iota(auxiliaryArray.begin() + 1, auxiliaryArray.end(), 1);

    std::partial_sum(auxiliaryArray.cbegin(), auxiliaryArray.cend(), auxiliaryArray.begin());

    std::vector<int> res;
    res.reserve(mat1Arr.size());

    for(std::vector<int>::size_type row = 0; row < rowSize; ++row){

        for(std::vector<int>::size_type col = 0; col <= row; ++col){

            int val = 0;

            for(std::vector<int>::size_type ele = col, elementCount = row + 1; ele < elementCount; ++ele){

                val += mat1Arr[auxiliaryArray[row] + ele] * mat2Arr[auxiliaryArray[ele] + col];
            }

            res.push_back(val);
        }
    }

    return  res;
}

std::vector<int> matrixMultiply(const std::vector<std::vector<int>>& mat1, const std::vector<std::vector<int>>& mat2){

    return multiplyMatrixArrays(leftDiagonalBottomMatrix(mat1), leftDiagonalBottomMatrix(mat2), mat1.size());
}


int main(){

    std::vector<std::vector<int>> mat1{{1, 0, 0, 0, 0}, {2, 3, 0, 0, 0}, {4, 1, 3, 0, 0}, {1, 9, 0, 2, 0},
                                       {1, 0, 1, 2, 2}};

    std::vector<std::vector<int>> mat2{{2, 0, 0, 0, 0}, {1, 1, 0, 0, 0}, {0, 1, 2, 0, 0}, {1, 1, 2, 3, 0},
                                       {2, 0, 0, 1, 2}};

    printMatrixArray(mat1.size(), matrixMultiply(mat1, mat2));
}


输出不会打印矩阵左对角线上方的元素!

奇怪的是,可以解释为“将有用元素……复制到数组”由于仍然不允许填充零,所以您仍然可以以一种简单的方式映射原始矩阵:)但我认为,这不是任务的根本目的……我没有用英语学习,所以我必须翻译这个问题,这就是为什么它有点模棱两可。在我自己的语言中,它更像是“转换矩阵的有用部分”(有用=主对角线及其下方的元素)到一个数组中).好的,那么V_a第一行有1个项目,第二行有2个项目,第三行有3个项目,等等。所以每个循环比上一次大一个。@JerryJeremiah,这就是我到目前为止所做的:现在我不知道如何从array3访问每个元素。我还需要1个循环吗?(我不这么认为)@八维亚尼库仑在强度折减之前,内部循环语句应该类似于
array3[(i+1)*i/2+j]+=array1[(i+1)*i/2+k]*array2[(k+1)*k/2+j];
。我真的不知道强度折减意味着什么,我在任何地方都没有看到。你能详细说明一下吗?@OctavianNiculescu继续计算
(i+1)是浪费时间的*i/2每次都是从头开始的。所以你可以将它缓存为外循环的第一条语句,甚至可以在循环外执行
int ti=0;
操作,然后在循环的顶部执行
ti+=i;
操作。不过编译器在这方面做得很好。我明白了。我想我已经完成了。谢谢你的时间:)解释得很好,回答也很全面谢谢你的时间,这是一个不同的方法,而不是我使用的方法,所以它真的帮助了我。@OctavianNiculescu:欢迎。
#include <iostream>

#include <vector>

#include <numeric>
#include <iterator>

using std::cout;

void printMatrixArray(std::size_t rowSize, const std::vector<int>& matArray){

    std::size_t elementCount = 1;
    std::vector<int>::const_iterator it = matArray.cbegin();

    for(std::size_t row = 0; row < rowSize; ++row){

        std::copy(it, it + elementCount, std::ostream_iterator<int>(cout, "\t"));
        cout<< '\n';

        it += elementCount;
        ++elementCount;
    }
}

std::vector<int> leftDiagonalBottomMatrix(const std::vector<std::vector<int>>& mat){

    std::vector<int> res;
    res.reserve(((1 + mat.size()) * mat.size()) / 2);

    std::vector<int>::size_type elementCount = 1;

    for(const std::vector<int>& row : mat){

        for(std::vector<int>::const_iterator it = row.cbegin(), endIt = row.cbegin() + elementCount; endIt != it; ++it){

            res.push_back(*it);
        }

        ++elementCount;
    }

    return res;
}

std::vector<int> multiplyMatrixArrays(const std::vector<int>& mat1Arr, const std::vector<int>& mat2Arr,
                                     std::vector<int>::size_type rowSize){

    std::vector<int> auxiliaryArray(rowSize);
    auxiliaryArray.front() = 0;

    std::iota(auxiliaryArray.begin() + 1, auxiliaryArray.end(), 1);

    std::partial_sum(auxiliaryArray.cbegin(), auxiliaryArray.cend(), auxiliaryArray.begin());

    std::vector<int> res;
    res.reserve(mat1Arr.size());

    for(std::vector<int>::size_type row = 0; row < rowSize; ++row){

        for(std::vector<int>::size_type col = 0; col <= row; ++col){

            int val = 0;

            for(std::vector<int>::size_type ele = col, elementCount = row + 1; ele < elementCount; ++ele){

                val += mat1Arr[auxiliaryArray[row] + ele] * mat2Arr[auxiliaryArray[ele] + col];
            }

            res.push_back(val);
        }
    }

    return  res;
}

std::vector<int> matrixMultiply(const std::vector<std::vector<int>>& mat1, const std::vector<std::vector<int>>& mat2){

    return multiplyMatrixArrays(leftDiagonalBottomMatrix(mat1), leftDiagonalBottomMatrix(mat2), mat1.size());
}


int main(){

    std::vector<std::vector<int>> mat1{{1, 0, 0, 0, 0}, {2, 3, 0, 0, 0}, {4, 1, 3, 0, 0}, {1, 9, 0, 2, 0},
                                       {1, 0, 1, 2, 2}};

    std::vector<std::vector<int>> mat2{{2, 0, 0, 0, 0}, {1, 1, 0, 0, 0}, {0, 1, 2, 0, 0}, {1, 1, 2, 3, 0},
                                       {2, 0, 0, 1, 2}};

    printMatrixArray(mat1.size(), matrixMultiply(mat1, mat2));
}

2   
7   3   
9   4   6   
13  11  4   6   
8   3   6   8   4