生活随笔
收集整理的這篇文章主要介紹了
数据结构 稀疏矩阵的实现方法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
稀疏矩陣的實現
什么是稀疏矩陣,怎么定義才是稀疏矩陣?假設在m x n的矩陣中,有t個不為0的元素。令z=t/(m x n),若z<=0.05則稱此矩陣為稀疏矩陣。由于稀疏矩陣的非0元素較少,所以如果用大容量存儲必定會造成內存浪費,因此只需存儲非0元素值即可,以下列出了常用的三種存儲稀疏矩陣的方法。
三元組順序表
三元組順序表的實現用順序存儲結構來實現。定義一個數組的結構體,存儲的是三元組(即由 3 部分數據組成的集合),組中數據分別表示(行標,列標,元素值)。結構體的實現如下:
typedef struct { int i
, j
; int data
;
} triple
;
typedef struct { triple data
[ number
] ; int n
, m
, num
;
} TSMatrix
;
如上圖所示即為依次再數組中插入的 三元表。具體實現過程如下所示:
#include <stdio.h>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define ELEMTYPE int typedef struct { int i
; int j
; ELEMTYPE e
;
} Triple
;
typedef struct { Triple data
[ MAXSIZE
+ 1 ] ; int mu
, nu
, tu
;
} TSmatrix
;
void display ( TSmatrix
* s
) ;
int main ( void )
{ TSmatrix s
; s
. mu
= 3 ; s
. nu
= 3 ; s
. tu
= 3 ; s
. data
[ 0 ] . i
= 3 ; s
. data
[ 0 ] . j
= 3 ; s
. data
[ 0 ] . e
= 6 ; s
. data
[ 1 ] . i
= 2 ; s
. data
[ 1 ] . j
= 3 ; s
. data
[ 1 ] . e
= 8 ; s
. data
[ 2 ] . i
= 2 ; s
. data
[ 2 ] . j
= 1 ; s
. data
[ 2 ] . e
= 4 ; display ( & s
) ; getchar ( ) ; return 0 ;
} void display ( TSmatrix
* s
)
{ for ( int i
= 1 ; i
<= s
-> mu
; i
++ ) { for ( int j
= 1 ; j
<= s
-> nu
; j
++ ) { int value
= 0 ; for ( int k
= 0 ; k
< s
-> tu
; k
++ ) { if ( s
-> data
[ k
] . i
== i
&& s
-> data
[ k
] . j
== j
) { value
= 1 ; printf ( "%d " , s
-> data
[ k
] . e
) ; break ; } } if ( value
== 0 ) printf ( "%d " , 0 ) ; } printf ( "\n" ) ; }
}
結果如上圖所示,檢查矩陣可知打印的位置是沒有問題的。 如上所示的方法能夠實現稀疏矩陣的存儲,但是在數據提取方面效率比較低,現在只是3x3的矩陣可能看不出來,但若是m和n都以千萬計的情況下稀疏矩陣中的非0元素個數近似于n,那么時間復雜度就會達到O(m x n xn),這將非常浪費時間。因此在此方法上改進有了下面的方法。
行邏輯鏈接的順序表
行邏輯鏈接順序表示基于上種方法的改進,在上面的基礎上再增加一個數組用來存儲用來用于存儲三元表的數組中每一行第一個非0元素的位置,這樣就無需遍歷整個三元表數組,只需要遍歷對應行的數據就可以了,大大提高了效率。 使用數組 rpos 記錄矩陣中每行第一個非 0 元素在一維數組中的存儲位置。遍歷的具體過程如下所示: 由 rpos 數組可知,第一行首個非 0 元素位于data[1],因此在遍歷此行時,可以直接從第 data[1] 的位置開始,一直遍歷到下一行首個非 0 元素所在的位置(data[3]之前; 同樣遍歷第二行時,由 rpos 數組可知,此行首個非 0 元素位于 data[3],因此可以直接從第 data[3] 開始,一直遍歷到下一行首個非 0 元素所在的位置(data[4])之前; 遍歷第三行時,由 rpos 數組可知,此行首個非 0 元素位于 data[4],由于這是矩陣的最后一行,因此一直遍歷到 rpos 數組結束即可(也就是 data[tu],tu 指的是矩陣非 0 元素的總個數)。
#include <stdio.h>
#define MAXSIZE 100
#define MAXSD 100
#define ELEMTYPE int typedef struct { int i
; int j
; ELEMTYPE e
;
} Triple
;
typedef struct { Triple data
[ MAXSIZE
] ; int rpos
[ MAXSD
] ; int mu
, nu
, tu
;
} RLSmatrix
;
void display ( RLSmatrix
* s
) ;
int main ( void )
{ RLSmatrix s
; s
. mu
= 4 ; s
. nu
= 3 ; s
. tu
= 4 ; s
. data
[ 1 ] . i
= 1 ; s
. data
[ 1 ] . j
= 1 ; s
. data
[ 1 ] . e
= 3 ; s
. data
[ 2 ] . i
= 2 ; s
. data
[ 2 ] . j
= 2 ; s
. data
[ 2 ] . e
= 4 ; s
. data
[ 3 ] . i
= 3 ; s
. data
[ 3 ] . j
= 3 ; s
. data
[ 3 ] . e
= 6 ; s
. data
[ 4 ] . i
= 4 ; s
. data
[ 4 ] . j
= 3 ; s
. data
[ 4 ] . e
= 3 ; s
. rpos
[ 1 ] = 1 ; s
. rpos
[ 2 ] = 2 ; s
. rpos
[ 3 ] = 3 ; s
. rpos
[ 4 ] = 4 ; display ( & s
) ; getchar ( ) ; return 0 ; } void display ( RLSmatrix
* s
)
{ for ( int i
= 1 ; i
<= s
-> mu
; i
++ ) { for ( int j
= 1 ; j
<= s
-> nu
; j
++ ) { int value
= 0 ; if ( i
+ 1 <= s
-> mu
) { for ( int k
= s
-> rpos
[ i
] ; k
< s
-> rpos
[ i
+ 1 ] ; k
++ ) { if ( s
-> data
[ k
] . i
== i
&& s
-> data
[ k
] . j
== j
) { value
= 1 ; printf ( "%d " , s
-> data
[ k
] . e
) ; break ; } if ( value
== 0 ) printf ( "0 " ) ; } } else { for ( int k
= s
-> rpos
[ i
] ; k
<= s
-> tu
; k
++ ) { if ( s
-> data
[ k
] . i
== i
&& s
-> data
[ k
] . j
== j
) { value
= 1 ; printf ( "%d " , s
-> data
[ k
] . e
) ; break ; } if ( value
== 0 ) printf ( "0 " ) ; } } } printf ( "\n" ) ; }
}
十字鏈表法存儲稀疏矩陣
上面兩種存儲方式用于固定存儲時可以很好的起作用,但是當要涉及非0元素的插入或者刪除的時候回引起元素值的移動,例如兩矩陣相加的操作,這種時候用鏈式存儲表示三元組更為恰當,該存儲方式采用的是 “鏈表+數組” 結構。 由上圖可以看到,非0元素用一個含有五個域的節點表示,兩個指針與分別用來指向同一列和同一行的元素。再用兩個存儲行鏈表和列鏈表的一維數組存儲這些鏈表。每一個非0元既是某行鏈表的一個節點,又是列鏈表的一個節點。整個矩陣構成了一個十字交叉的鏈表。
#include <stdio.h>
#include <stdlib.h>
typedef struct OLNode
{ int i
, j
, e
; struct OLNode
* right
, * down
;
} OLNode
, * OLink
;
typedef struct
{ OLink
* rhead
, * chead
; int mu
, nu
, tu
;
} CrossList
;
CrossList
CreateMatrix_OL ( CrossList M
) ;
void display ( CrossList M
) ;
int main ( )
{ CrossList M
; M
. rhead
= NULL ; M
. chead
= NULL ; M
= CreateMatrix_OL ( M
) ; printf ( "輸出矩陣M:\n" ) ; display ( M
) ; return 0 ;
}
CrossList
CreateMatrix_OL ( CrossList M
)
{ int m
, n
, t
; int i
, j
, e
; OLNode
* p
, * q
; printf ( "輸入矩陣的行數、列數和非0元素個數:" ) ; scanf ( "%d%d%d" , & m
, & n
, & t
) ; M
. mu
= m
; M
. nu
= n
; M
. tu
= t
; if ( ! ( M
. rhead
= ( OLink
* ) malloc ( ( m
+ 1 ) * sizeof ( OLink
) ) ) || ! ( M
. chead
= ( OLink
* ) malloc ( ( n
+ 1 ) * sizeof ( OLink
) ) ) ) { printf ( "初始化矩陣失敗" ) ; exit ( 0 ) ; } for ( i
= 1 ; i
<= m
; i
++ ) { M
. rhead
[ i
] = NULL ; } for ( j
= 1 ; j
<= n
; j
++ ) { M
. chead
[ j
] = NULL ; } for ( scanf ( "%d%d%d" , & i
, & j
, & e
) ; 0 != i
; scanf ( "%d%d%d" , & i
, & j
, & e
) ) { if ( ! ( p
= ( OLNode
* ) malloc ( sizeof ( OLNode
) ) ) ) { printf ( "初始化三元組失敗" ) ; exit ( 0 ) ; } p
-> i
= i
; p
-> j
= j
; p
-> e
= e
; if ( NULL == M
. rhead
[ i
] || M
. rhead
[ i
] -> j
> j
) { p
-> right
= M
. rhead
[ i
] ; M
. rhead
[ i
] = p
; } else { for ( q
= M
. rhead
[ i
] ; ( q
-> right
) && q
-> right
-> j
< j
; q
= q
-> right
) ; p
-> right
= q
-> right
; q
-> right
= p
; } if ( NULL == M
. chead
[ j
] || M
. chead
[ j
] -> i
> i
) { p
-> down
= M
. chead
[ j
] ; M
. chead
[ j
] = p
; } else { for ( q
= M
. chead
[ j
] ; ( q
-> down
) && q
-> down
-> i
< i
; q
= q
-> down
) ; p
-> down
= q
-> down
; q
-> down
= p
; } } return M
;
}
void display ( CrossList M
) { for ( int i
= 1 ; i
<= M
. nu
; i
++ ) { if ( NULL != M
. chead
[ i
] ) { OLink p
= M
. chead
[ i
] ; while ( NULL != p
) { printf ( "%d\t%d\t%d\n" , p
-> i
, p
-> j
, p
-> e
) ; p
= p
-> down
; } } }
}
總結
以上是生活随笔 為你收集整理的数据结构 稀疏矩阵的实现方法 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。