稀疏矩陣壓縮存儲的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 或程序缺陷, 請留言反饋, 謝謝。 測試