zoukankan      html  css  js  c++  java
  • C语言 稀疏矩阵 压缩 实现

    稀疏矩阵压缩存储的C语言实现 (GCC编译)。

      1 /**
      2 * @brief C语言 稀疏矩阵 压缩 实现
      3 * @author wid
      4 * @date 2013-11-04
      5 *
      6 * @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!
      7 */
      8 
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <assert.h>
     12 #include <string.h>
     13 
     14 #define TRUE 1
     15 #define FALSE 0
     16 #define NPOS -1
     17 
     18 typedef int ElemType;
     19 
     20 typedef struct
     21 {
     22     int m;              ///行下标
     23     int n;              ///列下标
     24     ElemType elm;       ///该下标所保存的元素
     25 }TTuple;    ///三元组结构
     26 
     27 typedef struct
     28 {
     29     TTuple *tup;        ///三元组顺序表
     30     int row;            ///矩阵行数
     31     int col;            ///矩阵列数
     32     int unul;           ///非 0 元素个数
     33 }TMatrix;   ///稀疏矩阵结构
     34 
     35 
     36 ///稀疏矩阵方法声明
     37 TMatrix *CreateEmptyTMatrix( int sizeM, int sizeN );              ///创建一个大小为 sizeM x sizeN 稀疏矩阵
     38 TMatrix *CreateTMatirxFrom2DArray( void *pArr2D, int sizeM, int sizeN );    ///从二维数组中创建稀疏矩阵
     39 void DestroyTMatrix( TMatrix *pMat );       ///销毁稀疏矩阵
     40 int ElemLocate( const TMatrix *const pMat, int m, int n );                  ///定位矩阵下标 m, n 在稀疏矩阵中的存储位置
     41 void DisplayTMatrix( const TMatrix *const pMat );       ///输出稀疏矩阵
     42 int GetTMatrixSize( const TMatrix *const pMat );        ///输出稀疏矩阵 pMat 所占用的空间大小(字节)
     43 int AppendElem( TMatrix *const pMat, ElemType elm, int m, int n );          ///将元素 elm 添加到稀疏矩阵 m, n 位置
     44 int DeleteElem( TMatrix *const pMat, int m, int n );    ///删除稀疏矩阵中 m, n 下标指向的元素
     45 int TMatrixCopy( TMatrix *const pMatDest, TMatrix *const pMatSrc );         ///将稀疏矩阵 pMatSrc 复制到 pMatDest
     46 int Value( const TMatrix *const pMat, int m, int n, ElemType *pElm );       ///从稀疏矩阵中取下标为 m, n 元素的值
     47 void ForEach( const TMatrix *const pMat, void (*func)(ElemType *pElm) );    ///对矩阵中的每个元素依次执行 func 函数
     48 
     49 ///稀疏矩阵方法实现
     50 
     51 /**
     52 * @brief 创建一个大小为 sizeM x sizeN 稀疏矩阵
     53 *
     54 * @return 返回创建的稀疏矩阵的指针
     55 */
     56 TMatrix *CreateEmptyTMatrix( int sizeM, int sizeN )
     57 {
     58     ///不接受大小为0的稀疏矩阵
     59     assert( sizeM > 0 && sizeN > 0 );
     60 
     61     TMatrix *pMat = (TMatrix *)malloc( sizeof(TMatrix) );
     62     pMat->tup = NULL;
     63     pMat->row = sizeM;
     64     pMat->col = sizeN;
     65     pMat->unul = 0;
     66 
     67     return pMat;
     68 }
     69 
     70 /**
     71 * @brief 从二维数组中创建稀疏矩阵
     72 *
     73 * @param pArr2D 一个ElemType型二维数组
     74 * @param sizeM 二维数组的行数
     75 * @param sizeN 二维数组的列数
     76 *
     77 * @return 返回创建的稀疏矩阵的指针
     78 */
     79 TMatrix *CreateTMatirxFrom2DArray( void *pArr2D, int sizeM, int sizeN )
     80 {
     81     ///不接受大小为0的稀疏矩阵
     82     assert( sizeM > 0 && sizeN > 0 );
     83 
     84     TMatrix *pMat = (TMatrix *)malloc( sizeof(TMatrix) );
     85 
     86     ///初始化稀疏矩阵行数、列数
     87     pMat->row = sizeM;
     88     pMat->col = sizeN;
     89 
     90     ///第一趟遍历, 统计非零元素个数
     91     int m = 0, n = 0;
     92     for( m = 0; m < sizeM; ++m )
     93         for( n = 0; n < sizeN; ++n )
     94             if( ((ElemType *)pArr2D)[sizeM * m + n] != 0 )
     95                 ++pMat->unul;
     96 
     97     ///申请合适长度的三元组类型的线性表
     98     pMat->tup = (TTuple *)calloc( pMat->unul, sizeof(TTuple) );
     99 
    100     ///第二趟遍历, 存储二维矩阵中的非零元素
    101     int nPos = 0;
    102     for( m = 0; m < sizeM; ++m )
    103         for( n = 0; n < sizeN; ++n )
    104             if( ((ElemType *)pArr2D)[sizeM * m + n] != 0 )
    105             {
    106                 pMat->tup[nPos].m = m;
    107                 pMat->tup[nPos].n = n;
    108                 pMat->tup[nPos].elm = ((ElemType *)pArr2D)[sizeM * m + n];
    109                 ++nPos;
    110             }
    111 
    112     return pMat;
    113 }
    114 
    115 /**
    116 * @brief 销毁稀疏矩阵
    117 *
    118 * @param pMat 指向待销毁的稀疏矩阵
    119 */
    120 void DestroyTMatrix( TMatrix *pMat )
    121 {
    122     free( pMat->tup );
    123     free( pMat );
    124 
    125     pMat = NULL;
    126 }
    127 
    128 /**
    129 * @brief 定位元素下标 m, n 在稀疏矩阵中出现的位置
    130 *
    131 * @param pMat 指向待定位元素的稀疏矩阵
    132 * @param m 元素行下标
    133 * @param n 元素列下标
    134 *
    135 * @return 若存在, 返回该下标组在稀疏矩阵中出现的位置, 否则返回 NPOS
    136 *
    137 * @note 元素位置由 0 计起
    138 */
    139 int ElemLocate( const TMatrix *const pMat, int m, int n )
    140 {
    141     int i = 0;
    142     for( i = 0; i < pMat->unul; ++i )
    143     {
    144         if( pMat->tup[i].m == m && pMat->tup[i].n == n )
    145             return i;
    146     }
    147 
    148     return NPOS;
    149 }
    150 
    151 /**‘
    152 * @brief 输出稀疏矩阵
    153 *
    154 * @param pMat 指向待输出的稀疏矩阵
    155 *
    156 * @return void
    157 */
    158 void DisplayTMatrix( const TMatrix *const pMat )
    159 {
    160     int m = 0, n = 0, pos = 0;
    161     for( m = 0; m < pMat->row; ++m )
    162     {
    163         for( n = 0; n < pMat->col; ++n )
    164         {
    165             pos = ElemLocate( pMat, m, n );
    166             if( pos != NPOS )
    167                 printf( "%d ",  pMat->tup[pos].elm );
    168             else
    169                 printf( "%d ", 0 );
    170         }
    171         putchar( '
    ' );
    172     }
    173 }
    174 
    175 /**
    176 * @brief 获取稀疏矩阵所占用的空间大小(字节)
    177 *
    178 * @param pMat 指向待获取占用空间的稀疏矩阵
    179 *
    180 * @return 返回该矩阵所占用的空间的大小
    181 */
    182 int GetTMatrixSize( const TMatrix *const pMat )
    183 {
    184     return pMat->unul * sizeof(TTuple);
    185 }
    186 
    187 /**
    188 * @brief 将元素添加到稀疏矩阵的 m, n 位置
    189 *
    190 * @param pMat 指向待添加元素的稀疏矩阵
    191 * @param elm 待添加的元素
    192 * @param m 元素所在的行数
    193 * @param n 元素所在的列数
    194 *
    195 * @return 返回添加后稀疏矩阵中非 0 元素的个数
    196 */
    197 int AppendElem( TMatrix *const pMat, ElemType elm, int m, int n )
    198 {
    199     ///断言下标合法
    200     assert( m >= 0 && m < pMat->row && n >= 0 && n < pMat->col );
    201 
    202     ///断言元素值合法(不接受元素值为0的元素)
    203     assert( elm != 0 );
    204 
    205     ///测试下标是否存在
    206     int i = 0, pos = 0;
    207     pos = ElemLocate( pMat, m, n );
    208     if( pos != NPOS )
    209     {   ///下标已存在, 覆盖原值
    210         pMat->tup[pos].elm = elm;
    211         return pMat->unul;
    212     }
    213 
    214     ///新添加
    215     pMat->tup = (TTuple *)realloc( pMat->tup, sizeof(TTuple) * (pMat->unul + 1) );
    216     pMat->tup[pMat->unul].m = m;
    217     pMat->tup[pMat->unul].n = n;
    218     pMat->tup[pMat->unul].elm = elm;
    219 
    220     return ++pMat->unul;
    221 }
    222 
    223 /**
    224 * @brief 删除稀疏矩阵中下标 m, n 指向的元素
    225 *
    226 * @param pMat 指向待删除元素的稀疏矩阵
    227 * @param m 元素行下标
    228 * @param n 元素列下标
    229 *
    230 * @param 若元素存在, 则返回删除后稀疏矩阵中非 0 元素个数, 否则返回NPOS
    231 */
    232 int DeleteElem( TMatrix *const pMat, int m, int n )
    233 {
    234     ///使用断言确保下标合法
    235     assert( m >= 0 && m < pMat->row && n >= 0 && n < pMat->col );
    236 
    237     int pos = ElemLocate( pMat, m, n );
    238 
    239     ///该元素是否存在
    240     if( pos == NPOS )
    241         return NPOS;
    242 
    243     ///删除该位置上的元素以及记录
    244     for( pos; pos < pMat->unul - 1; ++pos )
    245     {
    246         pMat->tup[pos].m = pMat->tup[pos+1].m;
    247         pMat->tup[pos].n = pMat->tup[pos+1].n;
    248         pMat->tup[pos].elm = pMat->tup[pos+1].elm;
    249     }
    250 
    251     ///缩小内容占用
    252     pMat->tup = (TTuple *)realloc( pMat->tup, sizeof(TTuple) * (pMat->unul - 1) );
    253 
    254     return --pMat->unul;
    255 }
    256 
    257 /**
    258 * @brief 将源稀疏矩阵复制到目标稀疏矩阵中
    259 *
    260 * @param pMatDest 指向目标稀疏矩阵
    261 * @param pMatSrc 指向源稀疏矩阵
    262 *
    263 * @return 返回复制成功后目标稀疏矩阵中的非0元素数量
    264 */
    265 int TMatrixCopy( TMatrix *const pMatDest, TMatrix *const pMatSrc )
    266 {
    267     if( pMatDest->tup )
    268         free( pMatDest->tup );
    269 
    270     ///源稀疏矩是否为空
    271     if( pMatSrc->tup )
    272     {   //不为空, 复制矩阵
    273         pMatDest->tup = (TTuple *)calloc( pMatSrc->unul, sizeof(TTuple) * pMatSrc->unul );
    274         assert( pMatDest->tup );
    275         memcpy( pMatDest->tup, pMatSrc->tup, sizeof(TTuple) * pMatSrc->unul );
    276     }
    277     else pMatDest->tup = NULL;
    278 
    279     pMatDest->row = pMatSrc->row;
    280     pMatDest->col = pMatSrc->col;
    281     pMatDest->unul = pMatSrc->unul;
    282 
    283     return pMatDest->unul;
    284 }
    285 
    286 /**
    287 * @brief 从稀疏矩阵中获取下标为 m, n 元素的值
    288 *
    289 * @param pMat 指向待获取元素的稀疏矩阵
    290 * @param m 元素所在位置的行下标
    291 * @param n 元素所在位置的列下标
    292 * @param pElm 接收数据元素的指针
    293 *
    294 * @return 返回该元素在稀疏矩阵中的位置
    295 *
    296 * @note 位置由 0 计起
    297 */
    298 int Value( const TMatrix *const pMat, int m, int n, ElemType *pElm )
    299 {
    300     ///使用断言确保下标合法
    301     assert( m >= 0 && m < pMat->row && n >= 0 && n < pMat->col );
    302 
    303     int pos = ElemLocate( pMat, m, n );
    304     if( pos != NPOS )
    305     {
    306         *pElm = pMat->tup[pos].elm;
    307         return pos;
    308     }
    309     else
    310     {
    311         *pElm = 0;
    312         return NPOS;
    313     }
    314 }
    315 
    316 /**
    317 * @brief 对稀疏矩阵中的每个元素依次执行 func 函数
    318 *
    319 * @param pMat 指向待处理的稀疏矩阵
    320 * @param func 回调函数
    321 *
    322 * @return void
    323 */
    324 void ForEach( const TMatrix *const pMat, void (*func)(ElemType *pElm) )
    325 {
    326     int m = 0, n = 0, pos = 0, t = 0;
    327 
    328     for( m = 0; m < pMat->row; ++m )
    329         for( n = 0; n < pMat->col; ++n )
    330         {
    331             pos = ElemLocate( pMat, m, n );
    332 
    333             if( pos != NPOS )
    334                 func( &pMat->tup[pos].elm );
    335             else
    336                 func( &t );
    337         }
    338 }
    339 
    340 ///测试
    341 
    342 /**
    343 * @brief ForEach的回调函数, 若元素为 0 则输出'x', 否则正常输出
    344 */
    345 void display( ElemType *pElm )
    346 {
    347     if( *pElm == 0 )
    348         putchar( 'x' );
    349     else
    350         printf( "%d", *pElm );
    351 }
    352 
    353 int main()
    354 {
    355     ///稀疏因子为 0.098 的二维数组
    356     ElemType arrMat[15][15] = {
    357         {0, 9, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0},
    358         {0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    359         {0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0},
    360         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    361         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0},
    362         {0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    363         {0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    364         {0, 0, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 8, 0, 0},
    365         {0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    366         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    367         {0, 7, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0},
    368         {0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 1, 0, 0},
    369         {0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    370         {0, 0, 0, 0, 8, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0},
    371         {0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0}
    372     };
    373 
    374 
    375     ///测试 CreateTMatirxFrom2DArray
    376     ///从二维数组 arrMat 中创建稀疏矩阵
    377     TMatrix *pMat = CreateTMatirxFrom2DArray( arrMat, 15, 15 );
    378     printf( "稀疏矩阵占用空间大小: %d (byte)
    ", GetTMatrixSize(pMat) );
    379 
    380     ///测试 CreateEmptyTMatrix
    381     ///创建一个 5 x 5 大小的稀疏矩阵
    382     TMatrix *pMat2 = CreateEmptyTMatrix( 5, 5 );
    383 
    384     ///测试 TMatrixCopy
    385     ///将 pMat 复制到 pMat2
    386     TMatrixCopy( pMat2, pMat );
    387 
    388     ///测试 DisplayTMatrix
    389     printf( "输出稀疏矩阵 pMat2:
    " );
    390     DisplayTMatrix( pMat2 );
    391 
    392     ///测试 AppendElem
    393     printf( "将 0, 0 处元素置为 1.
    " );
    394     AppendElem( pMat2, 1, 0, 0 );
    395 
    396     ///测试 DeleteElem
    397     printf( "删除 0, 1 处的元素.
    " );
    398     DeleteElem( pMat2, 0, 1 );
    399 
    400     ///输出 pMat2
    401     printf( "输出稀疏矩阵 pMat2:
    " );
    402     DisplayTMatrix( pMat2 );
    403 
    404     ///测试 Value
    405     int a = -1;
    406     Value( pMat2, 10, 8, &a );
    407     printf( "位置 10, 8 处的元素为: %d
    ", a );
    408 
    409     ///测试 ForEach
    410     printf( "将稀疏矩阵中值为0的元素用x代替并全部输出:
    " );
    411     ForEach(pMat2, display );
    412 
    413     ///销毁稀疏矩阵
    414     DestroyTMatrix( pMat );
    415     DestroyTMatrix( pMat2 );
    416 
    417     return 0;
    418 }

    运行测试:

    若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢。                                                                                                                                                                                                                                                                                                                                                            

  • 相关阅读:
    【LeetCode】Validate Binary Search Tree
    【LeetCode】Search in Rotated Sorted Array II(转)
    【LeetCode】Search in Rotated Sorted Array
    【LeetCode】Set Matrix Zeroes
    【LeetCode】Sqrt(x) (转载)
    【LeetCode】Integer to Roman
    贪心算法
    【LeetCode】Best Time to Buy and Sell Stock III
    【LeetCode】Best Time to Buy and Sell Stock II
    CentOS 6 上安装 pip、setuptools
  • 原文地址:https://www.cnblogs.com/mr-wid/p/3407714.html
Copyright © 2011-2022 走看看