稀疏矩阵的运算(完美版)

合集下载

稀疏矩阵求逆

稀疏矩阵求逆

稀疏矩阵求逆一、稀疏矩阵的定义和特点稀疏矩阵是指其中绝大部分元素都为0的矩阵。

与之相对的是密集矩阵,即绝大部分元素都不为0的矩阵。

稀疏矩阵在实际应用中非常常见,例如在图像处理、网络分析等领域中,经常需要处理大规模的稀疏数据。

二、求逆的概念和方法求逆是指对于一个n×n的方阵A,找到一个n×n的方阵B,使得AB=BA=In(其中In表示n×n的单位矩阵)。

如果A可逆,则B称为A的逆。

求逆是线性代数中非常重要的一个概念,在实际应用中也有广泛的应用。

求解一个密集矩阵的逆可以使用高斯-约旦消元法或LU分解等方法,但是这些方法在处理稀疏矩阵时效率较低。

因此,针对稀疏矩阵求逆问题需要采用特殊的算法。

三、基于LU分解的稀疏矩阵求逆算法1. LU分解首先介绍一下LU分解算法。

对于一个非奇异的n×n矩阵A,可以将其分解为一个下三角矩阵L和一个上三角矩阵U的乘积,即A=LU。

其中L和U都是非奇异的矩阵,且L的对角线元素为1。

LU分解算法可以使用高斯消元法来实现。

具体步骤如下:(1)对于A中的第i行,进行行变换,使得第i个元素成为主元(即绝对值最大的元素)。

(2)将第i+1到n行中第i个元素除以主元,得到一个系数ki。

(3)将第i+1到n行中第i列的所有元素减去ki倍的第i行中相应位置的元素。

重复以上步骤直到完成LU分解。

2. 稀疏矩阵求逆算法基于LU分解的稀疏矩阵求逆算法可以分为以下几个步骤:(1)对于稀疏矩阵A,使用稀疏存储方式将其存储在计算机内存中。

(2)使用LU分解算法求出L和U两个稀疏矩阵。

由于L和U都是三角形矩阵,因此它们也是稀疏的。

(3)根据AB=In,可以得到B=U^-1L^-1。

因此,我们需要分别求出U和L的逆矩阵。

(4)对于U^-1和L^-1,可以使用前/后代法(forward/backward substitution)求解。

具体来说,对于一个下三角矩阵L和一个向量b,可以使用前代法求解方程Ly=b;对于一个上三角矩阵U和一个向量y,可以使用后代法求解方程Ux=y。

稀疏矩阵的计算

稀疏矩阵的计算

#include <stdio.h>#include <malloc.h>#include<stdlib.h>typedef int ElemType;// 稀疏矩阵的十字链表存储表示typedef struct OLNode{int i,j; // 该非零元的行和列下标ElemType e; // 非零元素值struct OLNode *right,*down; // 该非零元所在行表和列表的后继链域}OLNode, *OLink;typedef struct// 行和列链表头指针向量基址,由CreatSMatrix_OL()分配{OLink *rhead, *chead;int mu, nu, tu; // 稀疏矩阵的行数、列数和非零元个数}CrossList;// 初始化M(CrossList类型的变量必须初始化,否则创建、复制矩阵将出错) int InitSMatrix(CrossList *M){(*M).rhead=(*M).chead=NULL;(*M).mu=(*M).nu=(*M).tu=0;return 1;}// 销毁稀疏矩阵Mint DestroySMatrix(CrossList *M){int i;OLNode *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);(*M).rhead=(*M).chead=NULL;(*M).mu=(*M).nu=(*M).tu=0;return 1;}// 创建稀疏矩阵M,采用十字链表存储表示。

int CreateSMatrix(CrossList *M){int i,j,k,m,n,t;ElemType e;OLNode *p,*q;if((*M).rhead)DestroySMatrix(M);printf("请输入稀疏矩阵的行数列数非零元个数:(space) ");scanf("%d%d%d",&m,&n,&t);(*M).mu=m;(*M).nu=n;(*M).tu=t;//初始化行链表头(*M).rhead=(OLink*)malloc((m+1)*sizeof(OLink));if(!(*M).rhead)exit(0);//初始化列链表头(*M).chead=(OLink*)malloc((n+1)*sizeof(OLink));if(!(*M).chead)exit(0);for(k=1;k<=m;k++) // 初始化行头指针向量;各行链表为空链表(*M).rhead[k]=NULL;for(k=1;k<=n;k++) // 初始化列头指针向量;各列链表为空链表(*M).chead[k]=NULL;printf("请按任意次序输入%d个非零元的行列元素值:(空格)\n",(*M).tu);for(k=0;k<t;k++){scanf("%d%d%d",&i,&j,&e);p=(OLNode*)malloc(sizeof(OLNode));if(!p)exit(0);p->i=i; // 生成结点p->j=j;p->e=e;if((*M).rhead[i]==NULL||(*M).rhead[i]->j>j){// p插在该行的第一个结点处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插在该列的第一个结点处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;}// 按行或按列输出稀疏矩阵Mint PrintSMatrix(CrossList 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){printf("%d行%d列值为%d\n",p->i,p->j,p->e);p=p->right;}}break;case 2:for(j=1;j<=M.nu;j++){p=M.chead[j];while(p){printf("%d行%d列值为%d\n",p->i,p->j,p->e);p=p->down;}}}return 1;}// 由稀疏矩阵M复制得到Tint CopySMatrix(CrossList M,CrossList *T){int i;OLink p,q,q1,q2;if((*T).rhead)DestroySMatrix(T);(*T).mu=M.mu;(*T).nu=M.nu;(*T).tu=M.tu;(*T).rhead=(OLink*)malloc((M.mu+1)*sizeof(OLink));if(!(*T).rhead)exit(0);(*T).chead=(OLink*)malloc((M.nu+1)*sizeof(OLink));if(!(*T).chead)exit(0);for(i=1;i<=M.mu;i++) // 初始化矩阵T的行头指针向量;各行链表为空链表(*T).rhead[i]=NULL;for(i=1;i<=M.nu;i++) // 初始化矩阵T的列头指针向量;各列链表为空链表(*T).chead[i]=NULL;for(i=1;i<=M.mu;i++) // 按行复制{p=M.rhead[i];while(p) // 没到行尾{q=(OLNode*)malloc(sizeof(OLNode)); // 生成结点if(!q)exit(0);q->i=p->i; // 给结点赋值q->j=p->j;q->e=p->e;if(!(*T).rhead[i]) // 插在行表头(*T).rhead[i]=q1=q;else // 插在行表尾q1=q1->right=q;if(!(*T).chead[q->j]) // 插在列表头{(*T).chead[q->j]=q;q->down=NULL;}else // 插在列表尾{q2=(*T).chead[q->j];while(q2->down)q2=q2->down;q2->down=q;q->down=NULL;}p=p->right;}q->right=NULL;}return 1;}// 求稀疏矩阵的和Q=M+Nint AddSMatrix(CrossList M,CrossList N,CrossList *Q){int i,k;OLink p,pq,pm,pn;OLink *col;if(M.mu!=N.mu||M.nu!=N.nu){printf("两个矩阵不是同类型的,不能相加\n");exit(0);}(*Q).mu=M.mu; // 初始化Q矩阵(*Q).nu=M.nu;(*Q).tu=0; // 元素个数的初值(*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));if(!(*Q).rhead)exit(0);(*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));if(!(*Q).chead)exit(0);for(k=1;k<=(*Q).mu;k++) // 初始化Q的行头指针向量;各行链表为空链表(*Q).rhead[k]=NULL;for(k=1;k<=(*Q).nu;k++) // 初始化Q的列头指针向量;各列链表为空链表(*Q).chead[k]=NULL;// 生成指向列的最后结点的数组col=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));if(!col)exit(0);for(k=1;k<=(*Q).nu;k++) // 赋初值col[k]=NULL;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均不空{if(pm->j<pn->j) // 矩阵M当前结点的列小于矩阵N当前结点的列{p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pm->j;p->e=pm->e;p->right=NULL;pm=pm->right; // pm指针向右移}else if(pm->j>pn->j)// 矩阵M当前结点的列大于矩阵N当前结点的列{p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pn->j;p->e=pn->e;p->right=NULL;pn=pn->right; // pn指针向右移}// 矩阵M、N当前结点的列相等且两元素之和不为0else if(pm->e+pn->e){p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pn->j;p->e=pm->e+pn->e;p->right=NULL;pm=pm->right; // pm指针向右移pn=pn->right; // pn指针向右移}else // 矩阵M、N当前结点的列相等且两元素之和为0{pm=pm->right; // pm指针向右移pn=pn->right; // pn指针向右移continue;}if((*Q).rhead[i]==NULL) // p为该行的第1个结点// p插在该行的表头且pq指向p(该行的最后一个结点)(*Q).rhead[i]=pq=p;else // 插在pq所指结点之后{pq->right=p; // 完成行插入pq=pq->right; // pq指向该行的最后一个结点}if((*Q).chead[p->j]==NULL) // p为该列的第1个结点// p插在该列的表头且col[p->j]指向p(*Q).chead[p->j]=col[p->j]=p;else // 插在col[p->]所指结点之后{col[p->j]->down=p; // 完成列插入// col[p->j]指向该列的最后一个结点col[p->j]=col[p->j]->down;}}while(pm) // 将矩阵M该行的剩余元素插入矩阵Q{p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pm->j;p->e=pm->e;p->right=NULL;pm=pm->right; // pm指针向右移if((*Q).rhead[i] == NULL) // p为该行的第1个结点// p插在该行的表头且pq指向p(该行的最后一个结点)(*Q).rhead[i] = pq = p;else // 插在pq所指结点之后{pq->right=p; // 完成行插入pq=pq->right; // pq指向该行的最后一个结点}if((*Q).chead[p->j] == NULL) // p为该列的第1个结点// p插在该列的表头且col[p->j]指向p(*Q).chead[p->j] = col[p->j] = p;else // 插在col[p->j]所指结点之后{col[p->j]->down=p; // 完成列插入// col[p->j]指向该列的最后一个结点col[p->j]=col[p->j]->down;}}while(pn) // 将矩阵N该行的剩余元素插入矩阵Q{p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pn->j;p->e=pn->e;p->right=NULL;pn=pn->right; // pm指针向右移if((*Q).rhead[i]==NULL) // p为该行的第1个结点// p插在该行的表头且pq指向p(该行的最后一个结点)(*Q).rhead[i]=pq=p;else // 插在pq所指结点之后{pq->right=p; // 完成行插入pq=pq->right; // pq指向该行的最后一个结点}if((*Q).chead[p->j]==NULL) // p为该列的第1个结点// p插在该列的表头且col[p->j]指向p(*Q).chead[p->j]=col[p->j]=p;else // 插在col[p->j]所指结点之后{col[p->j]->down=p; // 完成列插入// col[p->j]指向该列的最后一个结点col[p->j]=col[p->j]->down;}}}for(k=1;k<=(*Q).nu;k++)if(col[k]) // k列有结点col[k]->down=NULL; // 令该列最后一个结点的down指针为空free(col);return 1;}// 求稀疏矩阵的差Q=M-Nint SubtSMatrix(CrossList M,CrossList N,CrossList *Q){int i,k;OLink p,pq,pm,pn;OLink *col;if(M.mu!=N.mu||M.nu!=N.nu){printf("两个矩阵不是同类型的,不能相加\n");exit(0);}(*Q).mu=M.mu; // 初始化Q矩阵(*Q).nu=M.nu;(*Q).tu=0; // 元素个数的初值(*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));if(!(*Q).rhead)exit(0);(*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));if(!(*Q).chead)exit(0);for(k=1;k<=(*Q).mu;k++) // 初始化Q的行头指针向量;各行链表为空链表(*Q).rhead[k]=NULL;for(k=1;k<=(*Q).nu;k++) // 初始化Q的列头指针向量;各列链表为空链表(*Q).chead[k]=NULL;// 生成指向列的最后结点的数组col=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));if(!col)exit(0);for(k=1;k<=(*Q).nu;k++) // 赋初值col[k]=NULL;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均不空{if(pm->j<pn->j) // 矩阵M当前结点的列小于矩阵N当前结点的列{p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pm->j;p->e=pm->e;p->right=NULL;pm=pm->right; // pm指针向右移}// 矩阵M当前结点的列大于矩阵N当前结点的列else if(pm->j>pn->j){p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pn->j;p->e=-pn->e;p->right=NULL;pn=pn->right; // pn指针向右移}else if(pm->e-pn->e){// 矩阵M、N当前结点的列相等且两元素之差不为0p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pn->j;p->e=pm->e-pn->e;p->right=NULL;pm=pm->right; // pm指针向右移pn=pn->right; // pn指针向右移}else // 矩阵M、N当前结点的列相等且两元素之差为0{pm=pm->right; // pm指针向右移pn=pn->right; // pn指针向右移continue;}if((*Q).rhead[i]==NULL) // p为该行的第1个结点// p插在该行的表头且pq指向p(该行的最后一个结点)(*Q).rhead[i]=pq=p;else // 插在pq所指结点之后{pq->right=p; // 完成行插入pq=pq->right; // pq指向该行的最后一个结点}if((*Q).chead[p->j]==NULL) // p为该列的第1个结点// p插在该列的表头且col[p->j]指向p(*Q).chead[p->j]=col[p->j]=p;else // 插在col[p->]所指结点之后{col[p->j]->down=p; // 完成列插入// col[p->j]指向该列的最后一个结点col[p->j]=col[p->j]->down;}}while(pm) // 将矩阵M该行的剩余元素插入矩阵Q{p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pm->j;p->e=pm->e;p->right=NULL;pm=pm->right; // pm指针向右移if((*Q).rhead[i]==NULL) // p为该行的第1个结点// p插在该行的表头且pq指向p(该行的最后一个结点)(*Q).rhead[i]=pq=p;else // 插在pq所指结点之后{pq->right=p; // 完成行插入pq=pq->right; // pq指向该行的最后一个结点}if((*Q).chead[p->j]==NULL) // p为该列的第1个结点// p插在该列的表头且col[p->j]指向p(*Q).chead[p->j]=col[p->j]=p;else // 插在col[p->j]所指结点之后{col[p->j]->down=p; // 完成列插入// col[p->j]指向该列的最后一个结点col[p->j]=col[p->j]->down;}}while(pn) // 将矩阵N该行的剩余元素插入矩阵Q{p=(OLink)malloc(sizeof(OLNode)); // 生成矩阵Q的结点if(!p)exit(0);(*Q).tu++; // 非零元素数加1p->i=i; // 给结点赋值p->j=pn->j;p->e=-pn->e;p->right=NULL;pn=pn->right; // pm指针向右移if((*Q).rhead[i]==NULL) // p为该行的第1个结点// p插在该行的表头且pq指向p(该行的最后一个结点)(*Q).rhead[i]=pq=p;else // 插在pq所指结点之后{pq->right=p; // 完成行插入pq=pq->right; // pq指向该行的最后一个结点}if((*Q).chead[p->j]==NULL) // p为该列的第1个结点// p插在该列的表头且col[p->j]指向p(*Q).chead[p->j]=col[p->j]=p;else // 插在col[p->j]所指结点之后{col[p->j]->down=p; // 完成列插入// col[p->j]指向该列的最后一个结点col[p->j]=col[p->j]->down;}}}for(k=1;k<=(*Q).nu;k++)if(col[k]) // k列有结点col[k]->down=NULL; // 令该列最后一个结点的down指针为空free(col);return 1;}// 求稀疏矩阵乘积Q=M*Nint MultSMatrix(CrossList M,CrossList N,CrossList *Q){int i,j,e;OLink q,p0,q0,q1,q2;InitSMatrix(Q);(*Q).mu=M.mu;(*Q).nu=N.nu;(*Q).tu=0;(*Q).rhead=(OLink*)malloc(((*Q).mu+1)*sizeof(OLink));if(!(*Q).rhead)exit(0);(*Q).chead=(OLink*)malloc(((*Q).nu+1)*sizeof(OLink));if(!(*Q).chead)exit(0);for(i=1;i<=(*Q).mu;i++) // 初始化矩阵Q的行头指针向量;各行链表为空链表(*Q).rhead[i]=NULL;for(i=1;i<=(*Q).nu;i++) // 初始化矩阵Q的列头指针向量;各列链表为空链表(*Q).chead[i]=NULL;for(i=1;i<=(*Q).mu;i++)for(j=1;j<=(*Q).nu;j++){p0=M.rhead[i];q0=N.chead[j];e=0;while(p0&&q0){if(q0->i<p0->j)q0=q0->down; // 列指针后移else if(q0->i>p0->j)p0=p0->right; // 行指针后移else // q0->i==p0->j{e+=p0->e*q0->e; // 乘积累加q0=q0->down; // 行列指针均后移p0=p0->right;}}if(e) // 值不为0{(*Q).tu++; // 非零元素数加1q=(OLink)malloc(sizeof(OLNode)); // 生成结点if(!q) // 生成结点失败exit(0);q->i=i; // 给结点赋值q->j=j;q->e=e;q->right=NULL;q->down=NULL;if(!(*Q).rhead[i]) // 行表空时插在行表头(*Q).rhead[i]=q1=q;else // 否则插在行表尾q1=q1->right=q;if(!(*Q).chead[j]) // 列表空时插在列表头(*Q).chead[j]=q;else // 否则插在列表尾{q2=(*Q).chead[j]; // q2指向j行第1个结点while(q2->down)q2=q2->down; // q2指向j行最后1个结点q2->down=q;}}}return 1;}// 求稀疏矩阵M的转置矩阵Tint TransposeSMatrix(CrossList M,CrossList *T){int u,i;OLink *head,p,q,r;if((*T).rhead)DestroySMatrix(T);CopySMatrix(M,T); // T=Mu=(*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和.jp->i=p->j;p->j=i;r=p->down; // 交换.down.和rightp->down=p->right;p->right=r;p=q; // p指向下一个结点}}return 1;}int 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后:\n");PrintSMatrix(B);printf("创建矩阵B2:(与矩阵A的行、列数相同,行、列分别为%d,%d)\n",A.mu,A.nu);CreateSMatrix(&B);PrintSMatrix(B);printf("矩阵C1(A+B): ");AddSMatrix(A,B,&C);PrintSMatrix(C);DestroySMatrix(&C);printf("矩阵C2(A-B): ");SubtSMatrix(A,B,&C);PrintSMatrix(C);DestroySMatrix(&C);printf("矩阵C3(A的转置): ");TransposeSMatrix(A,&C);PrintSMatrix(C);DestroySMatrix(&A);DestroySMatrix(&B);DestroySMatrix(&C);printf("创建矩阵A2: ");CreateSMatrix(&A);PrintSMatrix(A);printf("创建矩阵B3:(行数应与矩阵A2的列数相同=%d)\n",A.nu);CreateSMatrix(&B);PrintSMatrix(B);printf("矩阵C5(A*B): ");MultSMatrix(A,B,&C);PrintSMatrix(C);DestroySMatrix(&A);DestroySMatrix(&B);DestroySMatrix(&C);system("pause");return 0;}。

数据结构实验报告稀疏矩阵运算

数据结构实验报告稀疏矩阵运算

数据结构实验报告稀疏矩阵运算实验目的:1.学习并理解稀疏矩阵的概念、特点以及存储方式。

2.掌握稀疏矩阵加法、乘法运算的基本思想和算法。

3.实现稀疏矩阵加法、乘法的算法,并进行性能测试和分析。

实验原理:稀疏矩阵是指矩阵中绝大多数元素为0的矩阵。

在实际问题中,有许多矩阵具有稀疏性,例如文本矩阵、图像矩阵等。

由于存储稀疏矩阵时,对于大量的零元素进行存储是一种浪费空间的行为,因此需要采用一种特殊的存储方式。

常见的稀疏矩阵的存储方式有三元组顺序表、十字链表、行逻辑链接表等。

其中,三元组顺序表是最简单直观的一种方式,它是将非零元素按行优先的顺序存储起来,每个元素由三个参数组成:行号、列号和元素值。

此外,还需要记录稀疏矩阵的行数、列数和非零元素个数。

稀疏矩阵加法的原理是将两个稀疏矩阵按照相同的行、列顺序进行遍历,对于相同位置的元素进行相加,得到结果矩阵。

稀疏矩阵乘法的原理是将两个稀疏矩阵按照乘法的定义进行计算,即行乘以列的和。

实验步骤:1.实现稀疏矩阵的三元组顺序表存储方式,并完成稀疏矩阵的初始化、转置、打印等基本操作。

2.实现稀疏矩阵的加法运算,并进行性能测试和分析。

3.实现稀疏矩阵的乘法运算,并进行性能测试和分析。

4.编写实验报告。

实验结果:经过实验测试,稀疏矩阵的加法和乘法算法都能正确运行,并且在处理稀疏矩阵时能够有效节省存储空间。

性能测试结果表明,稀疏矩阵加法、乘法的运行时间与非零元素个数有关,当非零元素个数较少时,运算速度较快;当非零元素个数较多时,运算速度较慢。

实验分析:稀疏矩阵的运算相对于普通矩阵的运算有明显的优势,可以节省存储空间和运算时间。

在实际应用中,稀疏矩阵的存储方式和运算算法都可以进行优化。

例如,可以采用行逻辑链接表的方式存储稀疏矩阵,进一步减少存储空间的占用;可以采用并行计算的策略加快稀疏矩阵的运算速度。

总结:通过本次实验,我深入学习了稀疏矩阵的概念、特点和存储方式,掌握了稀疏矩阵加法、乘法的基本思想和算法,并通过实验实现了稀疏矩阵的加法、乘法运算。

稀疏矩阵加法乘法

稀疏矩阵加法乘法

稀疏矩阵加法乘法稀疏矩阵是指其中大部分元素都是0的矩阵,而只有极小部分元素为非0值。

与密集矩阵相比,稀疏矩阵具有更高的压缩率以及更快的计算速度,因此在大型数据处理和机器学习等领域中得到了广泛应用。

稀疏矩阵加法和乘法是稀疏矩阵计算中最基本的两个操作。

一、稀疏矩阵的表示方法基于稀疏矩阵的特殊性质,我们通常使用三元组(TUPLES)实现稀疏矩阵的存储。

三元组存储方式将一个i * j的稀疏矩阵表示为三个一维数组,分别存储非零元素的值,行坐标和列坐标。

例如,一个矩阵:1 0 00 2 00 0 3通过三元组存储方式可以表示为:value = [1, 2, 3]row = [0, 1, 2]col = [0, 1, 2]值为1的元素位于第0行第0列,值为2的元素位于第1行第1列,值为3的元素位于第2行第2列。

二、稀疏矩阵的加法两个稀疏矩阵相加的操作可以通过对两个矩阵的三元组进行合并,对于重复的元素,则将它们的值相加。

例如,对于两个矩阵A和B:A:1 0 00 2 00 0 3B:1 0 00 2 00 0 3则可以通过以下方式对A和B进行加法操作:value = [1+1, 2+2, 3+3]row = [0, 1, 2]col = [0, 1, 2]即结果矩阵为:2 0 00 4 00 0 6三、稀疏矩阵的乘法稀疏矩阵乘法的实现比较复杂,首先需要明确一点,即两个矩阵相乘的结果不一定是稀疏矩阵。

我们可以使用两种常见的算法实现稀疏矩阵的乘法:COO算法和CSR算法。

1. COO算法COO算法也称坐标格式算法,其基本思路是将两个矩阵的三元组转换成一个三元组,然后依次进行乘法运算,最后将结果累加得到最终结果的三元组。

例如,对于两个矩阵A和B:A:1 23 4B:5 67 8则可以按照以下步骤进行乘法操作:①将矩阵A表示为三元组形式:value_A = [1,2,3,4]row_A = [0,0,1,1]col_A = [0,1,0,1]②将矩阵B表示为三元组形式:value_B = [5,6,7,8]row_B = [0,0,1,1]col_B = [0,1,0,1]③对A和B的三元组进行合并得到三元组C:value_C = [1,2,3,4,5,6,7,8]row_C = [0,0,1,1,0,0,1,1]col_C = [0,1,0,1,1,0,1,0]其中row_C和col_C表示的是C中每个元素对应的行数和列数。

稀疏矩阵的运算

稀疏矩阵的运算

稀疏矩阵的运算稀疏矩阵的运算稀疏矩阵,顾名思义,就是矩阵中空值(0)的比例很大,而实际值(非0)的比例很小的矩阵。

它最大的特点就是,当矩阵的规模增大时,仍然可以保持较低的计算量。

在运算时,因为稀疏矩阵中的0值没有意义,所以对其做运算也没有意义。

所以,在运算中需要把稀疏矩阵转换成一维数组,即只保留其有意义的值。

下面介绍几种常用的稀疏矩阵运算技术。

1.索引表(Indextable)这是一种最简单的稀疏矩阵运算技术,在使用索引表时,需要用一个额外的一维数组来保存有意义的值的位置,而把矩阵本身变成一维数组,进行运算。

例如矩阵A:1 0 0 0 00 0 0 4 00 0 0 0 00 3 0 0 00 0 7 0 0这样的矩阵,可以使用一个一维数组来保存其有意义的值及其位置,例如:[1,(0,0); 4,(1,3); 3,(3,1); 7,(2,2)]这样,我们就可以用简单的一维数组代替复杂的二维矩阵,从而加快稀疏矩阵的运算。

2.矩阵向量乘法(Matrix-Vector Multiplication)这是一种最常用的稀疏矩阵运算技术,把一个大的稀疏矩阵A和一个向量(一维数组)V作乘法,得到一个新的向量C,即:C = A * V对于上面的实例,可以用以下方式求出C:C[0] = 1 * V[0] + 0 * V[1] + 0 * V[2] + 0 * V[3] + 0 * V[4] C[1] = 0 * V[0] + 0 * V[1] + 0 * V[2] + 4 * V[3] + 0 * V[4] C[2] = 0 * V[0] + 0 * V[1] + 0 * V[2] + 0 * V[3] + 7 * V[4] C[3] = 0 * V[0] + 3 * V[1] + 0 * V[2] + 0 * V[3] + 0 * V[4] 3.矩阵乘法(Matrix Multiplication)矩阵乘法也是一种常用的稀疏矩阵运算技术,把两个大的稀疏矩阵A和B相乘,得到一个新的稀疏矩阵C,即:C = A * B以上就是稀疏矩阵运算的一些常用技术,稀疏矩阵也可以用于解决很多复杂的运算问题,例如机器学习和深度学习等。

稀疏矩阵乘法

稀疏矩阵乘法

稀疏矩阵乘法给定两个 A 和 B,返回AB的结果。

您可以假设A的列数等于B的⾏数。

本参考程序来⾃九章算法,由 @Roger 提供。

题⽬解法:时间复杂度分析:假设矩阵A,B均为 n x n 的矩阵,矩阵A的稀疏系数为a,矩阵B的稀疏系数为b,a,b∈[0, 1],矩阵越稀疏,系数越⼩。

⽅法⼀:暴⼒,不考虑稀疏性Time (n^2 * (1 + n)) = O(n^2 + n^3)Space O(1)⽅法⼆:改进,仅考虑A的稀疏性Time O(n^2 * (1 + a * n) = O(n^2 + a * n^3)Space O(1)⽅法三(最优):进⼀步改进,考虑A与B的稀疏性Time O(n^2 * (1 + a * b * n)) = O(n^2 + a * b * n^3)Space O(b * n^2)⽅法四:另外⼀种思路,将矩阵A, B⾮0元素的坐标抽出,对⾮0元素进⾏运算和结果累加Time O(2 * n^2 + a * b * n^4) = O(n^2 + a * b * n^4)Space O(a * n^2 + b * n^2)解读:矩阵乘法的两种形式,假设 A(n, t) * B(t, m) = C(n, m)// 形式⼀:外层两个循环遍历C (常规解法)for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {for (int k = 0; k < t; k++) {C[i][j] += A[i][k] * B[k][j];}}}// 或者写成下⾯这样⼦for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {int sum = 0;for (int k = 0; k < t; k++) {sum += A[i][k] * B[k][j];}C[i][j] = sum;}}// 形式⼆:外层两个循环遍历Afor (int i = 0; i < n; i++) {for (int k = 0; k < t; k++) {for (int j = 0; j < m; j++) {C[i][j] += A[i][k] * B[k][j];}}}两种⽅法的区别代码上的区别(表象):调换了第⼆三层循环的顺序核⼼区别(内在):形式⼀以C为核⼼进⾏遍历,每个C[i][j]只会被计算⼀次,就是最终答案。

稀疏矩阵算法

稀疏矩阵算法

稀疏矩阵算法
稀疏矩阵算法是一种有效处理大规模矩阵数据的方法。

相比于普通矩阵,稀疏矩阵中绝大部分元素都是0,只有极少数非零元素。

因此,传统矩阵计算方法不仅浪费时间和空间,而且在处理稀疏矩阵时效率低下。

稀疏矩阵算法可以更加高效地处理稀疏矩阵,包括稀疏矩阵压缩、稀疏矩阵乘法、稀疏矩阵求逆等等。

其中,稀疏矩阵压缩主要有COO、CSR、CSC等三种压缩方式,可以将稀疏矩阵存储空间缩小至原来的几十倍,大大提高了矩阵数据的处理效率。

稀疏矩阵乘法则是通过优化矩阵乘法的算法,避免了对所有元素进行计算的浪费,从而实现了更加高效的计算。

稀疏矩阵求逆则是在矩阵求逆过程中,结合稀疏矩阵的特性,采用一些特殊的算法,从而有效地减少了计算时间和空间消耗。

稀疏矩阵算法不仅可以应用于数学、物理等领域的科学计算,还广泛应用于机器学习、计算机视觉、自然语言处理等人工智能领域,成为了处理大规模矩阵数据的必备技术之一。

- 1 -。

稀疏矩阵的MapReduce计算方法

稀疏矩阵的MapReduce计算方法

1
Ubuntu介绍:
以桌面应用为主题的Linux操作系统。 支持x86、x64和ppc架构。 为什么我们使用Ubuntu? →界面非常友好 →对硬件的支持非常全面 →最适合做桌面系统的Linux发行版本 →容易上手,适合初学者
1
在Ubuntu下安装JDK:
通过U盘,把JDK压缩文件放入Linux系统中。(直接拖拽无效) 打开终端:鼠标右击屏幕可以找到。 在终端下输入:sudo tar zxvf ./jdk-7u9-linux-i586.tar.gz//解压命令 。 ④sudo mkdir /usr/lib/jvm 创建文件夹:在usr文件夹下的lib中。 ⑤sudo cp -r ~/jdk1.7.0_09/ /usr/lib/jvm/ 用最高权限将jdk1.7.0_09 文件夹复制到第四步创建的jvm文件夹下. ⑥profile使用文本编辑器打开,添加三行代码: export JAVA_HOME=/usr/lib/jvm/jdk1.7.0_09 export CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib export PATH="$JAVA_HOME/bin:$PATH" 保存后关闭
1
MapReduce思想:
在 MapReduce 模型下,完成单词统计的具体步骤为: (1) 用户编写Map 程序对出现的单词Hello 产生中间结果 key/value 偶对,如<Hello,1>。 (2)这些分布产生的中间结果将按key 值的不同进行汇总处理, 产生key(word)相同的value 列表,如<Hello,1,1,1,⋯>,并作为 Reduce 阶段的输入,这个阶段的工作将MapReduce策略,把对全 局(或阶段性)计算结果有影响且有关联的value采用相同key 标志。 由于这种策略的简单抽象,因此用户可以较容易地把握局部和全局 关系,从而确保问题求解并行实现的正确性,并进一步降低并行分 布式编程的难度。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

专业课程设计I报告( 2011 / 2012 学年第二学期)题目稀疏矩阵的转换专业软件工程学生姓名张鹏宇班级学号 09003018指导教师张卫丰指导单位计算机学院软件工程系日期 2012年6月18号指导教师成绩评定表附件:稀疏矩阵的转换一、课题内容和要求1.问题描述设计程序用十字链表实现稀疏矩阵的加、减、乘、转置。

2.需求分析(1)设计函数建立稀疏矩阵,初始化值。

(2)设计函数输出稀疏矩阵的值。

(3)构造函数进行两个稀疏矩阵相加,输出最终的稀疏矩阵。

(4)构造函数进行两个稀疏矩阵相减,输出最终的稀疏矩阵。

(5)构造函数进行两个稀疏矩阵的相乘,输出最终的稀疏矩阵。

(6)构造函数进行稀疏矩阵的转置,并输出结果。

(7)退出系统。

二、设计思路分析(1)设计函数建立稀疏矩阵,初始化值。

(2)设计函数输出稀疏矩阵的值。

(3)构造函数进行两个稀疏矩阵相加,输出最终的稀疏矩阵。

(4)构造函数进行两个稀疏矩阵相减,输出最终的稀疏矩阵。

(5)构造函数进行两个稀疏矩阵的相乘,输出最终的稀疏矩阵。

(6)构造函数进行稀疏矩阵的转置,并输出结果。

(7)退出系统。

三、概要设计为了实现以上功能,可以从3个方面着手设计。

1.主界面设计为了实现对稀疏矩阵的多种算法功能的管理,首先设计一个含有多个菜单项的主控菜单子程序以链接系统的各项子功能,方便用户交互式使用本系统。

本系统主控菜单运行界面如图所示。

2.存储结构设计本系统采用单链表结构存储稀疏矩阵的具体信息。

其中:全部结点的信息用头结点为指针数组的单链表存储。

3.系统功能设计本系统除了要完成稀疏矩阵的初始化功能外还设置了4个子功能菜单。

稀疏矩阵的初始化由函数i typedef int ElemType 实现。

建立稀疏矩阵用void Creat()实现,依据读入的行数和列数以及非零元素的个数,分别设定每个非零元素的信息。

4个子功能的设计描述如下。

(1)稀疏矩阵的加法:此功能由函数void Xiangjia( )实现,当用户选择该功能,系统即提示用户初始化要进行加法的两个矩阵的信息。

然后进行加法,最后输出结果。

(2)稀疏矩阵的乘法:此功能由函数void Xiangcheng( )实现。

当用户选择该功能,系统提示输入要进行相乘的两个矩阵的详细信息。

然后进行相乘,最后得到结果。

(3)稀疏矩阵的转置:此功能由函数void Zhuanzhi( )实现。

当用户选择该功能,系统提示用户初始化一个矩阵,然后进行转置,最终输出结果。

(4)退出:即退出稀疏矩阵的应用系统。

由函数5实现,但用户选择此功能时,系统会提示你是否确实想退出,如果是,则退出,否则继续。

三、模块设计1.模块设计本程序包含1个模块:主程序模块加各功能实现模块。

2.系统子程序及功能设计本系统共设置7个子程序,各子程序的函数名及功能说明如下。

(1)typedef int ElemType // 初始化矩阵( 2 ) void Creat(TSMatrix &M) //建立矩阵(3)void Print_SMatrix(TSMatrix M) // 输出矩阵的信息以下编号(4)-(6)是稀疏矩阵的基本操作。

依次是:相加,相乘,转置等。

(4)void Xiangjia(TSMatrix A,TSMatrix B,TSMatrix &C,int n)//把A 和B两个矩阵相加,结果是C(5)void Xiangcheng(TSMatrix A,TSMatrix B,TSMatrix &Q)//把A和B两个矩阵相乘,结果是Q(6)void Zhuanzhi(TSMatrix *a,TSMatrix *b)// 把A转置(7)void main()// 主函数。

设定界面的颜色,大小和窗口的标题,调用工作区模块函数四、详细设计#include<stdio.h>#include<malloc.h>#include<stdlib.h>#define MAXSIZE 40 //假设非零元素个数的最大值为40#define MAXRC 20 //假设矩阵的最大行数为20typedef int ElemType;typedef struct{int i,j; //非零元的行下标和列下标ElemType e; //非零元的值}Triple;typedef struct{Triple data[MAXSIZE+1];int rpos[MAXRC+1]; //各行第一个非零元在三元组的位置表int hs,ls,fls;}TSMatrix,*Matrix;void Creat(TSMatrix &M){int i,k;for(i=1;i<=MAXRC+1;i++)M.rpos[i]=0;printf("请输入矩阵的行数、列数和非零元个数(以空格隔开):");scanf("%d %d %d",&M.hs,&M.ls,&M.fls);for(i=1;i<=M.fls;i++){printf("请用三元组形式输入矩阵的元素(行列非零元素):");scanf("%d %d %d",&M.data[i].i,&M.data[i].j,&M.data[i].e);}for(i=1,k=1;i<=M.hs;i++){M.rpos[i]=k;while(M.data[k].i<=i && k<=M.fls)k++;}}void Xiangjia(TSMatrix A,TSMatrix B,TSMatrix &C,int n){int a,b,temp,l;C.hs=A.hs;C.ls=A.ls;a=b=l=1;while(a<=A.fls && b<=B.fls){if(A.data[a].i==B.data[b].i){if(A.data[a].j<B.data[b].j)C.data[l++]=A.data[a++];else if(A.data[a].j>B.data[b].j){C.data[l]=B.data[b]; C.data[l++].e=n*B.data[b++].e;}else{temp=A.data[a].e+n*B.data[b].e;if(temp){C.data[l]=A.data[a];C.data[l].e=temp;l++;}a++;b++;}}else if(A.data[a].i<B.data[b].i)C.data[l++]=A.data[a++];else {C.data[l]=B.data[b];C.data[l++].e=n*B.data[b++].e;}}while(a<=A.fls)C.data[l++]=A.data[a++];while(b<=B.fls){C.data[l]=B.data[b]; C.data[l++].e=n*B.data[b++].e;}C.fls=l-1;}int Xiangcheng(TSMatrix A,TSMatrix B,TSMatrix &Q){int arow,brow,ccol,tp,p,q,t;int ctemp[MAXRC+1];if(A.ls!=B.hs) return 0;Q.hs=A.hs;Q.ls=B.ls;Q.fls=0;if(A.fls*B.fls){for(arow=1;arow<=A.hs;arow++){for(ccol=1;ccol<=Q.ls;ccol++)ctemp[ccol]=0;Q.rpos[arow]=Q.fls+1;if(arow<A.hs) tp=A.rpos[arow+1];else tp=A.fls+1;for(p=A.rpos[arow];p<tp;p++){brow=A.data[p].j;if(brow<B.hs) t=B.rpos[brow+1];else t=B.fls+1;for(q=B.rpos[brow];q<t;q++){ccol=B.data[q].j;ctemp[ccol]+=A.data[p].e*B.data[q].e;}}for(ccol=1;ccol<=Q.ls;ccol++){if(ctemp[ccol]){if(++Q.fls>MAXSIZE) return 0;Q.data[Q.fls].i=arow;Q.data[Q.fls].j=ccol;Q.data[Q.fls].e=ctemp[ccol];}}}}return 1;}void Print_SMatrix(TSMatrix M){int k,l,n;Matrix p;p=&M;for(k=1,n=1;k<=p->hs;k++){for(l=1;l<=p->ls;l++){if(p->data[n].i==k && p->data[n].j==l){printf("%5d",p->data[n].e);n++;}elseprintf("%5d",0);}printf("\n");}printf("\n");}void Zhuanzhi(TSMatrix *a,TSMatrix *b){int q,col,p;b->hs=a->ls;b->ls=a->hs;b->fls=a->fls;if(b->fls){q=1;for(col=1;col<=a->ls;col++)for(p=1;p<=a->fls;p++)if(a->data[p].j==col){b->data[q].i=a->data[p].j;b->data[q].j=a->data[p].i;b->data[q].e=a->data[p].e;++q;}}}void Destory_SMatrix(TSMatrix &M){M.hs=M.ls=M.fls=0;}void main(){TSMatrix A,B,C;TSMatrix *p=&A,*q=&B;int flag,n;while(1){system("cls");printf("\n\n\n");printf("\t┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n");printf("\t┃ *** 稀疏矩阵的加、减、转、乘 *** ┃\n");printf("\t┣━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n");printf("\t┃1、稀疏矩阵的加法┃\n");printf("\t┃ 2、稀疏矩阵的减法┃\n");printf("\t┃3、稀疏矩阵的转置┃\n");printf("\t┃4、稀疏矩阵的乘法┃\n");printf("\t┃5、退出该应用程序┃\n");printf("\t┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n");printf("输入要进行的项目的编号:");scanf("%d",&flag);if(flag==5) break;Creat(A);printf("矩阵A:\n"); Print_SMatrix(A);switch(flag){case 1: C reat(B);n=1;printf("矩阵B:\n");Print_SMatrix(B);if(A.hs==B.hs && A.ls==B.ls){printf("A+B:\n");Xiangjia(A,B,C,n);Print_SMatrix(C);}else printf("错误!行列不一致\n");break;case 2: Creat(B);n=-1;printf("矩阵B:\n");Print_SMatrix(B);if(A.hs==B.hs && A.ls==B.ls){printf("A-B:\n");Xiangjia(A,B,C,n);Print_SMatrix(C);}else printf("错误!行列不一致\n");break;case 3: printf("A->B:\n");Zhuanzhi(p,q);Print_SMatrix(B);break;case 4: C reat(B);printf("矩阵B:\n");Print_SMatrix(B);printf("A*B:\n");n=Xiangcheng(A,B,C);if(!n) printf("错误!行列不匹配\n");else Print_SMatrix(C);break;default: printf("输入错误!\n");}Destory_SMatrix(A);Destory_SMatrix(B);Destory_SMatrix(C);getchar();getchar();}printf("\n\t\t\t ***程序已经退出***\n");getchar();}五、测试数据及其结果分析六、调试过程中的问题在进行int Xiangcheng(TSMatrix A,TSMatrix B,TSMatrix &Q) 函数调用的时候进行运算的时候出现了一点小差错。

相关文档
最新文档