一、矩阵逆置
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;
}