按行存储的基本思想是,最右边的下标最先变化.
二维数组用寻址方式展示:
int a[][4] = {{1,2,3,4},{5,6,7,8},{4,5,6,7}};
for (int i = 0; i<3; i++) // 行下标
{
for (int j = 0; j<4; j++) // 列下标
{
printf("%d ", *((int*)a + i*4 + j));
}
printf("\r\n");
}
特殊矩阵的压缩存储:
1.对称矩阵:在一个n阶方阵中,有Aij = Aji(i>=0, j<=n-1)
{ 3 6 4 7 8
6 2 8 4 2
4 8 1 6 9
7 4 6 0 5
8 2 9 5 7
}
对称矩阵关于主对角线对称,因此只需要存储下三角(或上三角)部分即可.原来需要n*n个存储单元,
现在仅需要n*(n+1)/2个存储单元,一个S[n(n+1)/2]个元素的一维数组存储,aij存储在S[K]中,对于
下三角元素,i>=j有如下对应关系k = i*(i+1)/2+j;对于上三角元素,有如下对应关系:k = j*(j+1)/2+i
可以想象成求aij元素在下三角中的第几个元素,先求i*(i+1)/2(三角形面积),然后加上j.
压缩:
// 将一个对称矩阵压缩存储,并输出存储后的数组
// 入参:int** array 要压缩的对称矩阵
// n 对称矩阵阶数
// Compress 压缩后的数组
void CompressSymMatrix(int** array, int n, int Compress[])
{
int k = 0;
for(int i = 0; i
解压:
// 将一个压缩矩阵解压成对称矩阵
// 入参:Compress[] 压缩的矩阵
// n n阶对称阵
// int** array 解压后的二维数组
void DeCompressSymMatrix(int Compress[], int n, int** array)
{
for (int i = 0; ij)
{
k = (i*(i+1))/2 + j;
}else
{
k = (j*(j+1))/2 + i;
}
*((int*)array + i*n + j) = Compress[k];
}
}
}
测试例子:
int SymArray[5][5] = {{3,6,4,7,8},{6,2,8,4,2},{4,8,1,6,9},{7,4,6,0,5},{8,2,9,5,7}};
printf("对称矩阵:\r\n");
for (int i = 0; i<5; i++)
{
for (int j = 0; j<5; j++)
{
printf("%d ", SymArray[i][j]);
}
printf("\r\n");
}
printf("将其压缩后:\r\n");
int Compress[15] = {0};
CompressSymMatrix((int**)SymArray, 5, Compress);
for (int i = 0; i<15; i++)
{
printf("%d ", Compress[i]);
}
printf("将其解压后:\r\n");
int DeArray[5][5] = {0};
DeCompressSymMatrix(Compress, 5, (int**)DeArray);
for (int i = 0; i<5; i++)
{
for (int j = 0; j<5; j++)
{
printf("%d ", DeArray[i][j]);
}
printf("\r\n");
}
2.三角矩阵
i>=j k = i*(i+1)/2 + j;
i
与下三角矩阵存储类似:
aij与k的对应关系为:
i<=j k = i*(2n-i+1)/2+j-i
i>j k = n*(n+1)/2
void CompressTriangle(int** array, int n, int compress[], bool bUp = true)
{
int m = 0;
for (int i = 0; i= j) )
{
compress[m++] = *((int*)array + i*n + j);
}
if ((!bUp) && (i<=j))
{
compress[m++] = *((int*)array + i*n + j);
}
}
}
if (bUp)
{
compress[(n*(n+1))/2] = *((int*)array + 1);
}else
{
compress[(n*(n+1))/2] = *((int*)array + n);
}
}
// 将压缩的下三角矩阵解压出来
// int** array 解压后的三角矩阵
// n N阶矩阵
// compress[] 压缩的一维数组
// bUp = true 上三角矩阵 bUp = false 下三角矩阵
void DeCompressTriangle(int** array, int n, int compress[], bool bUp = true)
{
int m = (n*(n+1))/2;
for (int i = 0; i= j)
{
k = (i*(i+1))/2 + j;
}else
{
k = m;
}
}else
{
if (i<=j)
{
k = i*(2*n-i+1)/2 + j - i;
}else
{
k = m;
}
}
*((int*)array + i*n + j) = compress[k];
}
}
}
int UpTriArray[][5] = {{3,1,1,1,1}, {6,2,1,1,1},{4,8,1,1,1},{7,4,6,0,1},{8,2,9,5,7}};
int DownTriArray[][5] = {{3,4,8,1,0},{1,2,9,4,6},{1,1,1,5,7},{1,1,1,0,8},{1,1,1,1,7}};
printf("下三角矩阵:\r\n");
for (int i = 0; i<5; i++)
{
for (int j = 0; j<5; j++)
{
printf("%d ", DownTriArray[i][j]);
}
printf("\r\n");
}
printf("将其压缩后:\r\n");
int Compress[16] = {0};
CompressTriangle((int**)DownTriArray, 5, Compress, false);
for (int i = 0; i<16; i++)
{
printf("%d ", Compress[i]);
}
printf("将其解压后:\r\n");
int DeArray[5][5] = {0};
DeCompressTriangle((int**)DeArray, 5, Compress, false);
for (int i = 0; i<5; i++)
{
for (int j = 0; j<5; j++)
{
printf("%d ", DeArray[i][j]);
}
printf("\r\n");
}
上三角矩阵的测试稍微改一下上面部分即可.
对角矩阵:在对角矩阵中,所有非0元素都集中在以主对角线为中心的带状区域中,除了主对角线和它的上下方若干条对角
线的元素外,其他元素都为0.
{2,1,0,0,0,
9,3,4,0,0,
0,7,5,3,0,
0,0,5,4,2,
0,0,0,1,1}
将一个m*n的w对角矩阵(w是占有非0元素对角线的个数,也成为带宽).压缩到m行,w列的二维数组B中.则Aij与Bts的映射关系
为:t = i; s = j - i + 1
// 入参: int** array 要压缩的对角矩阵
// m,n,w M行N列带宽w
// outArray 压缩后的矩阵
void CompressDiagonalMartix(int** array, int m, int n, int w, int** outArray)
{
int t = 0;
int s = 0;
for (int i = 0; ii) && ((j - i) < ((w-1)/2 + 1)) || (i>j) && ((i-j) < ((w-1)/2 + 1)))
{
*((int*)array + i*n + j) = *((int*)outArray + t*w + s);
}else
{
*((int*)array + i*n + j) = 0;
}
}
}
}
测试:
int DiagonalArray[5][5] = {{1,2,0,0,0},{3,4,5,0,0},{0,6,7,8,0},{0,0,9,3,1},{0,0,0,2,3}};
int CompressDiagonalArray[5][3] = {0};
printf("对角矩阵:\r\n");
for (int i = 0; i<5; i++)
{
for (int j = 0; j<5; j++)
{
printf("%d ", DiagonalArray[i][j]);
}
printf("\r\n");
}
printf("将其压缩后:\r\n");
//int Compress[16] = {0};
CompressDiagonalMartix((int**)DiagonalArray, 5, 5, 3, (int**)CompressDiagonalArray);
for (int i = 0; i<5; i++)
{
for (int j = 0; j<3; j++)
{
printf("%d ", CompressDiagonalArray[i][j]);
}
printf("\r\n");
}
printf("将其解压后:\r\n");
int DeArray[5][5] = {0};
DeCompressDiagonalMartix((int**)DeArray, 5, 5, 3, (int**)CompressDiagonalArray);
for (int i = 0; i<5; i++)
{
for (int j = 0; j<5; j++)
{
printf("%d ", DeArray[i][j]);
}
printf("\r\n");
}
对角矩阵另一种存储方法是压缩到一维数组中,按行存储非0元素,k = 2i+j;
4. 稀疏矩阵的压缩存储
稀疏矩阵的压缩存储
稀疏矩阵是0元素居多的矩阵.
1.对于稀疏矩阵,0元素分布没有规律.仅存储非0元素是没有用的,还要存储元素的行号和列号.
即每个非0元素可以表示成如下三元组
template
struct element
{
int row;
int col;
T data;
};
三元组顺序表,为了确定一个唯一稀疏矩阵,还要存储稀疏矩阵的行数,列数和非0元素的个数
const int MaxTerm = 256;
template
struct SparseMatrix
{
element data[MaxTerm];
int rowCount; // 行数
int colCount; // 列数
int notZeroCount;
};
// 稀疏矩阵压缩存储
// 入参:int** array要压缩的稀疏矩阵
// m,nM行N列
// 出参:SparseMatrix& 输出存储的结构
void CompressSpareMatrix(int** array, int m, int n, SparseMatrix& spareMatrix)
{
// 对稀疏矩阵非0元素存储
int nCount = 0;
for (int row = 0; row < m; row++)
{
for (int col = 0; col < n; col++)
{
int value = *((int*)array + row*n + col);
if (value != 0)
{
spareMatrix.data[nCount].data = value;
spareMatrix.data[nCount].row = row;
spareMatrix.data[nCount].col = col;
nCount++;
}
}
}
spareMatrix.notZeroCount = nCount;
spareMatrix.rowCount = m;
spareMatrix.colCount = n;
}
// 稀疏矩阵对三元组顺序表的转置
// 1)直接取,顺序存
// 描述:依次从A矩阵寻找0,1..n-1列的三元组,找到之后交换行列位置存入B中.
void Trans1(SparseMatrix& sparseMatrixA, SparseMatrix& sparseMatrixB)
{
sparseMatrixB.colCount = sparseMatrixA.rowCount;
sparseMatrixB.rowCount = sparseMatrixA.colCount;
sparseMatrixB.notZeroCount = sparseMatrixA.notZeroCount;
int pb = 0;
if (sparseMatrixA.notZeroCount > 0)
{
for (int col = 0; col < sparseMatrixA.colCount; col++)
{
for (int notZero = 0; notZero
2)顺序取,直接存
稀疏矩阵十字链表实现.