矩阵逆置(图解详讲)

一、矩阵逆置

1.压缩矩阵

矩阵逆置就是把 element[i][j] 换成 element[j][i] 。
而对于在这里插入图片描述
i为列的下标,j为行的下标。
这样的矩阵,有无效数字0,我们无需处理,因此我们采用压缩矩阵,如下图
在这里插入图片描述
类似于我们只需处理这个压缩矩阵。

2.结构体的建立

typedef struct Triple 
{
    int i;
    int j;
    ElemType e;
}Triple, *TriplePtr;

typedef struct CompressedMatrix 
{
    int rows;
    int columns;
    int numElements;
    Triple* elements;
} CompressedMatrix, * CompressedMatrixPtr;

3.初始化矩阵

CompressedMatrixPtr initCompressedMatrix(int paraRows, int paraColumns, int paraElements, int** paraData)
{
    CompressedMatrixPtr resultPtr = new struct CompressedMatrix;

    resultPtr->rows = paraRows;
    resultPtr->columns = paraColumns;
    resultPtr->numElements = paraElements;

    resultPtr->elements = new Triple[paraElements];

    for (int i = 0; i < paraElements; i++)
    {
        resultPtr->elements[i].i = paraData[i][0];
        resultPtr->elements[i].j = paraData[i][1];
        resultPtr->elements[i].e = paraData[i][2];
    }

    return resultPtr;
}

在这里插入图片描述
通过压缩矩阵,建立这样一个可扫描的矩阵。

4.矩阵逆置(核心)

CompressedMatrixPtr transposeCompressedMatrix(CompressedMatrixPtr paraPtr)
{
    //Step 1.分配空间
    int i, tempColum, tempPosition;
   
    int* tempColumnCounts = new int[paraPtr->columns];//临时列数
    int* tempOffsets = new int[paraPtr->columns];//临时开端数组

    for (i = 0; i < paraPtr->columns; i++)
    {
        tempColumnCounts[i] = 0;
    }

    CompressedMatrixPtr resultPtr = new struct CompressedMatrix;

    resultPtr->rows = paraPtr->columns;
    resultPtr->columns = paraPtr->rows;
    resultPtr->numElements = paraPtr->numElements;

    resultPtr->elements = new Triple[paraPtr->numElements];

    //Step 2.0 一次扫描以计算开端数
    for (int i = 0; i < paraPtr->numElements; i++)
    {
        tempColumnCounts[paraPtr->elements[i].j]++;
    }//3.1.2数量

    //Step 2.1 开端数字所在的行数开头下标
    tempOffsets[0] = 0;
    for (int i = 1; i < paraPtr->columns; i++)
    {
        tempOffsets[i] = tempOffsets[i - 1] + tempColumnCounts[i - 1];
        printf("tempOffsets[%d] = %d \r\n", i, tempOffsets[i]);//测试代码
    } //0.1.2开头下标0,3,4

    //Step 3.再次扫描以填充数据
    for (int i = 0; i < paraPtr->numElements; i++)
    {
        tempColum = paraPtr->elements[i].j;
        tempPosition = tempOffsets[tempColum];

        resultPtr->elements[tempPosition].i = paraPtr->elements[i].j;
        resultPtr->elements[tempPosition].j = paraPtr->elements[i].i;
        resultPtr->elements[tempPosition].e = paraPtr->elements[i].e;

        tempOffsets[tempColum]++;
    }

    return resultPtr;
}

先从step.2.0开始说起,由于i,j是原矩阵的行数和列数,我们要换成j,i的形式。就得先处理行的开头问题。因此就必须先对原来的j所在的那一列进行扫描,也就是下面表紫色的那一列。对应的代码就是step2里面的forx循环。在这里插入图片描述由于本列中只出现了0 1 2三个数,也就说明了逆置后的矩阵行数开头的数字也就是只有 0 1 2 。扫描的过程中,其实就是一个计数的过程。扫描最终得到 tempColumnCounts[paraPtr->elements[i].j]数组,如图
在这里插入图片描述
接下里就是step.2.1 这一步是在计算出,行开端以0 1 2的,他们所在的初始行数。也就是为了得到如下图)
在这里插入图片描述
这个图的意思就是,行开端以0开头的有3个,以1开头的有1个,以2开头的有2个。
进而得到:
在这里插入图片描述
最后就是step.3 我们再次采用for循环,这里大家思考一个问题:本段采用了三次for循环,他们的判断条件为什么会是那样的呢? 我们继续step.3的讲解。这个for循环也就是再次对原来的第j所在列进行扫描,执行的也就是step.2.0的扫描动作,只不过扫描时,采取的操作不一样。下面根据图示走一个在这里插入图片描述
第一次扫描的j为0,(标红)

第一次对原来矩阵第0行进行逆置,开头放在新的矩阵的第0行,逆置依次如下结果:
在这里插入图片描述
似乎没什么变化,那是因为(0,0)逆置还是在(0,0)没关系,我们再走一个。第二次扫描到的j为2
在这里插入图片描述
对行开头为2的进行处理也就是 ,得到了
在这里插入图片描述
这样就好理解了。剩下的依次类推。最终逆置的结果如下图
在这里插入图片描述
逆置完毕

5.完整代码

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

typedef int ElemType;


typedef struct Triple 
{
    int i;
    int j;
    ElemType e;
}Triple, *TriplePtr;

typedef struct CompressedMatrix 
{
    int rows;
    int columns;
    int numElements;
    Triple* elements;
} CompressedMatrix, * CompressedMatrixPtr;

CompressedMatrixPtr initCompressedMatrix(int paraRows, int paraColumns, int paraElements, int** paraData)
{
    CompressedMatrixPtr resultPtr = new struct CompressedMatrix;

    resultPtr->rows = paraRows;
    resultPtr->columns = paraColumns;
    resultPtr->numElements = paraElements;

    resultPtr->elements = new Triple[paraElements];

    for (int i = 0; i < paraElements; i++)
    {
        resultPtr->elements[i].i = paraData[i][0];
        resultPtr->elements[i].j = paraData[i][1];
        resultPtr->elements[i].e = paraData[i][2];
    }

    return resultPtr;
}
void printCompressedMatrix(CompressedMatrixPtr paraPtr) 
{
    for (int i = 0; i < paraPtr->numElements; i++)
    {
        printf("(%d, %d): %d \r\n", paraPtr->elements[i].i, paraPtr->elements[i].j, paraPtr->elements[i].e);
    }

}

CompressedMatrixPtr transposeCompressedMatrix(CompressedMatrixPtr paraPtr)
{
    //Step 1.分配空间
    int i, tempColum, tempPosition;
   
    int* tempColumnCounts = new int[paraPtr->columns];//临时列数
    int* tempOffsets = new int[paraPtr->columns];//临时开端数组

    for (i = 0; i < paraPtr->columns; i++)
    {
        tempColumnCounts[i] = 0;
    }

    CompressedMatrixPtr resultPtr = new struct CompressedMatrix;

    resultPtr->rows = paraPtr->columns;
    resultPtr->columns = paraPtr->rows;
    resultPtr->numElements = paraPtr->numElements;

    resultPtr->elements = new Triple[paraPtr->numElements];

    //Step 2. 一次扫描以计算开端数
    for (int i = 0; i < paraPtr->numElements; i++)
    {
        tempColumnCounts[paraPtr->elements[i].j]++;
    }//3.1.2数量

    tempOffsets[0] = 0;

    //Step 2.1  0.1.2开头下标0,3,4
    for (int i = 1; i < paraPtr->columns; i++)
    {
        tempOffsets[i] = tempOffsets[i - 1] + tempColumnCounts[i - 1];
        printf("tempOffsets[%d] = %d \r\n", i, tempOffsets[i]);//测试代码
    }

    //Step 3.再次扫描以填充数据
    for (int i = 0; i < paraPtr->numElements; i++)
    {
        tempColum = paraPtr->elements[i].j;
        tempPosition = tempOffsets[tempColum];

        resultPtr->elements[tempPosition].i = paraPtr->elements[i].j;
        resultPtr->elements[tempPosition].j = paraPtr->elements[i].i;
        resultPtr->elements[tempPosition].e = paraPtr->elements[i].e;

        tempOffsets[tempColum]++;
    }

    return resultPtr;
}

void compressedMatrixTest() {
    CompressedMatrixPtr tempPtr1 =NULL,tempPtr2 = NULL;
    int i, j, tempElements;

    //Construct the first sample matrix.
    tempElements = 6;

    int** tempMatrix1 = new int* [tempElements];
    for (i = 0; i < tempElements; i++) {
        tempMatrix1[i] = new int[3];

    }

    int tempMatrix2[6][3] = { {0, 0, 2}, {0, 2, 3}, {2, 0, 5}, {2, 1, 6},{3, 0, 4},{3, 2, 7} };
    for (i = 0; i < tempElements; i++) 
    {
        for (j = 0; j < 3; j++) 
        {
            tempMatrix1[i][j] = tempMatrix2[i][j];
        }
    }

    tempPtr1 = initCompressedMatrix(2, 5, 6, tempMatrix1);//行:012 三行;列:012345 六列

    printf("After initialization.\r\n");
    printCompressedMatrix(tempPtr1);

    tempPtr2 = transposeCompressedMatrix(tempPtr1);
    printf("After transpose.\r\n");
    printCompressedMatrix(tempPtr2);
}

int main() 
{
    compressedMatrixTest();

    system("pause");
    return 0;
}

6.运行展示

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值