题目:设计一个程序,实现一个能进行稀疏矩阵基本运算的计算器。按照教科书《数据结构(C语言版)》(严蔚敏等)5.3.2节中描述的方法,以十字链表表示稀疏矩阵。
一、需求分析
- 稀疏矩阵是指那些多数元素为零的矩阵。利用“稀疏”特点进修学校储存和计算可以大大节省储存空间,提高计算效率。实现一个能进行稀疏矩阵基本运算的计算器。
以“带行逻辑链接信息”的三元组顺序表表示稀疏矩阵,实现两个矩阵相加、相减和相乘的运算。稀疏矩阵的输入形式采用三元组表示,而运算结果的矩阵则以通常的阵列形式列出。 - 测试数据
\left[ \begin{matrix} 10&0& 0 \\ 0&0&9 \\ -1&0&0 \\ \end{matrix}\right] + \left[ \begin{matrix} 0&0& 0 \\ 0&0&-1 \\ 1&0&-3 \\ \end{matrix}\right]= \left[ \begin{matrix} 10&0& 0 \\ 0&0&8 \\ 0&0&-3 \\ \end{matrix}\right]
\left[ \begin{matrix} 10&9 \\ 0&9 \\ -1&0 \\ \end{matrix}\right] - \left[ \begin{matrix} 0&0 \\ 0&-1 \\ 1&-3 \\ \end{matrix}\right]= \left[ \begin{matrix} 10&0 \\ 0&10 \\ -2&-3 \\ \end{matrix}\right]
\left[ \begin{matrix} 4&-3&0&0&1 \\ 0&0&0&8&0 \\ 0&0&1&0&0 \\ 0&0&0&0&0 \end{matrix}\right] \times \left[ \begin{matrix} 3&0&0 \\ 4&2&0 \\ 0&1&0 \\ 1&0&0 \\ 0&0&0 \end{matrix}\right] = \left[ \begin{matrix} 0&-6&0 \\ 8&0&0 \\ 0&1&0 \\ 0&0&0 \end{matrix}\right]
二、概要设计
1.数据结构
ADT SparseMatrix{
数据对象:D={ aij | i = 1,2,...,m; j = 1,2,...,n;
aij∈ElemSet, m和n分别为矩阵的行数和列数}
数据关系:R={Row,Col}
Row={<ai,j,ai,j+1 >|1≤i≤m,1≤j≤n-1 }
Col={<ai,j,ai+1,j>|1≤i≤m-1,1≤j≤n }
基本操作:
CreateSMatrix(&M)
操作结果:创建稀疏矩阵M。
PrintSMatrix(M)
初始条件:稀疏矩阵M存在。
操作结果: 输出稀疏矩阵M。
AddSMatrix(M, N, &Q)
初始条件:稀疏矩阵M与N的行数和列数对应相等。
操作结果:求稀疏矩阵的和Q=M+N。
SubtSMatrix(M, N, &Q)
初始条件:稀疏矩阵M与N的行数和列数对应相等。
操作结果:求稀疏矩阵的差Q=M-N。
MultSMatrix(M, N, &Q)
初始条件:稀疏矩阵M的列数等于N的行数。
操作结果:求稀疏矩阵乘积Q=M*N。
}ADT SparseMatrix
2. 使用函数
(1)行逻辑链接的顺序表
int CreateSMatrix(RLSMatrix *M)
操作结果:创建稀疏矩阵
int PrintSMatrix(RLSMatrix M)
操作结果:打印稀疏矩阵
int AddSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q)
操作结果:稀疏矩阵加法,Q=M+N
int SubSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q)
操作结果:稀疏矩阵减法,Q=M-N
int MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q)
操作结果:稀疏矩阵乘法,Q=M*N
(2)十字链表
int CreateSMatrix_OL(CrossList *M)
操作结果:创建稀疏矩阵
int PrintSMatrix_OL(CrossList M)
操作结果:打印稀疏矩阵
int AddSMatrix_OL(CrossList *A, CrossList *B)
操作结果:将稀疏矩阵B加到稀疏矩阵A上
int SubSMatrix_OL(CrossList *A, CrossList *B)
操作结果:在稀疏矩阵A上减去稀疏矩阵B
int MultSMatrix_OL(CrossList A, CrossList B, CrossList *C)
操作结果:稀疏矩阵乘法,C=A*B
三、详细设计
1. 数据储存结构
(1)行逻辑链接顺序表
#define MAXSIZE 400 // 最大非零元个数
#define MAXRC 20 // 最大行数和列数
typedef struct{
int i,j; // 该非零元的行下标和列下标
int e;
}Triple;
typedef struct{
Triple data[MAXSIZE+1]; // 非零元三元组表
int rpos[MAXRC+1]; // 各行第一个非零元位置表
int mu,nu,tu; // 矩阵行数、列数和非零元个数
}RLSMatrix;
(2)十字链表
#define MAXSIZE 400 // 最大非零元个数
#define MAXRC 20 // 最大行数和列数
typedef struct OLNode{
int i,j; // 该非零元的行和列下标
int e;
struct OLNode *right, *down; // 该非零元所在行表和列表的后继链域
}OLNode, *OLink;
typedef struct {
OLink *rhead, *chead; // 行和列链表头指针向量基址由CreateSMatrix分配
int mu, nu, tu; // 稀疏矩阵行数、列数和非零元个数
}CrossList;
2.基本功能实现
2.1行逻辑链接顺序表
(1)稀疏矩阵创建
分别读入矩阵行数、列数以及非零元个数,同时提示输入各个非零元位置和数值,对于输入的非零元判断是否合法,并根据行号和列号进行以行为主序的储存,最后计算各行首个非零元位置。
int CreateSMatrix(RLSMatrix *M){
if(M) free(M);
int m,n,t;
do{
printf("输入矩阵行数,列数和非零元数目,用空格隔开\n");
scanf("%d %d %d", &m, &n, &t);
if(m < 0 || n < 0 || t < 0 || t > m*n){
printf("参数错误 \n");
}
}while(m < 0 || n < 0 || t < 0 || t > m*n);
M->mu = m; M->nu = n; M->tu = t;
printf("请按行优先输入三元组\n");
int i,j,e,k;
int p,q;
for(k = 1; k <= t; k++){
do{
printf("输入第%d个非零元的行号 列号 值, 用空格隔开\n",k);
scanf("%d %d %d", &i, &j, &e);
if(i <= 0 || j <= 0 || i > m || j > n|| e==0){
printf("参数错误\n");
}
}while(i <= 0 || j <= 0 || i > m || j > n|| e==0);
for(p = 1; p <= k-1 && (i > M->data[p].i || (i == M->data[p].i && j > M->data[p].j)); p++); //找到三元组插入的位置
for(q = k-1;q >= p; q--) M->data[q+1] = M->data[q]; //行序大的三元组依次向后移动
M->data[p].i = i;
M->data[p].j = j;
M->data[p].e = e;
}
int row,x;
int num[MAXRC + 1];
for(row = 1; row <= M->mu; ++row) num[row] = 0;
for(x = 1; x <= M->tu; ++x) ++num[M->data[x].i]; // 每一行非零元个数
M->rpos[1] = 1;
for(row = 2; row<=M->mu; ++row) M->rpos[row] = M->rpos[row-1] + num[row-1]; // 各行首个非零元位置
return 1;
}
(2)稀疏矩阵加减法
加减法基本思路一致,这里以加法为例。找到M和N矩阵各行非零元素的起始和终末位置之后开始遍历,对列号相等和不等两种情况分别处理,并处理相加结果等于0的情况。
int AddSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q){
int arow;
int p,q,s = 1;
int tp,tq;
if(M.mu != N.mu || M.nu != N.nu) return 0;
Q->mu = M.mu; Q->nu = M.nu;
for(arow = 1; arow <= M.mu; ++arow){
Q->rpos[arow] = Q->tu + 1;
p = M.rpos[arow]; q = N.rpos[arow];
if(arow < M.mu){
tp = M.rpos[arow + 1];
tq = N.rpos[arow + 1];
}
else{
tp = M.tu + 1;
tq = N.tu + 1;
}
while(p < tp && q < tq){
if(M.data[p].j != N.data[q].j){ // 列号不等
if(M.data[p].j < N.data[q].j){
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e;
s++; p++; Q->tu++;
}else{
Q->data[s].i = arow;
Q->data[s].j = N.data[q].j;
Q->data[s].e = N.data[q].e;
s++; q++; Q->tu++;
}
}else{ // 列号相等
if(M.data[p].e + N.data[q].e != 0){ // 结果非零
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e + N.data[q].e;
s++; q++; p++; Q->tu++;
}else{q++; p++;}
}
}
while(p < tp){
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e;
p++; s++; Q->tu++;
}
while(q < tq){
Q->data[s].i = arow;
Q->data[s].j = N.data[q].j;
Q->data[s].e = N.data[q].e;
q++; s++; Q->tu++;
}
}
return 1;
}
(3)稀疏矩阵乘法
对于M中每个元素M.data[p]找到N中所有满足条件M.data[p].j=N.data[q].i的元素N.data[q],求得M.data[p].e * N.data[q].e,对Q中元素设计累计和变量,初值为零,扫描数组M,求得相应元素乘积累加到适当的求累计和变量上。Q中元素行号与M中元素行号一致,又M中元素以M的行序为主序,因此对Q进行逐行处理,先求得累计和的中间结果(Q的一行),再压缩储存到Q.data中去。
int MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q){
// 求矩阵乘积Q=M×N,采用行逻辑链接储存表示
int arow,brow;
int p,q,t,tp;
int ccol;
int ctemp[MAXRC + 1];
if(M.nu != N.mu) return 0;
Q->mu = M.mu; Q->nu = N.nu; Q->tu = 0; // Q初始化
if(M.tu * N.tu != 0){ // Q是非零矩阵
for(arow = 1; arow <= M.mu; ++arow){ // 处理M的每一行
for(int i = 1; i <= N.nu; i++) ctemp[i] = 0; // 当前行各元素累加器清零
Q->rpos[arow] = Q->tu + 1;
if(arow < M.mu) tp = M.rpos[arow + 1];
else{tp = M.tu + 1;}
for(p = M.rpos[arow]; p<tp; ++p){ // 对当前行每一个非零元
brow = M.data[p].j; // 找到对应元所在N中的行号
if(brow < N.mu) t = N.rpos[brow + 1];
else{t = N.tu + 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;
}// for q
}// 求得Q中第crow(=arow)行的非零元
for(ccol = 1; ccol <= Q->nu; ++ccol){ //压缩储存改行非零元
if(ctemp[ccol]){
if(++Q->tu > MAXSIZE) return 0;
Q->data[Q->tu].i = arow;
Q->data[Q->tu].j = ccol;
Q->data[Q->tu].e = ctemp[ccol];
}// if
} // for ccol
}// for arow
}// if
return 1;
}// MultSMatrix
(4)稀疏矩阵输出
通过双重循环,打印稀疏矩阵中非零元和零元素
int PrintSMatrix(RLSMatrix M){
int row,col,t = 1;
for(row = 1; row <= M.mu; row++){
for(col = 1; col <= M.nu; col++){
if(M.data[t].i == row && M.data[t].j == col){
printf("%d\t",M.data[t].e);
t++;
}else{
printf("0\t");
}
}
printf("\n");
}
return 1;
}
2.2十字链表
(1)稀疏矩阵创建
读入矩阵行数、列数和非零元个数,同时提示输入各个非零元位置和数值,对于输入的非零元判断是否合法,生成结点并完成在行链表和列链表中的插入。
int CreateSMatrix_OL(CrossList *M){
if(M) free(M);
int c;
int m,n,t;
int i,j,k,e;
OLink p,q;
do{
printf("输入矩阵行数,列数和非零元数目,用空格隔开\n");
scanf("%d %d %d", &m, &n, &t);
if(m < 0 || n < 0 || t < 0 || t > m*n){
printf("参数错误 \n");
}
}while(m < 0 || n < 0 || t < 0 || t > m*n);
M->mu = m; M->nu = n; M->tu = t;
if(!(M->rhead = (OLink*)malloc((m+1)*sizeof(OLink)))) exit(-2);
if(!(M->chead = (OLink*)malloc((n+1)*sizeof(OLink)))) exit(-2);
for(c = 1; c <= M->mu; c++) M->rhead[c]=NULL; // 初始化行列头指针向量
for(c = 1; c <= M->nu; c++) M->chead[c]=NULL;
for(k = 1; k <= t; k++){ // 按任意顺序输入非零元
do{
printf("输入第%d个非零元的行号 列号 值, 用空格隔开\n",k);
scanf("%d %d %d", &i, &j, &e);
if(i <= 0 || j <= 0 || i > m || j > n|| e==0){
printf("参数错误\n");
}
}while(i <= 0 || j <= 0 || i > m || j > n|| e==0);
if(!(p = (OLNode*)malloc(sizeof(OLNode)))) exit(-2);
p->i = i; p->j = j; p ->e = e; // 生成结点
if(M->rhead[i] == NULL || 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(M->chead[j] == NULL || 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 1;
}
(2)稀疏矩阵加减法
加减法基本思路一致,这里以加法为例。
非空指针pa和pb分别指向矩阵A,B中行值相同的两个结点,pa==NULL表明矩阵A在改行没有非零元,分为以下四种情况:
- 若pa==NULL或pa->j>pb->i,则需要在A矩阵的链表中插入一个值为bij的结点,此时,需要改变同一行中前一结点的right域值,以及同一列中前一结点的down域值。
- 若pa->j<pb->j,则将pa指针向右推进一步
- 若pa->j==pb->j,且pa->e+pb->e!=0,则只要将aij+bij的值送到pa所指结点的e域即可,其他所有域的值都不变
- 若pa->j==pb->j,且pa->e+pb->e==0,则需要在A矩阵链表中删除pa所指结点,此时需要改变同一行中前一结点的right域值以及同一列前一结点的down阈值。
为了便于插入和删除节点,还需要设置一些辅助指针。其一是在A的行链表上设pre指针,指示pa所指结点的前驱结点;其二是在A的每一列的链表上设一个指针hl[j],其初值和列链表的头指针相同,即hl[j]=chead[j]
int AddSMatrix_OL(CrossList *A, CrossList *B){
OLink pa, pb, pre, p, hl[MAXRC + 1];
int i, j;
if(A->mu != B->mu || A->nu != B->nu) return 0;
for(j = 1; j <= A->nu; j++) hl[j] = A->chead[j];
for(i = 1; i <= A->mu; i++){
pa = A->rhead[i]; pb = B->rhead[i]; pre = NULL;
while(pb){
if(!(p = (OLNode*)malloc(sizeof(OLNode)))) exit(-2);
p->i = pb->i; p->j = pb->j; p->e = pb->e;
if(pa == NULL || pa->j > pb->j){ // 在A中插入pb所指结点的复制结点p
if(pre == NULL) A->rhead[p->i] = p;
else{pre->right = p; }
p->right = pa;
pre = p;
if(A->chead[p->j] == NULL || A->chead[p->j]->i > p->i){
p->down = A->chead[p->j];
A->chead[p->j] = p;
}else{ // 在hl[p->j]中找到新结点的前驱,插入结点
p->down = hl[p->j]->down;
hl[p->j]->down = p;
}
hl[p->j] = p;
pb = pb->right;
A->tu++;
}else if(pa && pa->j < pb->j){ // pa指向本行下一个非零结点
pre = pa;
pa = pa->right;
}else if(pa->j == pb->j){ // 加和
pa->e += pb->e;
if(pa->e == 0){ // 加和为0,删除结点,修改行表和列表相应指针
if(pre == NULL) A->rhead[pa->i] = pa->right;
else{pre->right = pa->right; }
p = pa; pa = pa->right;
if(A->chead[p->j] == p) A->chead[p->j] = hl[p->j] = p->down;
else{hl[p->j]->down = p->down; }
free(p);
pb = pb->right;
A->tu--;
}else{pre = pa; pa = pa->right; pb = pb->right; }
}
}
}
return 1;
}
(3)稀疏矩阵乘法
对于C中i行j列的元素,分别使p指向A中i行链表头指针,q指向B中j列链表头指针,累加和e置为零。p,q不为空时,
- 当p->j > q->i,q指针下移
- 当p->j < q->i,p指针右移
- 当p->j == q->i,对乘积累计求和,并移动指针
累加器e不为0时,则在矩阵C行列链表中插入节点p1,设置cpre和rpre分别指示行列链表中p1的前驱结点。
int MultSMatrix_OL(CrossList A, CrossList B, CrossList *C){
int i, j, e;
OLink p, q, p1, rpre, cpre;
if(A.nu != B.mu) return 0;
C->mu = A.mu; C->nu = B.nu; C->tu = 0; // 初始化矩阵C
if(!(C->rhead = (OLink*)malloc((C->mu+1)*sizeof(OLink)))) exit(-2);
if(!(C->chead = (OLink*)malloc((C->nu+1)*sizeof(OLink)))) exit(-2);
for(i = 1; i <= C->mu; i++) C->rhead[i] = NULL;
for(j = 1; j <= C->nu; j++) C->chead[j] = NULL;
for(i = 1; i <= C->mu; i++){
for(j = 1; j <= C->nu; j++){
p = A.rhead[i]; q = B.chead[j]; e = 0; // p,q分别指向A中该行链表头指针,B中该列链表头指针
while(p && q){
if(p->j > q->i){
q = q->down;
}else if(p->j < q->i){
p = p->right;
}else{
e += p->e * q->e; // 乘积累加
q = q->down;
p = p->right;
}
}
if(e){ // 累加不为0
C->tu++;
if(!(p1 = (OLNode*)malloc(sizeof(OLNode)))) exit(-2);
p1->i = i; p1->j = j; p1->e = e;
p1->right = NULL; p1->down = NULL;
// 行插入
if(C->rhead[i] == NULL) {C->rhead[i] = p1; rpre = p1;}
else{rpre->right = p1; rpre = p1; }
// 列插入
if(C->chead[j] == NULL) {C->chead[j] = p1; cpre = p1;}
else{cpre->down = p1; cpre = p1; }
}
}
}
return 1;
}
(4)稀疏矩阵输出
通过双重循环,打印稀疏矩阵中非零元和零元素
int PrintSMatrix_OL(CrossList M){
OLink p;
int row,col;
for(row = 1; row <= M.mu; row++){
if(M.rhead[row]){
p = M.rhead[row];
for(col = 1; col <= M.nu; col++){
if(p->i == row && p->j == col && p != NULL){
printf("%d\t",p->e);
if(p->right) p = p->right;
}else{printf("0\t");}
}
}else{for(col = 1; col <= M.nu; col++) printf("0\t");}
printf("\n");
}
return 1;
}
4.主程序
通过读入操作序号来进行相应操作,在满足操作对应条件下进行相应操作,并打印结果,两种储存方式下主程序结构基本一致,只是运算时调用函数不同。
int main(){
int num;
CrossList M, N, Q;
do{
printf("操作:1.矩阵相加 2.矩阵相减 3.矩阵相乘 4.退出\n");
scanf("%d",&num);
if(num == 1 || num == 2 || num == 3){
printf("请输入矩阵1\n");
CreateSMatrix_OL(&M);
printf("请输入矩阵2\n");
CreateSMatrix_OL(&N);
printf("两矩阵为:\n");
PrintSMatrix_OL(M);
printf("\n");
PrintSMatrix_OL(N);
switch(num){
case 1:
{
if(AddSMatrix_OL(&M, &N)){
printf("结果:\n");
PrintSMatrix_OL(M);
}
else {printf("参数错误\n");}
break;
}
case 2:
{
if(SubSMatrix_OL(&M, &N)){
printf("结果:\n");
PrintSMatrix_OL(M);
}
else {printf("参数错误\n");}
break;
}
case 3:
{
if(MultSMatrix_OL(M,N,&Q)){
printf("结果:\n");
PrintSMatrix_OL(Q);
}
else {printf("参数错误\n");}
break;
}
default: break;
}
}
}while(num == 1 || num == 2 || num == 3);
return 1;
}
5.程序的层次结构
四、用户手册
- 本程序的运行环境为DOS操作系统,执行文件为:sparsematrix.exe和crossmatrix.exe 分别对应行逻辑链接顺序表和十字链表实现的稀疏矩阵计算器
- 进入程序按提示操作,输入要进行操作对应的序号
- 根据操作提示输入两矩阵的行数、列数和非零元个数,并输入非零元的行号,列号以及值
- 结果打印
- 根据操作提示退出程序
五、测试结果
\left[ \begin{matrix} 10&0& 0 \\ 0&0&9 \\ -1&0&0 \\ \end{matrix}\right] + \left[ \begin{matrix} 0&0& 0 \\ 0&0&-1 \\ 1&0&-3 \\ \end{matrix}\right]= \left[ \begin{matrix} 10&0& 0 \\ 0&0&8 \\ 0&0&-3 \\ \end{matrix}\right]
\left[ \begin{matrix} 10&9 \\ 0&9 \\ -1&0 \\ \end{matrix}\right] - \left[ \begin{matrix} 0&0 \\ 0&-1 \\ 1&-3 \\ \end{matrix}\right]= \left[ \begin{matrix} 10&0 \\ 0&10 \\ -2&-3 \\ \end{matrix}\right]
\left[ \begin{matrix} 4&-3&0&0&1 \\ 0&0&0&8&0 \\ 0&0&1&0&0 \\ 0&0&0&0&0 \end{matrix}\right] \times \left[ \begin{matrix} 3&0&0 \\ 4&2&0 \\ 0&1&0 \\ 1&0&0 \\ 0&0&0 \end{matrix}\right] = \left[ \begin{matrix} 0&-6&0 \\ 8&0&0 \\ 0&1&0 \\ 0&0&0 \end{matrix}\right]
六、源代码
sparsematrix.c
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 400
#define MAXRC 20
typedef struct{
int i,j;
int e;
}Triple;
typedef struct{
Triple data[MAXSIZE+1];
int rpos[MAXRC+1];
int mu,nu,tu; // 行,列,非零元个数
}RLSMatrix;
int CreateSMatrix(RLSMatrix *M){
if(M) free(M);
int m,n,t;
do{
printf("输入矩阵行数,列数和非零元数目,用空格隔开\n");
scanf("%d %d %d", &m, &n, &t);
if(m < 0 || n < 0 || t < 0 || t > m*n){
printf("参数错误 \n");
}
}while(m < 0 || n < 0 || t < 0 || t > m*n);
M->mu = m; M->nu = n; M->tu = t;
printf("请按行优先输入三元组\n");
int i,j,e,k;
int p,q;
for(k = 1; k <= t; k++){
do{
printf("输入第%d个非零元的行号 列号 值, 用空格隔开\n",k);
scanf("%d %d %d", &i, &j, &e);
if(i <= 0 || j <= 0 || i > m || j > n|| e==0){
printf("参数错误\n");
}
}while(i <= 0 || j <= 0 || i > m || j > n|| e==0);
for(p = 1; p <= k-1 && (i > M->data[p].i || (i == M->data[p].i && j > M->data[p].j)); p++); //找到此三元组插入的位置
for(q = k-1;q >= p; q--) M->data[q+1] = M->data[q]; //行序比它大的三元组依次向后移动
M->data[p].i = i;
M->data[p].j = j;
M->data[p].e = e;
}
int row,x;
int num[MAXRC + 1];
for(row = 1; row <= M->mu; ++row) num[row] = 0;
for(x = 1; x <= M->tu; ++x) ++num[M->data[x].i];
M->rpos[1] = 1;
for(row = 2; row<=M->mu; ++row) M->rpos[row] = M->rpos[row-1] + num[row-1];
return 1;
}
int PrintSMatrix(RLSMatrix M){
int row,col,t = 1;
for(row = 1; row <= M.mu; row++){
for(col = 1; col <= M.nu; col++){
if(M.data[t].i == row && M.data[t].j == col){
printf("%d\t",M.data[t].e);
t++;
}else{
printf("0\t");
}
}
printf("\n");
}
return 1;
}
int AddSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q){
int arow;
int p,q,s = 1;
int tp,tq;
if(M.mu != N.mu || M.nu != N.nu) return 0;
Q->mu = M.mu; Q->nu = M.nu;
for(arow = 1; arow <= M.mu; ++arow){
Q->rpos[arow] = Q->tu + 1;
p = M.rpos[arow]; q = N.rpos[arow];
if(arow < M.mu){
tp = M.rpos[arow + 1];
tq = N.rpos[arow + 1];
}
else{
tp = M.tu + 1;
tq = N.tu + 1;
}
while(p < tp && q < tq){
if(M.data[p].j != N.data[q].j){ // 列号不等
if(M.data[p].j < N.data[q].j){
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e;
s++; p++; Q->tu++;
}else{
Q->data[s].i = arow;
Q->data[s].j = N.data[q].j;
Q->data[s].e = N.data[q].e;
s++; q++; Q->tu++;
}
}else{ // 列号相等
if(M.data[p].e + N.data[q].e != 0){ // 结果非零
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e + N.data[q].e;
s++; q++; p++; Q->tu++;
}else{q++; p++;}
}
}
while(p < tp){
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e;
p++; s++; Q->tu++;
}
while(q < tq){
Q->data[s].i = arow;
Q->data[s].j = N.data[q].j;
Q->data[s].e = N.data[q].e;
q++; s++; Q->tu++;
}
}
return 1;
}
int SubSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q){
int arow;
int p,q,s = 1;
int tp,tq;
if(M.mu != N.mu || M.nu != N.nu) return 0;
Q->mu = M.mu; Q->nu = M.nu;
for(arow = 1; arow <= M.mu; ++arow){
Q->rpos[arow] = Q->tu + 1;
p = M.rpos[arow]; q = N.rpos[arow];
if(arow < M.mu){
tp = M.rpos[arow + 1];
tq = N.rpos[arow + 1];
}
else{
tp = M.tu + 1;
tq = N.tu + 1;
}
while(p < tp && q < tq){
if(M.data[p].j != N.data[q].j){ // 列号不等
if(M.data[p].j < N.data[q].j){
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e;
s++; p++; Q->tu++;
}else{
Q->data[s].i = arow;
Q->data[s].j = N.data[q].j;
Q->data[s].e = - N.data[q].e;
s++; q++; Q->tu++;
}
}else{ // 列号相等
if(M.data[p].e - N.data[q].e != 0){
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e - N.data[q].e;
s++; q++; p++; Q->tu++;
}else{q++; p++;}
}
}
while(p < tp){
Q->data[s].i = arow;
Q->data[s].j = M.data[p].j;
Q->data[s].e = M.data[p].e;
p++; s++; Q->tu++;
}
while(q < tq){
Q->data[s].i = arow;
Q->data[s].j = N.data[q].j;
Q->data[s].e = - N.data[q].e;
q++; s++; Q->tu++;
}
}
return 1;
}
int MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix *Q){
// 求矩阵乘积Q=M×N,采用行逻辑链接储存表示
int arow,brow;
int p,q,t,tp;
int ccol;
int ctemp[MAXRC + 1];
if(M.nu != N.mu) return 0;
Q->mu = M.mu; Q->nu = N.nu; Q->tu = 0; // Q初始化
if(M.tu * N.tu != 0){ // Q是非零矩阵
for(arow = 1; arow <= M.mu; ++arow){ // 处理M的每一行
for(int i = 1; i <= N.nu; i++) ctemp[i] = 0; // 当前行各元素累加器清零
Q->rpos[arow] = Q->tu + 1;
if(arow < M.mu) tp = M.rpos[arow + 1];
else{tp = M.tu + 1;}
for(p = M.rpos[arow]; p<tp; ++p){ // 对当前行每一个非零元
brow = M.data[p].j; // 找到对应元所在N中的行号
if(brow < N.mu) t = N.rpos[brow + 1];
else{t = N.tu + 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;
}// for q
}// 求得Q中第crow(=arow)行的非零元
for(ccol = 1; ccol <= Q->nu; ++ccol){ //压缩储存改行非零元
if(ctemp[ccol]){
if(++Q->tu > MAXSIZE) return 0;
Q->data[Q->tu].i = arow;
Q->data[Q->tu].j = ccol;
Q->data[Q->tu].e = ctemp[ccol];
}// if
} // for ccol
}// for arow
}// if
return 1;
}// MultSMatrix
int main(){
int num;
RLSMatrix M, N, Q;
do{
printf("操作:1.矩阵相加 2.矩阵相减 3.矩阵相乘 4.退出\n");
scanf("%d",&num);
if(num == 1 || num == 2 || num == 3){
printf("请输入矩阵1\n");
CreateSMatrix(&M);
printf("请输入矩阵2\n");
CreateSMatrix(&N);
printf("两矩阵为:\n");
PrintSMatrix(M);
printf("\n");
PrintSMatrix(N);
switch(num){
case 1:
{
if(AddSMatrix(M,N,&Q)){
printf("结果:\n");
PrintSMatrix(Q);
}
else {printf("参数错误\n");}
break;
}
case 2:
{
if(SubSMatrix(M,N,&Q)){
printf("结果:\n");
PrintSMatrix(Q);
}
else {printf("参数错误\n");}
break;
}
case 3:
{
if(MultSMatrix(M,N,&Q)){
printf("结果:\n");
PrintSMatrix(Q);
}
else {printf("参数错误\n");}
break;
}
default: break;
}
}
}while(num == 1 || num == 2 || num == 3);
return 1;
}
crosmatrix.c
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 400
#define MAXRC 20
typedef struct OLNode{
int i,j;
int e;
struct OLNode *right, *down;
}OLNode, *OLink;
typedef struct {
OLink *rhead, *chead;
int mu, nu, tu;
}CrossList;
int CreateSMatrix_OL(CrossList *M){
if(M) free(M);
int c;
int m,n,t;
int i,j,k,e;
OLink p,q;
do{
printf("输入矩阵行数,列数和非零元数目,用空格隔开\n");
scanf("%d %d %d", &m, &n, &t);
if(m < 0 || n < 0 || t < 0 || t > m*n){
printf("参数错误 \n");
}
}while(m < 0 || n < 0 || t < 0 || t > m*n);
M->mu = m; M->nu = n; M->tu = t;
if(!(M->rhead = (OLink*)malloc((m+1)*sizeof(OLink)))) exit(-2);
if(!(M->chead = (OLink*)malloc((n+1)*sizeof(OLink)))) exit(-2);
for(c = 1; c <= M->mu; c++) M->rhead[c]=NULL;
for(c = 1; c <= M->nu; c++) M->chead[c]=NULL;
for(k = 1; k <= t; k++){
do{
printf("输入第%d个非零元的行号 列号 值, 用空格隔开\n",k);
scanf("%d %d %d", &i, &j, &e);
if(i <= 0 || j <= 0 || i > m || j > n|| e==0){
printf("参数错误\n");
}
}while(i <= 0 || j <= 0 || i > m || j > n|| e==0);
if(!(p = (OLNode*)malloc(sizeof(OLNode)))) exit(-2);
p->i = i; p->j = j; p ->e = e;
if(M->rhead[i] == NULL || 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(M->chead[j] == NULL || 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 1;
}
int PrintSMatrix_OL(CrossList M){
OLink p;
int row,col;
for(row = 1; row <= M.mu; row++){
if(M.rhead[row]){
p = M.rhead[row];
for(col = 1; col <= M.nu; col++){
if(p->i == row && p->j == col && p != NULL){
printf("%d\t",p->e);
if(p->right) p = p->right;
}else{printf("0\t");}
}
}else{for(col = 1; col <= M.nu; col++) printf("0\t");}
printf("\n");
}
return 1;
}
int AddSMatrix_OL(CrossList *A, CrossList *B){
OLink pa, pb, pre, p, hl[MAXRC + 1];
int i, j;
if(A->mu != B->mu || A->nu != B->nu) return 0;
for(j = 1; j <= A->nu; j++) hl[j] = A->chead[j];
for(i = 1; i <= A->mu; i++){
pa = A->rhead[i]; pb = B->rhead[i]; pre = NULL;
while(pb){
if(!(p = (OLNode*)malloc(sizeof(OLNode)))) exit(-2);
p->i = pb->i; p->j = pb->j; p->e = pb->e;
if(pa == NULL || pa->j > pb->j){
if(pre == NULL) A->rhead[p->i] = p;
else{pre->right = p; }
p->right = pa;
pre = p;
if(A->chead[p->j] == NULL || A->chead[p->j]->i > p->i){
p->down = A->chead[p->j];
A->chead[p->j] = p;
}else{
p->down = hl[p->j]->down;
hl[p->j]->down = p;
}
hl[p->j] = p;
pb = pb->right;
A->tu++;
}else if(pa && pa->j < pb->j){
pre = pa;
pa = pa->right;
}else if(pa->j == pb->j){
pa->e += pb->e;
if(pa->e == 0){
if(pre == NULL) A->rhead[pa->i] = pa->right;
else{pre->right = pa->right; }
p = pa; pa = pa->right;
if(A->chead[p->j] == p) A->chead[p->j] = hl[p->j] = p->down;
else{hl[p->j]->down = p->down; }
free(p);
pb = pb->right;
A->tu--;
}else{pre = pa; pa = pa->right; pb = pb->right; }
}
}
}
return 1;
}
int SubSMatrix_OL(CrossList *A, CrossList *B){
OLink pa, pb, pre, p, hl[MAXRC + 1];
int i, j;
if(A->mu != B->mu || A->nu != B->nu) return 0;
for(j = 1; j <= A->nu; j++) hl[j] = A->chead[j];
for(i = 1; i <= A->mu; i++){
pa = A->rhead[i]; pb = B->rhead[i]; pre = NULL;
while(pb){
if(!(p = (OLNode*)malloc(sizeof(OLNode)))) exit(-2);
p->i = pb->i; p->j = pb->j; p->e = - pb->e;
if(pa == NULL || pa->j > pb->j){
if(pre == NULL) A->rhead[p->i] = p;
else{pre->right = p; }
p->right = pa;
pre = p;
if(A->chead[p->j] == NULL || A->chead[p->j]->i > p->i){
p->down = A->chead[p->j];
A->chead[p->j] = p;
}else{
p->down = hl[p->j]->down;
hl[p->j]->down = p;
}
hl[p->j] = p;
pb = pb->right;
A->tu++;
}else if(pa && pa->j < pb->j){
pre = pa;
pa = pa->right;
}else if(pa->j == pb->j){
pa->e -= pb->e;
if(pa->e == 0){
if(pre == NULL) A->rhead[pa->i] = pa->right;
else{pre->right = pa->right; }
p = pa; pa = pa->right;
if(A->chead[p->j] == p) A->chead[p->j] = hl[p->j] = p->down;
else{hl[p->j]->down = p->down; }
free(p);
pb = pb->right;
A->tu--;
}else{pre = pa; pa = pa->right; pb = pb->right; }
}
}
}
return 1;
}
int MultSMatrix_OL(CrossList A, CrossList B, CrossList *C){
int i, j, e;
OLink p, q, p1, rpre, cpre;
if(A.nu != B.mu) return 0;
C->mu = A.mu; C->nu = B.nu; C->tu = 0;
if(!(C->rhead = (OLink*)malloc((C->mu+1)*sizeof(OLink)))) exit(-2);
if(!(C->chead = (OLink*)malloc((C->nu+1)*sizeof(OLink)))) exit(-2);
for(i = 1; i <= C->mu; i++) C->rhead[i] = NULL;
for(j = 1; j <= C->nu; j++) C->chead[j] = NULL;
for(i = 1; i <= C->mu; i++){
for(j = 1; j <= C->nu; j++){
p = A.rhead[i]; q = B.chead[j]; e = 0;
while(p && q){
if(p->j > q->i){
q = q->down;
}else if(p->j < q->i){
p = p->right;
}else{
e += p->e * q->e;
q = q->down;
p = p->right;
}
}
if(e){
C->tu++;
if(!(p1 = (OLNode*)malloc(sizeof(OLNode)))) exit(-2);
p1->i = i; p1->j = j; p1->e = e;
p1->right = NULL; p1->down = NULL;
// 行插入
if(C->rhead[i] == NULL) {C->rhead[i] = p1; rpre = p1;}
else{rpre->right = p1; rpre = p1; }
// 列插入
if(C->chead[j] == NULL) {C->chead[j] = p1; cpre = p1;}
else{cpre->down = p1; cpre = p1; }
}
}
}
return 1;
}
int main(){
int num;
CrossList M, N, Q;
do{
printf("操作:1.矩阵相加 2.矩阵相减 3.矩阵相乘 4.退出\n");
scanf("%d",&num);
if(num == 1 || num == 2 || num == 3){
printf("请输入矩阵1\n");
CreateSMatrix_OL(&M);
printf("请输入矩阵2\n");
CreateSMatrix_OL(&N);
printf("两矩阵为:\n");
PrintSMatrix_OL(M);
printf("\n");
PrintSMatrix_OL(N);
switch(num){
case 1:
{
if(AddSMatrix_OL(&M, &N)){
printf("结果:\n");
PrintSMatrix_OL(M);
}
else {printf("参数错误\n");}
break;
}
case 2:
{
if(SubSMatrix_OL(&M, &N)){
printf("结果:\n");
PrintSMatrix_OL(M);
}
else {printf("参数错误\n");}
break;
}
case 3:
{
if(MultSMatrix_OL(M,N,&Q)){
printf("结果:\n");
PrintSMatrix_OL(Q);
}
else {printf("参数错误\n");}
break;
}
default: break;
}
}
}while(num == 1 || num == 2 || num == 3);
return 1;
}