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 或程序缺陷, 请留言反馈, 谢谢。                                                                                                                                                                                                                                                                                                                                                            

  • 相关阅读:
    Python 爬虫 —— BeautifulSoup
    sklearn、theano、TensorFlow 以及 theras 的理解
    sklearn、theano、TensorFlow 以及 theras 的理解
    keras 的使用
    keras 的使用
    古人的字、号、别称
    古人的字、号、别称
    hdu1226 超级密码 (BFS,里面用了大数取余原理)
    2013渣打科营编程马拉松赛样题
    对象序列化实现深度克隆
  • 原文地址:https://www.cnblogs.com/mr-wid/p/3407714.html
Copyright © 2011-2022 走看看