多维数组与特殊矩阵的压缩存储

    xiaoxiao2023-03-25  4

    数组是由类型相同的数据元素构成的有序集合,每个数据元素称为一个数组元素,每个元素受(n>=1)个线性关系的的约束,每个元素在n个线性关系中的序号i1,i2...in称为该元素的下标,并称该数组为n维数组. 数组的存储结构与寻址 由于数组一般要求实现随机存取,所以一般采用顺序存储结构.由于内存单元是一维,而多维数组是多维的结构,所以采用顺序存储结构存储数组首先需要将多维结构映射到一维结构中.二维数组的每个元素含有两个下标,需要将其映射为一维关系。通常有两种映射方式:按行存储和按列存储. C++是按行优先存储的. 设二维数组行下标和列下标分别为闭区间[L1, H1],[L2,H2];则按行优先存储的任意一元素Aij的地址可以用以下公式计算:LOC(Aij) = LOC(aL1L2) + ((i-L1)*(H2-L2+1) + (J-L2))*c 行下标[0,2] 列下标[0,3] 根据上述公式a[2][3] = a + 2*4 + 3 

    按行存储的基本思想是,最右边的下标最先变化.

    二维数组用寻址方式展示:

    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<n; i++) { for (int j = 0; j<n; j++) { if (j<=i) // 存储下三角元素 { Compress[k++] = *((int*)array + i*n + j); } } } }解压:

    // 将一个压缩矩阵解压成对称矩阵 // 入参:Compress[] 压缩的矩阵 // n n阶对称阵 // int** array 解压后的二维数组 void DeCompressSymMatrix(int Compress[], int n, int** array) { for (int i = 0; i<n; i++) { for (int j = 0; j<n; j++) { int k = 0; // 压缩数组下标k与二维数组下标的对应关系 if (i>j) { k = (i*(i+1))/2 + j; }else { k = (j*(j+1))/2 + i; } *((int*)array + i*n + j) = Compress[k]; } } }测试例子:

    <span style="white-space:pre"> </span>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}}; <span style="white-space:pre"> </span>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"); <span style="white-space:pre"> </span>} 2.三角矩阵 {3,c,c,c,c,  6,2,c,c,c,  4,8,1,c,c,  7,4,6,0,c,  8,2,9,5,7, } 下三角矩阵与对称矩阵存储类似,只是需要多存储一个常数.需要存储空间为n(n+1)/2 + 1 aij与k的对应关系为:

     i>=j k = i*(i+1)/2 + j;  i<j  k = n(n+1)/2 上三角矩阵: 与下三角矩阵存储类似: 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<n; i++) { for (int j = 0; j<n; j++) { if (bUp && (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<n; i++) { for (int j = 0; j<n; j++) { int k = 0; if (bUp) { if (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}}; <span style="white-space:pre"> </span>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"); }上三角矩阵的测试稍微改一下上面部分即可. 3.对角矩阵:

    对角矩阵:在对角矩阵中,所有非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; i<m; i++) { for (int j = 0; j<n; j++) { int value = *((int*)array + i*n + j); if (0 != value) { t = i; // 压缩到的行号 s = j-i+1; // 压缩到的列号 *((int*)outArray + t*w + s) = value; } } } } // 入参:int** array 要解压的对角矩阵 // m,n,w要解压出M行N列W带宽的对角矩阵. // outArray解压后的对角矩阵 void DeCompressDiagonalMartix(int** array, int m, int n, int w, int** outArray) { int t = 0; int s = 0; for (int i = 0; i<m; i++) { for (int j = 0; j<n; j++) { t = i; // 行 s = j-i+1; // 列 if (i==j || (j>i) && ((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; } } } }测试:

    <span style="white-space:pre"> </span>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}}; <span style="white-space:pre"> </span>int CompressDiagonalArray[5][3] = {0}; <span style="white-space:pre"> </span>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 <class T> struct element { int row; int col; T data; };三元组顺序表,为了确定一个唯一稀疏矩阵,还要存储稀疏矩阵的行数,列数和非0元素的个数

    const int MaxTerm = 256; template <class T> struct SparseMatrix { element<T> data[MaxTerm]; int rowCount; // 行数 int colCount; // 列数 int notZeroCount; }; // 稀疏矩阵压缩存储 // 入参:int** array要压缩的稀疏矩阵 // m,nM行N列 // 出参:SparseMatrix& 输出存储的结构 void CompressSpareMatrix(int** array, int m, int n, SparseMatrix<int>& 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<int>& sparseMatrixA, SparseMatrix<int>& 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<sparseMatrixA.notZeroCount; notZero++) { if (sparseMatrixA.data[notZero].col == col) { sparseMatrixB.data[pb].row = sparseMatrixA.data[notZero].col; sparseMatrixB.data[pb].col = sparseMatrixA.data[notZero].row; sparseMatrixB.data[pb].data = sparseMatrixA.data[notZero].data; pb++; } } } } }2)顺序取,直接存

    稀疏矩阵十字链表实现.

    转载请注明原文地址: https://ju.6miu.com/read-1203977.html
    最新回复(0)