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( '\n' );
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)\n", 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:\n" );
390     DisplayTMatrix( pMat2 );
391 
392     ///測試 AppendElem
393     printf( "將 0, 0 處元素置爲 1.\n" );
394     AppendElem( pMat2, 1, 0, 0 );
395 
396     ///測試 DeleteElem
397     printf( "刪除 0, 1 處的元素.\n" );
398     DeleteElem( pMat2, 0, 1 );
399 
400     ///輸出 pMat2
401     printf( "輸出稀疏矩陣 pMat2:\n" );
402     DisplayTMatrix( pMat2 );
403 
404     ///測試 Value
405     int a = -1;
406     Value( pMat2, 10, 8, &a );
407     printf( "位置 10, 8 處的元素爲: %d\n", a );
408 
409     ///測試 ForEach
410     printf( "將稀疏矩陣中值爲0的元素用x代替並所有輸出:\n" );
411     ForEach(pMat2, display );
412 
413     ///銷燬稀疏矩陣
414     DestroyTMatrix( pMat );
415     DestroyTMatrix( pMat2 );
416 
417     return 0;
418 }

 

 

運行測試:函數

 

若代碼存在 bug 或程序缺陷, 請留言反饋, 謝謝。                                                                                                                                                                                                                                                                                                                                                            測試

相關文章
相關標籤/搜索