// c5-2.h 稀疏矩陣的三元組順序表存儲表示(見圖5.4)
#define MAX_SIZE 100 // 非零元個數的最大值
struct Triple
{
int i,j; // 行下標,列下標
ElemType e; // 非零元素值
};
struct TSMatrix
{
Triple data[MAX_SIZE+1]; // 非零元三元組表,data[0]未用
int mu,nu,tu; // 矩陣的行數、列數和非零元個數
};
圖55 是採用三元組順序表存儲稀疏矩陣的例子。爲簡化算法,在創建稀疏矩陣輸
入非零元時,要按行、列的順序由小到大輸入。
// bo5-2.cpp 三元組稀疏矩陣的基本操作(8個),包括算法5.1
Status CreateSMatrix(TSMatrix &M)
{ // 創建稀疏矩陣M
int i,m,n;
ElemType e;
Status k;
printf("請輸入矩陣的行數,列數,非零元素數:");
scanf("%d,%d,%d",&M.mu,&M.nu,&M.tu);
if(M.tu>MAX_SIZE)
return ERROR;
M.data[0].i=0; // 爲以下比較順序做準備
for(i=1;i<=M.tu;i++)
{
do
{
printf("請按行序順序輸入第%d個非零元素所在的行(1~%d),列(1~%d),元素值:",i,M.mu,M.nu);
scanf("%d,%d,%d",&m,&n,&e);
k=0;
if(m<1||m>M.mu||n<1||n>M.nu) // 行或列超出範圍
k=1;
if(m<M.data[i-1].i||m==M.data[i-1].i&&n<=M.data[i-1].j) // 行或列的順序有錯
k=1;
}while(k);
M.data[i].i=m;
M.data[i].j=n;
M.data[i].e=e;
}
return OK;
}
void DestroySMatrix(TSMatrix &M)
{ // 銷燬稀疏矩陣M(見圖5.6)
M.mu=M.nu=M.tu=0;
}
void PrintSMatrix(TSMatrix M)
{ // 輸出稀疏矩陣M
int i;
printf("%d行%d列%d個非零元素。\n",M.mu,M.nu,M.tu);
printf("行列元素值\n");
for(i=1;i<=M.tu;i++)
printf("%2d%4d%8d\n",M.data[i].i,M.data[i].j,M.data[i].e);
}
void PrintSMatrix1(TSMatrix M)
{ // 按矩陣形式輸出M
int i,j,k=1;
Triple *p=M.data;
p++; // p指向第1個非零元素
for(i=1;i<=M.mu;i++)
{
for(j=1;j<=M.nu;j++)
if(k<=M.tu&&p->i==i&&p->j==j) // p指向非零元,且p所指元素爲當前處理元素
{
printf("%3d",p->e); // 輸出p所指元素的值
p++; // p指向下一個元素
k++; // 計數器+1
}
else // p所指元素不是當前處理元素
printf("%3d",0); // 輸出0
printf("\n");
}
}
void CopySMatrix(TSMatrix M,TSMatrix &T)
{ // 由稀疏矩陣M複製得到T
T=M;
}
int comp(int c1,int c2)
{ // AddSMatrix函數要用到,另加
if(c1<c2)
return -1;
if(c1==c2)
return 0;
return 1;
}
Status AddSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{ // 求稀疏矩陣的和Q=M+N
int m=1,n=1,q=0;
if(M.mu!=N.mu||M.nu!=N.nu) // M、N兩稀疏矩陣行或列數不同
return ERROR;
Q.mu=M.mu;
Q.nu=M.nu;
while(m<=M.tu&&n<=N.tu) // 矩陣M和N的元素都沒處理完
{
switch(comp(M.data[m].i,N.data[n].i))
{
case -1: Q.data[++q]=M.data[m++]; // 將矩陣M的當前元素值賦給矩陣Q
break;
case 0: switch(comp(M.data[m].j,N.data[n].j)) // M、N矩陣當前元素的行相等,繼續比較列
{
case -1: Q.data[++q]=M.data[m++];
break;
case 0: Q.data[++q]=M.data[m++]; // M、N矩陣當前非零元素的行列均相等
Q.data[q].e+=N.data[n++].e; //矩陣M、N的當前元素值求和並賦給矩陣Q
if(Q.data[q].e==0) // 元素值爲0,不存入壓縮矩陣
q--;
break;
case 1: Q.data[++q]=N.data[n++];
}
break;
case 1: Q.data[++q]=N.data[n++]; // 將矩陣N的當前元素值賦給矩陣Q
}
}
while(m<=M.tu) // 矩陣N的元素全部處理完畢
Q.data[++q]=M.data[m++];
while(n<=N.tu) // 矩陣M的元素全部處理完畢
Q.data[++q]=N.data[n++];
Q.tu=q; // 矩陣Q的非零元素個數
if(q>MAX_SIZE) // 非零元素個數太多
return ERROR;
return OK;
}
Status SubtSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{ // 求稀疏矩陣的差Q=M-N
int i;
for(i=1;i<=N.tu;i++)
N.data[i].e*=-1;
return AddSMatrix(M,N,Q);
}
void TransposeSMatrix(TSMatrix M,TSMatrix &T)
{ // 求稀疏矩陣M的轉置矩陣T。算法5.1改
int p,q,col;
T.mu=M.nu;
T.nu=M.mu;
T.tu=M.tu;
if(T.tu)
{
q=1;
for(col=1;col<=M.nu;++col)
for(p=1;p<=M.tu;++p)
if(M.data[p].j==col)
{
T.data[q].i=M.data[p].j;
T.data[q].j=M.data[p].i;
T.data[q].e=M.data[p].e;
++q;
}
}
}
Status MultSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q)
{ // 求稀疏矩陣的乘積Q=M×N
int i,j;
ElemType *Nc,*Tc;
TSMatrix T; // 臨時矩陣
if(M.nu!=N.mu)
return ERROR;
T.nu=M.mu; // 臨時矩陣T是Q的轉秩矩陣
T.mu=N.nu;
T.tu=0;
Nc=(ElemType*)malloc((N.mu+1)*sizeof(ElemType));//Nc爲矩陣N一列的臨時數組(非壓縮,[0]不用)
Tc=(ElemType*)malloc((M.nu+1)*sizeof(ElemType));//Tc爲矩陣T一行的臨時數組(非壓縮,[0]不用)
if(!Nc||!Tc) // 創建臨時數組不成功
exit(ERROR);
for(i=1;i<=N.nu;i++) // 對於N的每一列
{
for(j=1;j<=N.mu;j++)
Nc[j]=0; // 矩陣Nc的初值爲0
for(j=1;j<=M.mu;j++)
Tc[j]=0; // 臨時數組Tc的初值爲0,[0]不用
for(j=1;j<=N.tu;j++) // 對於N的每一個非零元素
if(N.data[j].j==i) // 屬於第i列
Nc[N.data[j].i]=N.data[j].e; // 根據其所在行將其元素值賦給相應的Nc
for(j=1;j<=M.tu;j++) // 對於M的每一個值
Tc[M.data[j].i]+=M.data[j].e*Nc[M.data[j].j]; // Tc中存N的第i列與M相乘的結果
for(j=1;j<=M.mu;j++)
if(Tc[j]!=0)
{
T.data[++T.tu].e=Tc[j];
T.data[T.tu].i=i;
T.data[T.tu].j=j;
}
}
if(T.tu>MAX_SIZE) // 非零元素個數太多
return ERROR;
TransposeSMatrix(T,Q); // 將T的轉秩賦給Q
DestroySMatrix(T); // 銷燬臨時矩陣T
free(Tc); // 釋放動態數組Tc和Nc
free(Nc);
return OK;
}
// main5-2.cpp 檢驗bo5-2.cpp的主程序
#include"c1.h"
typedef int ElemType;
#include"c5-2.h"
#include"bo5-2.cpp"
void main()
{
TSMatrix A,B,C;
printf("創建矩陣A: ");
CreateSMatrix(A);
PrintSMatrix(A);
printf("由矩陣A複製矩陣B:\n");
CopySMatrix(A,B);
PrintSMatrix1(B);
DestroySMatrix(B);
printf("銷燬矩陣B後:\n");
PrintSMatrix1(B);
printf("創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲%d,%d)\n",A.mu,A.nu);
CreateSMatrix(B);
PrintSMatrix1(B);
AddSMatrix(A,B,C);
printf("矩陣C1(A+B):\n");
PrintSMatrix1(C);
SubtSMatrix(A,B,C);
printf("矩陣C2(A-B):\n");
PrintSMatrix1(C);
TransposeSMatrix(A,C);
printf("矩陣C3(A的轉置):\n");
PrintSMatrix1(C);
printf("創建矩陣A2: ");
CreateSMatrix(A);
PrintSMatrix1(A);
printf("創建矩陣B3:(行數應與矩陣A2的列數相同=%d)\n",A.nu);
CreateSMatrix(B);
PrintSMatrix1(B);
MultSMatrix(A,B,C);
printf("矩陣C5(A×B):\n");
PrintSMatrix1(C);
}
代碼的運行結果:
創建矩陣A: 請輸入矩陣的行數,列數,非零元素數:3,3,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~3),元素值:2,2,2
3行3列2個非零元素。(見圖57)
行列元素值
1 2 1
2 2 2
由矩陣A複製矩陣B:
0 1 0
0 2 0
0 0 0
銷燬矩陣B後:
創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲3,3)
請輸入矩陣的行數,列數,非零元素數:3,3,1
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
0 1 0
0 0 0
0 0 0
矩陣C1(A+B):
0 2 0
0 2 0
0 0 0
矩陣C2(A-B):
0 0 0
0 2 0
0 0 0
矩陣C3(A的轉置):
0 0 0
1 2 0
0 0 0
創建矩陣A2: 請輸入矩陣的行數,列數,非零元素數:2,3,2
請按行序順序輸入第1個非零元素所在的行(1~2),列(1~3),元素值:1,1,1
請按行序順序輸入第2個非零元素所在的行(1~2),列(1~3),元素值:2,3,2
1 0 0
0 0 2
創建矩陣B3:(行數應與矩陣A2的列數相同=3)
請輸入矩陣的行數,列數,非零元素數:3,2,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~2),元素值:2,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~2),元素值:3,1,2
0 0
0 1
2 0
矩陣C5(A×B):
0 0
4 0
// algo5-1.cpp 實現算法5.2的程序
#include"c1.h"
typedef int ElemType;
#include"c5-2.h"
#include"bo5-2.cpp"
void FastTransposeSMatrix(TSMatrix M,TSMatrix &T)
{ // 快速求稀疏矩陣M的轉置矩陣T。算法5.2改
int p,q,t,col,*num,*cpot;
num=(int *)malloc((M.nu+1)*sizeof(int)); // 存M每列(T每行)非零元素個數([0]不用)
cpot=(int *)malloc((M.nu+1)*sizeof(int)); // 存T每行的下1個非零元素的存儲位置([0]不用)
T.mu=M.nu; // 給T的行、列數與非零元素個數賦值
T.nu=M.mu;
T.tu=M.tu;
if(T.tu) // 是非零矩陣
{
for(col=1;col<=M.nu;++col)
num[col]=0; // 計數器初值設爲0
for(t=1;t<=M.tu;++t) // 求M中每一列含非零元素個數
++num[M.data[t].j];
cpot[1]=1; // T的第1行的第1個非零元在T.data中的序號爲1
for(col=2;col<=M.nu;++col)
cpot[col]=cpot[col-1]+num[col-1]; // 求T的第col行的第1個非零元在T.data中的序號
for(p=1;p<=M.tu;++p) // 從M的第1個元素開始
{
col=M.data[p].j; // 求得在M中的列數
q=cpot[col]; // q指示M當前的元素在T中的序號
T.data[q].i=M.data[p].j;
T.data[q].j=M.data[p].i;
T.data[q].e=M.data[p].e;
++cpot[col]; // T第col行的下1個非零元在T.data中的序號
}
}
free(num);
free(cpot);
}
void main()
{
TSMatrix A,B;
printf("創建矩陣A: ");
CreateSMatrix(A);
PrintSMatrix1(A);
FastTransposeSMatrix(A,B);
printf("矩陣B(A的快速轉置):\n");
PrintSMatrix1(B);
}
代碼的運行結果:
創建矩陣A: 請輸入矩陣的行數,列數,非零元素數:3,2,4
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~2),元素值:1,1,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~2),元素值:2,1,2
請按行序順序輸入第3個非零元素所在的行(1~3),列(1~2),元素值:3,1,3
請按行序順序輸入第4個非零元素所在的行(1~3),列(1~2),元素值:3,2,4
1 0
2 0
3 4
矩陣B(A的快速轉置):
1 2 3
0 0 4
由於稀疏矩陣的三元組順序表存儲結構要求先按行、同行再按列順序存儲非零元素,
算法5.1(在bo5-2.cpp 中)採用了雙重循環求轉置矩陣,對於外層循環col(列)的每一個
值,對所有的非零元素,如果其列數與col 相等,則按順序存入轉秩矩陣。這就保證了轉
秩矩陣也是先按行、同行再按列順序存儲非零元素。所以它的時間複雜度爲O(列數×非
零元素數)。而算法5.2(在algo5-1.cpp 中)採用了2 個單循環。第1 個循環,對所有的非
零元素,計算其所在列並計數,得到每列的非零元素數num[col]及每列第1 個非零元素在
轉秩矩陣中的存儲位置cpot[col]。第2 個循環,對所有的非零元素,根據其列數和
cpot[col]的當前值,存入轉秩矩陣。由於還要給num[col]和cpot[col]賦初值,它的時間復
雜度爲O(列數+非零元素數)。
// c5-3.h 稀疏矩陣的三元組行邏輯鏈接的順序表存儲表示(見圖5.8)
#define MAX_SIZE 100 // 非零元個數的最大值
#define MAX_RC 20 // 最大行列數
struct Triple // 同c5-2.h
{
int i,j; // 行下標,列下標
ElemType e; // 非零元素值
};
struct RLSMatrix
{
Triple data[MAX_SIZE+1]; // 非零元三元組表,data[0]未用
int rpos[MAX_RC+1]; // 各行第一個非零元素的位置表,比c5-2.h增加的項
int mu,nu,tu; // 矩陣的行數、列數和非零元個數
};
三元組行邏輯鏈接的順序表存儲表示(c5-3.h)比三元組順序表存儲表示(c5-2.h)增加
了rpos 數組,用以存放各行的第一個非零元素在data 數組中的位置。這樣,就可以迅速地
找到某一行的元素。圖59 是採用三元組行邏輯鏈接的順序表存儲稀疏矩陣的實例。和
c5-2.h 存儲結構一樣,創建稀疏矩陣輸入非零元時,也要按行、列的順序由小到大輸入。
// bo5-3.cpp 行邏輯鏈接稀疏矩陣(存儲結構由c5-3.h定義)的基本操作(8個),包括算法5.3
Status CreateSMatrix(RLSMatrix &M)
{ // 創建稀疏矩陣M
int i,j;
Triple T;
Status k;
printf("請輸入矩陣的行數,列數,非零元素數:");
scanf("%d,%d,%d",&M.mu,&M.nu,&M.tu);
if(M.tu>MAX_SIZE||M.mu>MAX_RC)
return ERROR;
M.data[0].i=0; // 爲以下比較做準備
for(i=1;i<=M.tu;i++)
{
do
{
printf("請按行序順序輸入第%d個非零元素所在的行(1~%d),列(1~%d),元素值:",i,M.mu,M.nu);
scanf("%d,%d,%d",&T.i,&T.j,&T.e);
k=0;
if(T.i<1||T.i>M.mu||T.j<1||T.j>M.nu) // 行、列超出範圍
k=1;
if(T.i<M.data[i-1].i||T.i==M.data[i-1].i&&T.j<=M.data[i-1].j)//沒有按順序輸入非零元素
k=1;
}while(k); // 當輸入有誤,重新輸入
M.data[i]=T;
}
for(i=1;i<=M.mu;i++) // 給rpos[]賦初值0
M.rpos[i]=0;
for(i=1;i<=M.tu;i++) // 計算每行非零元素數並賦給rpos[]
M.rpos[M.data[i].i]++;
for(i=M.mu;i>=1;i--) // 計算rpos[]
{
M.rpos[i]=1; // 賦初值1
for(j=i-1;j>=1;j--)
M.rpos[i]+=M.rpos[j];
}
return OK;
}
void DestroySMatrix(RLSMatrix &M)
{ // 銷燬稀疏矩陣M(使M爲0行0列0個非零元素的矩陣)
M.mu=M.nu=M.tu=0;
}
void PrintSMatrix(RLSMatrix M)
{ // 輸出稀疏矩陣M
int i;
printf("%d行%d列%d個非零元素。\n",M.mu,M.nu,M.tu);
printf("行列元素值\n");
for(i=1;i<=M.tu;i++)
printf("%2d%4d%8d\n",M.data[i].i,M.data[i].j,M.data[i].e);
for(i=1;i<=M.mu;i++)
printf("第%d行的第一個非零元素是本矩陣第%d個元素\n",i,M.rpos[i]);
}
void PrintSMatrix1(RLSMatrix M)
{ // 按矩陣形式輸出M
int i,j,k=1;
Triple *p=M.data;
p++; // p指向第1個非零元素
for(i=1;i<=M.mu;i++)
{
for(j=1;j<=M.nu;j++)
if(k<=M.tu&&p->i==i&&p->j==j) // p指向非零元,且p所指元素爲當前處理元素
{
printf("%3d",p->e); // 輸出p所指元素的值
p++; // p指向下一個元素
k++; // 計數器+1
}
else // p所指元素不是當前處理元素
printf("%3d",0); // 輸出0
printf("\n");
}
}
void CopySMatrix(RLSMatrix M,RLSMatrix &T)
{ // 由稀疏矩陣M複製得到T
T=M;
}
Status AddSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q)
{ // 求稀疏矩陣的和Q=M+N
int k,p,q,tm,tn;
if(M.mu!=N.mu||M.nu!=N.nu)
return ERROR;
Q.mu=M.mu; // Q矩陣行數
Q.nu=M.nu; // Q矩陣列數
Q.tu=0; // Q矩陣非零元素數初值
for(k=1;k<=M.mu;++k) // 對於每一行,k指示行號
{
Q.rpos[k]=Q.tu+1; // Q矩陣第k行的第1個元素的位置
p=M.rpos[k]; // p指示M矩陣第k行當前元素的序號
q=N.rpos[k]; // q指示N矩陣第k行當前元素的序號
if(k==M.mu) // 是最後一行
{
tm=M.tu+1; // tm,tn分別是p,q的上界
tn=N.tu+1;
}
else
{
tm=M.rpos[k+1];
tn=N.rpos[k+1];
}
while(p<tm&&q<tn) // M,N矩陣均有第k行元素未處理
if(M.data[p].j==N.data[q].j) // M矩陣當前元素的列=N矩陣當前元素的列
{
if(M.data[p].e+N.data[q].e!=0) // 和不爲0,存入Q
{
Q.data[++Q.tu]=M.data[p];
Q.data[Q.tu].e+=N.data[q].e;
}
p++;
q++;
}
else if(M.data[p].j<N.data[q].j) // M矩陣當前元素的列<N矩陣當前元素的列
Q.data[++Q.tu]=M.data[p++]; // 將M的當前值賦給Q
else // M矩陣當前元素的列>N矩陣當前元素的列
Q.data[++Q.tu]=N.data[q++]; // 將N的當前值賦給Q
while(p<tm) // M矩陣還有第k行的元素未處理
Q.data[++Q.tu]=M.data[p++]; // 將M的當前值賦給Q
while(q<tn) // N矩陣還有k行的元素未處理
Q.data[++Q.tu]=N.data[q++]; // 將N的當前值賦給Q
}
if(Q.tu>MAX_SIZE)
return ERROR;
else
return OK;
}
Status SubtSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q)
{ // 求稀疏矩陣的差Q=M-N
int i;
if(M.mu!=N.mu||M.nu!=N.nu)
return ERROR;
for(i=1;i<=N.tu;++i) // 對於N的每一元素,其值乘以-1
N.data[i].e*=-1;
AddSMatrix(M,N,Q); // Q=M+(-N)
return OK;
}
Status MultSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q)
{ // 求稀疏矩陣乘積Q=M×N。算法5.3改
int arow,brow,p,q,ccol,ctemp[MAX_RC+1],t,tp;
if(M.nu!=N.mu) // 矩陣M的列數應和矩陣N的行數相等
return ERROR;
Q.mu=M.mu; // Q初始化
Q.nu=N.nu;
Q.tu=0;
if(M.tu*N.tu==0) // M和N至少有一個是零矩陣
return ERROR;
for(arow=1;arow<=M.mu;++arow)
{ // 從M的第一行開始,到最後一行,arow是M的當前行
for(ccol=1;ccol<=Q.nu;++ccol)
ctemp[ccol]=0; // Q的當前行的各列元素累加器清零
Q.rpos[arow]=Q.tu+1; // Q當前行的第1個元素位於上1行最後1個元素之後
if(arow<M.mu)
tp=M.rpos[arow+1];
else
tp=M.tu+1; // 給最後1行設界
for(p=M.rpos[arow];p<tp;++p)
{ // 對M當前行中每一個非零元
brow=M.data[p].j; // 找到對應元在N中的行號(M當前元的列號)
if(brow<N.mu)
t=N.rpos[brow+1];
else
t=N.tu+1; // 給最後1行設界
for(q=N.rpos[brow];q<t;++q)
{
ccol=N.data[q].j; // 乘積元素在Q中列號
ctemp[ccol]+=M.data[p].e*N.data[q].e;
}
} // 求得Q中第arow行的非零元
for(ccol=1;ccol<=Q.nu;++ccol) // 壓縮存儲該行非零元
if(ctemp[ccol]!=0)
{
if(++Q.tu>MAX_SIZE)
return ERROR;
Q.data[Q.tu].i=arow;
Q.data[Q.tu].j=ccol;
Q.data[Q.tu].e=ctemp[ccol];
}
}
return OK;
}
void TransposeSMatrix(RLSMatrix M,RLSMatrix &T)
{ // 求稀疏矩陣M的轉置矩陣T
int p,q,t,col,*num;
num=(int *)malloc((M.nu+1)*sizeof(int));
T.mu=M.nu;
T.nu=M.mu;
T.tu=M.tu;
if(T.tu)
{
for(col=1;col<=M.nu;++col)
num[col]=0; // 設初值
for(t=1;t<=M.tu;++t) // 求M中每一列非零元個數
++num[M.data[t].j];
T.rpos[1]=1;
for(col=2;col<=M.nu;++col) // 求M中第col中第一個非零元在T.data中的序號
T.rpos[col]=T.rpos[col-1]+num[col-1];
for(col=1;col<=M.nu;++col)
num[col]=T.rpos[col];
for(p=1;p<=M.tu;++p)
{
col=M.data[p].j;
q=num[col];
T.data[q].i=M.data[p].j;
T.data[q].j=M.data[p].i;
T.data[q].e=M.data[p].e;
++num[col];
}
}
free(num);
}
// main5-3.cpp 檢驗bo5-3.cpp的主程序(與main5-2.cpp很相像)
#include"c1.h"
typedef int ElemType;
#include"c5-3.h" // 此行與main5-2.cpp不同
#include"bo5-3.cpp" // 此行與main5-2.cpp不同
void main()
{
RLSMatrix A,B,C; // 此行與main5-2.cpp不同
printf("創建矩陣A: ");
CreateSMatrix(A);
PrintSMatrix(A);
printf("由矩陣A複製矩陣B:\n");
CopySMatrix(A,B);
PrintSMatrix1(B);
DestroySMatrix(B);
printf("銷燬矩陣B後:\n");
PrintSMatrix1(B);
printf("創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲%d,%d)\n",A.mu,A.nu);
CreateSMatrix(B);
PrintSMatrix1(B);
AddSMatrix(A,B,C);
printf("矩陣C1(A+B):\n");
PrintSMatrix1(C);
SubtSMatrix(A,B,C);
printf("矩陣C2(A-B):\n");
PrintSMatrix1(C);
TransposeSMatrix(A,C);
printf("矩陣C3(A的轉置):\n");
PrintSMatrix1(C);
printf("創建矩陣A2:\n");
CreateSMatrix(A);
PrintSMatrix1(A);
printf("創建矩陣B3:(行數應與矩陣A2的列數相同=%d)\n",A.nu);
CreateSMatrix(B);
PrintSMatrix1(B);
MultSMatrix(A,B,C);
printf("矩陣C5(A×B):\n");
PrintSMatrix1(C);
}
代碼的運行結果:
創建矩陣A: 請輸入矩陣的行數,列數,非零元素數:3,3,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~3),元素值:2,2,2
3行3列2個非零元素。(見圖57)
行列元素值
1 2 1
2 2 2
第1行的第一個非零元素是本矩陣第1個元素
第2行的第一個非零元素是本矩陣第2個元素
第3行的第一個非零元素是本矩陣第3個元素
由矩陣A複製矩陣B:
0 1 0
0 2 0
0 0 0
銷燬矩陣B後:
創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲3,3)
請輸入矩陣的行數,列數,非零元素數:3,3,1
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~3),元素值:1,2,1
0 1 0
0 0 0
0 0 0
矩陣C1(A+B):
0 2 0
0 2 0
0 0 0
矩陣C2(A-B):
0 0 0
0 2 0
0 0 0
矩陣C3(A的轉置):
0 0 0
1 2 0
0 0 0
創建矩陣A2:
請輸入矩陣的行數,列數,非零元素數:2,3,2
請按行序順序輸入第1個非零元素所在的行(1~2),列(1~3),元素值:1,1,1
請按行序順序輸入第2個非零元素所在的行(1~2),列(1~3),元素值:2,3,2
1 0 0
0 0 2
創建矩陣B3:(行數應與矩陣A2的列數相同=3)
請輸入矩陣的行數,列數,非零元素數:3,2,2
請按行序順序輸入第1個非零元素所在的行(1~3),列(1~2),元素值:2,2,1
請按行序順序輸入第2個非零元素所在的行(1~3),列(1~2),元素值:3,1,2
0 0
0 1
2 0
矩陣C5(A×B):
0 0
4 0
// c5-4.h 稀疏矩陣的十字鏈表存儲表示(見圖5.10)
struct OLNode
{
int i,j; // 該非零元的行和列下標
ElemType e; // 非零元素值
OLNode *right,*down;
// 該非零元所在行表和列表的後繼鏈域
};
typedef OLNode *OLink;
struct CrossList
{
OLink *rhead,*chead;
// 行和列鏈表頭指針向量基址,由CreatSMatrix_OL()分配
int mu,nu,tu; // 稀疏矩陣的行數、列數和非零元個數
};
圖511 是採用十字鏈表存儲稀疏矩陣的實例(教科書圖5.6)。由於十字鏈表存儲結
構中的非零元素是按其所在行、列插入相應的鏈表的,所以,在創建稀疏矩陣輸入非零元
時,可以按任意順序輸入非零元素。每個非零元結點按升序被插入到兩個沒有頭結點的單
鏈表中:一個是所在行鏈表;另一個是所在列鏈表。當插入或刪除結點時,只要修改相關的行、列鏈表即可,比較靈活。
// bo5-4.cpp 稀疏矩陣的十字鏈表存儲(存儲結構由c5-4.h定義)的基本操作(9個),包括算法5.4
void InitSMatrix(CrossList &M)
{ // 初始化M(CrossList類型的變量必須初始化,否則創建、複製矩陣將出錯)。加(見圖5.12)
M.rhead=M.chead=NULL;
M.mu=M.nu=M.tu=0;
}
void InitSMatrixList(CrossList &M)
{ // 初始化十字鏈表表頭指針向量。加(見圖5.13)
int i;
if(!(M.rhead=(OLink*)malloc((M.mu+1)*sizeof(OLink))))
// 生成行表頭指針向量
exit(OVERFLOW);
if(!(M.chead=(OLink*)malloc((M.nu+1)*sizeof(OLink))))
// 生成列表頭指針向量
exit(OVERFLOW);
for(i=1;i<=M.mu;i++)
// 初始化矩陣T的行表頭指針向量,各行鏈表爲空
M.rhead[i]=NULL;
for(i=1;i<=M.nu;i++)
// 初始化矩陣T的列表頭指針向量,各列鏈表爲空
M.chead[i]=NULL;
}
void InsertAscend(CrossList &M,OLink p)
{ // 初始條件:稀疏矩陣M存在,p指向的結點存在。
// 操作結果:按行列升序將p所指結點插入M(見圖5.14)
OLink q=M.rhead[p->i]; // q指向待插行表
if(!q||p->j<q->j) // 待插的行表空或p所指結點的列值小於首結點的列值
{
p->right=M.rhead[p->i]; // 插在表頭
M.rhead[p->i]=p;
}
else
{
while(q->right&&q->right->j<p->j)//q所指不是尾結點且q的下一結點的列值小於p所指結點的列值
q=q->right; // q向後移
p->right=q->right; // 將p插在q所指結點之後
q->right=p;
}
q=M.chead[p->j]; // q指向待插列表
if(!q||p->i<q->i) // 待插的列表空或p所指結點的行值小於首結點的行值
{
p->down=M.chead[p->j]; // 插在表頭
M.chead[p->j]=p;
}
else
{
while(q->down&&q->down->i<p->i) //q所指不是尾結點且q的下一結點的行值小於p所指結點的行值
q=q->down; // q向下移
p->down=q->down; // 將p插在q所指結點之下
q->down=p;
}
M.tu++;
}
void DestroySMatrix(CrossList &M)
{ // 初始條件:稀疏矩陣M存在。操作結果:銷燬稀疏矩陣M(見圖5.12)
int i;
OLink p,q;
for(i=1;i<=M.mu;i++) // 按行釋放結點
{
p=*(M.rhead+i);
while(p)
{
q=p;
p=p->right;
free(q);
}
}
free(M.rhead);
free(M.chead);
InitSMatrix(M);
}
void CreateSMatrix(CrossList &M)
{ // 創建稀疏矩陣M,採用十字鏈表存儲表示。算法5.4改
int i,k;
OLink p;
if(M.rhead)
DestroySMatrix(M);
printf("請輸入稀疏矩陣的行數列數非零元個數: ");
scanf("%d%d%d",&M.mu,&M.nu,&i);
InitSMatrixList(M); // 初始化M的表頭指針向量
printf("請按任意次序輸入%d個非零元的行列元素值:\n",M.tu);
for(k=0;k<i;k++)
{
p=(OLink)malloc(sizeof(OLNode)); // 生成結點
if(!p)
exit(OVERFLOW);
scanf("%d%d%d",&p->i,&p->j,&p->e); // 給結點的3個成員賦值
InsertAscend(M,p); // 將結點p按行列值升序插到矩陣M中
}
}
void PrintSMatrix(CrossList M)
{ // 初始條件:稀疏矩陣M存在。操作結果:按行或按列輸出稀疏矩陣M
int i,j;
OLink p;
printf("%d行%d列%d個非零元素\n",M.mu,M.nu,M.tu);
printf("請輸入選擇(1.按行輸出2.按列輸出): ");
scanf("%d",&i);
switch(i)
{
case 1: for(j=1;j<=M.mu;j++)
{
p=M.rhead[j];
while(p)
{
cout<<p->i<<"行"<<p->j<<"列值爲"<<p->e<<endl;
p=p->right;
}
}
break;
case 2: for(j=1;j<=M.nu;j++)
{
p=M.chead[j];
while(p)
{
cout<<p->i<<"行"<<p->j<<"列值爲"<<p->e<<endl;
p=p->down;
}
}
}
}
void PrintSMatrix1(CrossList M)
{ // 按矩陣形式輸出M
int i,j;
OLink p;
for(i=1;i<=M.mu;i++)
{ // 從第1行到最後1行
p=M.rhead[i]; // p指向該行的第1個非零元素
for(j=1;j<=M.nu;j++) // 從第1列到最後1列
if(!p||p->j!=j) // 已到該行表尾或當前結點的列值不等於當前列值
printf("%-3d",0); // 輸出0
else
{
printf("%-3d",p->e);
p=p->right;
}
printf("\n");
}
}
void CopySMatrix(CrossList M,CrossList &T)
{ // 初始條件:稀疏矩陣M存在。操作結果:由稀疏矩陣M複製得到T
int i;
OLink p,q;
if(T.rhead) // 矩陣T存在
DestroySMatrix(T);
T.mu=M.mu;
T.nu=M.nu;
InitSMatrixList(T); // 初始化T的表頭指針向量
for(i=1;i<=M.mu;i++) // 按行復制
{
p=M.rhead[i]; // p指向i行鏈表頭
while(p) // 沒到行尾
{
if(!(q=(OLNode*)malloc(sizeof(OLNode)))) // 生成結點q
exit(OVERFLOW);
*q=*p; // 給結點q賦值
InsertAscend(T,q); // 將結點q按行列值升序插到矩陣T中
p=p->right;
}
}
}
int comp(int c1,int c2)
{ // AddSMatrix函數要用到,另加
if(c1<c2)
return -1;
if(c1==c2)
return 0;
return 1;
}
void AddSMatrix(CrossList M,CrossList N,CrossList &Q)
{ // 初始條件:稀疏矩陣M與N的行數和列數對應相等。操作結果:求稀疏矩陣的和Q=M+N
int i;
OLink pq,pm,pn;
if(M.mu!=N.mu||M.nu!=N.nu)
{
printf("兩個矩陣不是同類型的,不能相加\n");
exit(OVERFLOW);
}
Q.mu=M.mu; // 初始化Q矩陣
Q.nu=M.nu;
Q.tu=0; // Q矩陣元素個數的初值爲0
InitSMatrixList(Q); // 初始化Q的表頭指針向量
for(i=1;i<=M.mu;i++) // 按行的順序相加
{
pm=M.rhead[i]; // pm指向矩陣M的第i行的第1個結點
pn=N.rhead[i]; // pn指向矩陣N的第i行的第1個結點
while(pm&&pn) // pm和pn均不空
{
pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
switch(comp(pm->j,pn->j))
{
case -1: *pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pm=pm->right; // 指針向後移
break;
case 0: *pq=*pm; // M、N矩陣的列相等,元素值相加
pq->e+=pn->e;
if(pq->e!=0) // 和爲非零元素
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
else
free(pq); // 釋放結點
pm=pm->right; // 指針向後移
pn=pn->right;
break;
case 1: *pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pn=pn->right; // 指針向後移
}
}
while(pm) // pn=NULL
{
pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
*pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pm=pm->right; // 指針向後移
}
while(pn) // pm=NULL
{
pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
*pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pn=pn->right; // 指針向後移
}
}
if(Q.tu==0) // Q矩陣元素個數爲0
DestroySMatrix(Q); // 銷燬矩陣Q
}
void SubtSMatrix(CrossList M,CrossList N,CrossList &Q)
{ // 初始條件:稀疏矩陣M與N的行數和列數對應相等。操作結果:求稀疏矩陣的差Q=M-N
int i;
OLink pq,pm,pn;
if(M.mu!=N.mu||M.nu!=N.nu)
{
printf("兩個矩陣不是同類型的,不能相減\n");
exit(OVERFLOW);
}
Q.mu=M.mu; // 初始化Q矩陣
Q.nu=M.nu;
Q.tu=0; // Q矩陣元素個數的初值爲0
InitSMatrixList(Q); // 初始化Q的表頭指針向量
for(i=1;i<=M.mu;i++) // 按行的順序相減
{
pm=M.rhead[i]; // pm指向矩陣M的第i行的第1個結點
pn=N.rhead[i]; // pn指向矩陣N的第i行的第1個結點
while(pm&&pn) // pm和pn均不空
{
pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
switch(comp(pm->j,pn->j))
{
case -1: *pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pm=pm->right; // 指針向後移
break;
case 0: *pq=*pm; // M、N矩陣的列相等,元素值相減
pq->e-=pn->e;
if(pq->e!=0) // 差爲非零元素
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
else
free(pq); // 釋放結點
pm=pm->right; // 指針向後移
pn=pn->right;
break;
case 1: *pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
pq->e*=-1; // 求反
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pn=pn->right; // 指針向後移
}
}
while(pm) // pn=NULL
{
pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
*pq=*pm; // M的列<N的列,將矩陣M的當前元素值賦給pq
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pm=pm->right; // 指針向後移
}
while(pn) // pm=NULL
{
pq=(OLink)malloc(sizeof(OLNode)); // 生成矩陣Q的結點
*pq=*pn; // M的列>N的列,將矩陣N的當前元素值賦給pq
pq->e*=-1; // 求反
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
pn=pn->right; // 指針向後移
}
}
if(Q.tu==0) // Q矩陣元素個數爲0
DestroySMatrix(Q); // 銷燬矩陣Q
}
void MultSMatrix(CrossList M,CrossList N,CrossList &Q)
{ // 初始條件:稀疏矩陣M的列數等於N的行數。操作結果:求稀疏矩陣乘積Q=M×N
int i,j,e;
OLink pq,pm,pn;
InitSMatrix(Q);
Q.mu=M.mu;
Q.nu=N.nu;
Q.tu=0;
InitSMatrixList(Q); // 初始化Q的表頭指針向量
for(i=1;i<=Q.mu;i++)
for(j=1;j<=Q.nu;j++)
{
pm=M.rhead[i];
pn=N.chead[j];
e=0;
while(pm&&pn)
switch(comp(pn->i,pm->j))
{
case -1: pn=pn->down; // 列指針後移
break;
case 0: e+=pm->e*pn->e; // 乘積累加
pn=pn->down; // 行列指針均後移
pm=pm->right;
break;
case 1: pm=pm->right; // 行指針後移
}
if(e) // 值不爲0
{
pq=(OLink)malloc(sizeof(OLNode)); // 生成結點
if(!pq) // 生成結點失敗
exit(OVERFLOW);
pq->i=i; // 給結點賦值
pq->j=j;
pq->e=e;
InsertAscend(Q,pq); // 將結點pq按行列值升序插到矩陣Q中
}
}
if(Q.tu==0) // Q矩陣元素個數爲0
DestroySMatrix(Q); // 銷燬矩陣Q
}
void TransposeSMatrix(CrossList M,CrossList &T)
{ // 初始條件:稀疏矩陣M存在。操作結果:求稀疏矩陣M的轉置矩陣T
int u,i;
OLink *head,p,q,r;
CopySMatrix(M,T); // T=M
u=T.mu; // 交換T.mu和T.nu
T.mu=T.nu;
T.nu=u;
head=T.rhead; // 交換T.rhead和T.chead
T.rhead=T.chead;
T.chead=head;
for(u=1;u<=T.mu;u++) // 對T的每一行
{
p=T.rhead[u]; // p爲行表頭
while(p) // 沒到表尾,對T的每一結點
{
q=p->down; // q指向下一個結點
i=p->i; // 交換.i和.j
p->i=p->j;
p->j=i;
r=p->down; // 交換.down和.right
p->down=p->right;
p->right=r;
p=q; // p指向下一個結點
}
}
}
// main5-4.cpp 檢驗bo5-4.cpp的主程序
#include"c1.h"
typedef int ElemType;
#include"c5-4.h"
#include"bo5-4.cpp"
void main()
{
CrossList A,B,C;
InitSMatrix(A); // CrossList類型的變量在初次使用之前必須初始化
InitSMatrix(B);
printf("創建矩陣A: ");
CreateSMatrix(A);
PrintSMatrix(A);
printf("由矩陣A複製矩陣B: ");
CopySMatrix(A,B);
PrintSMatrix(B);
DestroySMatrix(B); // CrossList類型的變量在再次使用之前必須先銷燬
printf("銷燬矩陣B後,矩陣B爲\n");
PrintSMatrix1(B);
printf("創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲%d,%d)\n",A.mu,A.nu);
CreateSMatrix(B);
PrintSMatrix1(B);
printf("矩陣C1(A+B):\n");
AddSMatrix(A,B,C);
PrintSMatrix1(C);
DestroySMatrix(C);
printf("矩陣C2(A-B):\n");
SubtSMatrix(A,B,C);
PrintSMatrix1(C);
DestroySMatrix(C);
printf("矩陣C3(A的轉置):\n");
TransposeSMatrix(A,C);
PrintSMatrix1(C);
DestroySMatrix(A);
DestroySMatrix(B);
DestroySMatrix(C);
printf("創建矩陣A2: ");
CreateSMatrix(A);
PrintSMatrix1(A);
printf("創建矩陣B3:(行數應與矩陣A2的列數相同=%d)\n",A.nu);
CreateSMatrix(B);
PrintSMatrix1(B);
printf("矩陣C5(A×B):\n");
MultSMatrix(A,B,C);
PrintSMatrix1(C);DestroySMatrix(A);
DestroySMatrix(B);
DestroySMatrix(C);
}
代碼運行結果:
創建矩陣A: 請輸入稀疏矩陣的行數列數非零元個數: 3 3 2
請按任意次序輸入2個非零元的行列元素值:
2 1 2
1 2 1
3行3列2個非零元素(見圖515)
請輸入選擇(1.按行輸出2.按列輸出): 1
1行2列值爲1
2行1列值爲2
由矩陣A複製矩陣B: 3行3列2個非零元素
請輸入選擇(1.按行輸出2.按列輸出): 2
2行1列值爲2
1行2列值爲1
銷燬矩陣B後,矩陣B爲
創建矩陣B2:(與矩陣A的行、列數相同,行、列分別爲3,3)
請輸入稀疏矩陣的行數列數非零元個數: 3 3 2
請按任意次序輸入2個非零元的行列元素值:
2 2 5
1 2 -1
0 -1 0
0 5 0
0 0 0
矩陣C1(A+B):
0 0 0
2 5 0
0 0 0
矩陣C2(A-B):
0 2 0
2 -5 0
0 0 0
矩陣C3(A的轉置):
0 2 0
1 0 0
0 0 0
創建矩陣A2: 請輸入稀疏矩陣的行數列數非零元個數: 2 3 2
請按任意次序輸入2個非零元的行列元素值:
1 1 1
2 3 2
1 0 0
0 0 2
創建矩陣B3:(行數應與矩陣A2的列數相同=3)
請輸入稀疏矩陣的行數列數非零元個數: 3 2 2
請按任意次序輸入2個非零元的行列元素值:
2 2 1
3 1 2
0 0
0 1
2 0
矩陣C5(A×B):
0 0
4 0