實現稀疏矩陣相乘C/C++
1、問題描述:已知稀疏矩陣A(m1,n1)和B(m2,n2),求乘積C(m1,n2)。
A=|3 0 0 7| B=|4 1| C=|12 17|
|0 0 0 -1| |0 0| |0 -2|
|0 2 0 0| |1 -1| |0 0|
|0 2|
A、B、C的三元組表示法分別爲:
A
|
i |
j |
v |
1 |
1 |
1 |
2 |
2 |
1 |
4 |
7 |
3 |
2 |
4 |
-1 |
4 |
3 |
2 |
2 |
B
|
i |
j |
v |
1 |
1 |
1 |
4 |
2 |
1 |
2 |
1 |
3 |
3 |
1 |
1 |
4 |
3 |
2 |
-1 |
5 |
4 |
2 |
2 |
C
|
i |
j |
v |
1 |
1 |
1 |
12 |
2 |
1 |
2 |
17 |
3 |
2 |
2 |
-2 |
2、解決思路:由矩陣乘法規則可知C(i,j) = A(i,1)*B(1,j)+A(i,2)*B(2,j)+....+A(i,n)*B(n,j),即C(i,j)爲A的第i行與B的第j列非零元素乘積之和。設置累加器temp[B的列值]保存C矩陣每行的值,結束後將temp中的值賦給C矩陣。
3、定義數據結構:
3.1、稀疏矩陣中節點的定義:
//定義三元組表的節點
typedef struct{
int i,j;
int v;
}SPNode;
i,j爲行列值,v爲此位置的數值。
3.2、稀疏矩陣的定義:
//定義三元組表
typedef struct{
int mu,nu,tu;
SPNode data[SMAX];
}SPMatrix;
mu爲矩陣行數,nu爲矩陣列數,tu爲矩陣中非零元素的個數。
4、具體實現:
爲了便於B.data尋找第k行第一個非零元素,在此引入num和rpot兩個內容。num[k]表示矩陣B中第k行非零元素的個數;rpot[k]表示第k行的第一個非零元素在B.data中的位置。
rpot[1] = 0;
rpot[k] = rpot[k-1]+num[k-1];
矩陣B中的num與rpot的值
col |
1 |
2 |
3 |
4 |
num[col] |
2 |
0 |
2 |
0 |
rpot[col] |
0 |
2 |
2 |
4 |
4.1、初始化。清理一些單元,準備按行順序存放乘積矩陣。
4.2、求B的num與rpot。
4.3、做矩陣的乘法。
5、代碼的具體實現:
/*
*進行兩個稀疏矩陣之間的乘法
*/
#include<stdio.h>
#include<malloc.h>
#define SMAX 1024
//定義三元組表的節點
typedef struct{
int i,j;
int v;
}SPNode;
//定義三元組表
typedef struct{
int mu,nu,tu;
SPNode data[SMAX];
}SPMatrix;
//進行兩個稀疏矩陣之間的乘法,返回值爲乘積矩陣
SPMatrix * MulSMatrix(SPMatrix *A,SPMatrix *B){
SPMatrix *C;
int p,j,q,i,r,k,t;
//用於結果的暫存
int temp[B->nu+1];
int num[B->mu+1],rpot[B->mu+1];
C = (SPMatrix*)malloc(sizeof(SPMatrix));
if(C==NULL){
printf("申請內存空間失敗!\n");
return NULL;
}
//A的列值與B的行值不相等時
if(A->nu!=B->mu) return NULL;
C->mu = A->mu;
C->nu = B->nu;
//當A或B中的非零元素爲0時
if(A->tu*B->tu==0){
C->tu = 0;
return C;
}
//計算B矩陣中每行非0元素的個數
for(i = 1;i<=B->mu;i++)
num[i] = 0;
for(i = 0;i<B->tu;i++)
num[B->data[i].i]++;
rpot[1] = 0;
//計算B矩陣中每行首位非0元素的位置
for(i = 2;i<=B->mu;i++)
rpot[i] = rpot[i-1]+num[i-1];
r = 0;//記錄當前C矩陣中非0元素的個數
p = 0;//指示當前A矩陣中非零元素的位置
//進行矩陣的乘積運算
for(i = 1;i<=A->mu;i++){
//將Cij的累加器初始化
for(j = 1;j<=B->nu;j++)
temp[j] = 0;
//求Cij第i行的元素集合
while(i==A->data[p].i){
k = A->data[p].j;//獲取A矩陣中第p個非零元素的列值
//確定B中的k行的非零元素在B.data中的下限位置
if(k<B->mu) t = rpot[k+1];
else t = B->tu;
//將B中第k行的每一列非零元素與A中非零元素記錄到累加器中
for(q = rpot[k];q<t;q++){
j = B->data[q].j;
temp[j] += A->data[p].v*B->data[q].v;
}
p++;
}
//將第i行的結果賦值給C矩陣
for(j = 1;j<=B->nu;j++){
if(temp[j]!=0){
C->data[r] = {i,j,temp[j]};
r++;
}
}
}
C->tu = r;
return C;
}
int main(){
SPMatrix *A,*B,*C;
int i;
A = (SPMatrix*)malloc(sizeof(SPMatrix));
B = (SPMatrix*)malloc(sizeof(SPMatrix));
printf("請輸入A矩陣的行列值與非零元素");
scanf("%d %d %d",&A->mu,&A->nu,&A->tu);
printf("請輸入A矩陣的非零元素值:\n");
for(i = 0;i<A->tu;i++)
scanf("%d %d %d",&A->data[i].i,&A->data[i].j,&A->data[i].v);
printf("請輸入B矩陣的行列值與非零元素");
scanf("%d %d %d",&B->mu,&B->nu,&B->tu);
printf("請輸入B矩陣陣的非零元素值:\n");
for(i = 0;i<B->tu;i++)
scanf("%d %d %d",&B->data[i].i,&B->data[i].j,&B->data[i].v);
C = MulSMatrix(A,B);
printf("C->nu:%d,C->mu:%d,C->tu:%d\n",C->mu,C->nu,C->tu);
for(i = 0;i<C->tu;i++)
printf("i:%d,j:%d,v:%d\n",C->data[i].i,C->data[i].j,C->data[i].v);
delete A,B,C;
return 0;
}
5、算法的時間複雜度:
5.1、求num的時間複雜度爲:O(2*B->nu)
5.2、求rpot的時間複雜度爲:O(B->mu)
5.3、求temp的時間複雜度爲:O(A->mu*B->nu)
5.4、求C中所有元素的時間複雜度爲:O(A->tu*B->tu/B->mu)