稀疏矩阵及其压缩存储方法
python稀疏矩阵存储
python稀疏矩阵存储Python稀疏矩阵存储在计算机科学中,稀疏矩阵是指元素大部分为0的矩阵。
因为大部分元素为0,稀疏矩阵具有很好的压缩性,有效地节约了存储空间。
由于在实现机器学习、深度学习算法时经常会使用稀疏矩阵,所以学会使用 Python 存储稀疏矩阵是很重要的。
本文将介绍Python稀疏矩阵存储相关的知识和技巧。
1. 稀疏矩阵的存储方式在稀疏矩阵的存储中,主要包括两种方法:稠密矩阵和压缩矩阵。
- 稠密矩阵存储:如果一个矩阵的元素大多数都是非零的,那么该矩阵就为稠密矩阵。
在稠密矩阵存储时,矩阵中的所有元素都需要被存储。
在 Python 中,我们可以使用Numpy array来存储稠密矩阵。
- 压缩矩阵存储:在许多稀疏矩阵中,大部分元素等于0,所以我们可以只存储非零元素的位置和值,也就是所谓的压缩矩阵存储。
常用的压缩矩阵存储方法包括: - Coordinate storage format (COO) - Compressed Sparse Row (CSR) format - Compressed Sparse Column (CSC) format下面我们将逐一介绍这几种压缩矩阵存储格式。
2. Coordinate storage format (COO)在 COO 格式中,每个非零元素存储它的行、列坐标和值。
例如,对于一个3x3的矩阵$$ \begin{bmatrix} 1 & 0 & 0 \\ 0 & 0 & 2 \\ 3 & 0 & 0 \end{bmatrix} $$可以按照如下的方式进行 COO 存储:``` [(0, 0, 1), (1, 2, 2), (2, 0, 3)] ```COO 格式的缺点是在矩阵的查询和更新时,需要进行类似列表的遍历操作。
但是在构建矩阵时,COO 格式是非常高效的。
下面是在Python中如何使用 COO 格式实现稀疏矩阵的存储和读取:```python import numpy as np from scipy.sparse import coo_matrixa = np.array([[1,0,0], [0,0,2], [3,0,0]]) row, col, value = coo_matrix(a).nonzero() coo =np.column_stack((row, col, value))print(coo) # [(0, 0, 1), (1, 2, 2), (2, 0, 3)] ```其中`coo_matrix`函数返回一个COO格式的稀疏矩阵,`nonzero`函数返回非零元素的行、列坐标,然后通过`np.column_stack`函数将它们合并在一起。
数据结构之稀疏矩阵稀疏矩阵的存储方式和操作分析
数据结构之稀疏矩阵稀疏矩阵的存储方式和操作分析稀疏矩阵是指矩阵中大部分元素为零的特殊矩阵。
在实际应用中,稀疏矩阵经常出现,如图像处理、网络分析和科学计算等领域。
对于稀疏矩阵的存储和操作是数据结构中的重要内容。
本文将介绍稀疏矩阵的存储方式和相关操作的分析。
一、稀疏矩阵存储方式稀疏矩阵的存储方式有多种,其中三元组顺序表和二维数组是比较常用的方法。
1. 三元组顺序表三元组顺序表是一种基于行优先存储的方式,可以将稀疏矩阵以非零元素的形式存储起来。
主要包括行号、列号和元素值三个信息。
以一个4x5的稀疏矩阵为例,其中有三个非零元素分别为A[1][2]=3, A[2][3]=4, A[3][4]=5。
可以使用三元组顺序表来存储:```行号列号元素值1 2 32 3 43 4 5```三元组顺序表的优点是可以节省存储空间,同时也方便进行矩阵的操作。
但是在进行元素的查找和修改时,效率较低。
2. 二维数组二维数组是一种常见的矩阵表示方法,可以直接使用二维数组来表示稀疏矩阵。
其中非零元素的位置用实际的值表示,其余位置用零值表示。
以同样的4x5的稀疏矩阵为例,使用二维数组存储如下:```0 0 0 0 00 0 3 0 00 0 0 4 00 0 0 0 5```二维数组的优点是简单直观,并且可以快速进行元素的查找和修改。
但当稀疏矩阵的规模较大时,会造成较高的存储资源浪费。
二、稀疏矩阵的操作分析对于稀疏矩阵的操作,主要包括矩阵的转置、相加、相乘等。
1. 转置操作稀疏矩阵的转置是指将原始矩阵的行与列对调。
对于三元组顺序表来说,转置操作主要涉及到行号和列号的交换。
而对于二维数组来说,可以直接在取值的时候将行号和列号对调即可。
2. 相加操作稀疏矩阵的相加操作是指将两个矩阵对应位置的元素相加。
对于三元组顺序表来说,可以通过遍历两个矩阵的非零元素,并将其对应位置的元素相加。
而对于二维数组来说,可以直接将对应位置的元素相加即可。
3. 相乘操作稀疏矩阵的相乘操作是指将两个矩阵相乘得到一个新的矩阵。
稀疏矩阵的压缩存储
稀疏矩阵的压缩存储稀疏矩阵的压缩存储:实现稀疏矩阵压缩存储,并实现矩阵转置和求和。
输⼊矩阵时,⾸先需要输⼊⾮零元素的个数,然后分别输⼊矩阵的⾏号,列号和值。
输完2个矩阵后,⾃动进⾏计算第⼀个矩阵的转置以及两个矩阵的和。
例如:输⼊如下:100 90 5 //矩阵的⾏数为100,列数为90,共5个⾮零元素。
1 10 100 //a(1,10)=10050 60 200//a(50,60)=20050 80 100//a(50,80)=10060 60 200//a(60,60)=20099 89 10//a(99,89)=10100 90 2 //矩阵b的⾏数为100,列数为90,共2个⾮零元素。
1 1 10 //b(1,1)=1050 60 -200//b(50,60)=-200#include <iostream>using namespace std;struct Triple { //三元组int Row, Col; //⾮零元素⾏号/列号int value; //⾮零元素的值void operator = (Triple & R) //赋值{Row = R.Row; Col = R.Col; value = R.value;}};class SparseMatrix {private: //a = a*bint Rows, Cols, Terms; //⾏/列/⾮零元素数Triple *smArray; //三元组表public:SparseMatrix(int maxSize=100); //构造函数void Transpose(SparseMatrix& B); //转置SparseMatrix Add(SparseMatrix& b); //a = a+bfriend ostream& operator << (ostream& out, SparseMatrix &M);friend istream& operator >> (istream& in, SparseMatrix &M);};SparseMatrix::SparseMatrix(int maxSize){Terms = maxSize;smArray = new Triple[maxSize];Rows = Cols = 0;};void SparseMatrix::Transpose(SparseMatrix & B){int *rowSize = new int[Cols]; //列元素数数组int *rowStart = new int[Cols]; //转置位置数组B.Rows = Cols; B.Cols = Rows;B.Terms = Terms;if (Terms > 0) {int i, j;for (i = 0; i < Cols; i++) rowSize[i] = 0;for (i = 0; i < Terms; i++)rowSize[smArray[i].Col]++;rowStart[0] = 0;for (i = 1; i < Cols; i++)rowStart[i] = rowStart[i - 1] + rowSize[i - 1];for (i = 0; i < Terms; i++) {j = rowStart[smArray[i].Col];B.smArray[j].Row = smArray[i].Col;B.smArray[j].Col = smArray[i].Row;B.smArray[j].value = smArray[i].value;rowStart[smArray[i].Col]++;}}delete[] rowSize; delete[] rowStart;}SparseMatrix SparseMatrix::Add(SparseMatrix & b){SparseMatrix res;int i = 0, j = 0, index_a, index_b;res.Terms = 0;while (i < Terms&&j < b.Terms) {index_a = Cols * smArray[i].Row + smArray[i].Col;index_b = Cols * b.smArray[j].Row + b.smArray[j].Col;if (index_a < index_b) {res.smArray[res.Terms] = smArray[i];i++;}else if (index_a > index_b) {res.smArray[res.Terms] = b.smArray[j];j++;}else{int vv= smArray[i].value + b.smArray[j].value;if (vv != 0) {res.smArray[res.Terms] = smArray[i];res.smArray[res.Terms].value = vv;}if (vv == 0) {res.Terms--;}i++; j++;}res.Terms++;}for (; i < Terms; i++) {res.smArray[res.Terms] = smArray[i];res.Terms++;}for (; j < b.Terms; j++) {res.smArray[res.Terms] = b.smArray[j];res.Terms++;}return res;}ostream & operator<<(ostream & out, SparseMatrix & M){for (int i = 0; i < M.Terms; i++) {out << M.smArray[i].Row << " " << M.smArray[i].Col << " " << M.smArray[i].value << endl; }return out;// TODO: 在此处插⼊ return 语句}istream & operator>>(istream & in, SparseMatrix & M){in >> M.Rows >> M.Cols >> M.Terms;for (int i = 0; i < M.Terms; i++) {in >> M.smArray[i].Row >> M.smArray[i].Col >> M.smArray[i].value;}return in;// TODO: 在此处插⼊ return 语句}int main(){SparseMatrix s,s2,s3,s4;cin >> s;cin >> s3;s.Transpose(s2);cout << "The transformed matrix is:" << endl;cout << s2;s4=s.Add(s3);cout << "The added matrix is:" << endl;cout << s4;return 0;}。
稀疏矩阵的压缩存储方法及主要运算的实现
1.实验目的:掌握稀疏矩阵的压缩存储方法及主要运算的实现。
2.实验内容与要求:设计一个稀疏矩阵计算器,要求能够:⑴输入并建立稀疏矩阵;⑵输出稀疏矩阵;⑶执行两个矩阵相加;⑷执行两个矩阵相乘;⑸求一个矩阵的转置矩阵。
3.数据结构设计逻辑结构:线性结构存储结构:顺序存储结构4.算法设计#include<stdio.h>#define MAXSIZE 100typedef int datatype;typedef struct{ int i,j;datatype v;}Triple;typedef struct{ Triple data[MAXSIZE+1];int rpos[MAXSIZE+1];int mu,nu,tu;}RLSMatrix;int main(){ void AddSMatrix(RLSMatrix M);void MultSMatrix(RLSMatrix M);void FastTransposeSMatrix(RLSMatrix M);RLSMatrix M;int k;printf("请输入稀疏矩阵M的行数、列数和非零元素个数:");scanf("%d%d%d",&M.mu,&M.nu,&M.tu);printf("请输入稀疏矩阵M中非零元素的行号、列号和元素的值:\n");for(k=1;k<=M.tu;k++)scanf("%d%d%d",&M.data[k].i,&M.data[k].j,&M.data[k].v);printf("请输出稀疏矩阵M中非零元素的行号、列号和元素的值:\n");for(k=1;k<=M.tu;k++){ printf("%d%3d%3d",M.data[k].i,M.data[k].j,M.data[k].v);printf("\n");}AddSMatrix(M);MultSMatrix(M);FastTransposeSMatrix(M);return 0;}void AddSMatrix(RLSMatrix M){ RLSMatrix N,R;int k,l=1,s=1;printf("请输入稀疏矩阵N的行数、列数和非零元素个数:");scanf("%d%d%d",&N.mu,&N.nu,&N.tu);printf("请输入稀疏矩阵N中非零元素的行号、列号和元素的值:\n"); for(k=1;k<=N.tu;k++)scanf("%d%d%d",&N.data[k].i,&N.data[k].j,&N.data[k].v);if(M.mu!=N.mu||M.nu!=N.nu) printf("错误\n");else{ R.mu=M.mu;R.nu=M.nu;k=1;if(M.tu*N.tu!=0){ while(k<=M.tu&&l<=N.tu){ if(M.data[k].i==N.data[l].i){ if(M.data[k].j<N.data[k].j){ R.data[s].i=M.data[k].i;R.data[s].j=M.data[k].j;R.data[s].v=M.data[k].v;k++;s++;}else if(M.data[k].j==N.data[l].j){ R.data[s].i=M.data[k].i;R.data[s].j=M.data[k].j;R.data[s].v=M.data[k].v+N.data[l].v;if(R.data[s].v!=0) s++;k++;l++;}else{ R.data[s].i=N.data[l].i;R.data[s].j=N.data[l].j;R.data[s].v=N.data[l].v;l++;s++;}}else if(M.data[k].i<N.data[l].i){ R.data[s].i=M.data[k].i;R.data[s].j=M.data[k].j;R.data[s].v=M.data[k].v;k++;s++;}else{ R.data[s].i=N.data[l].i;R.data[s].j=N.data[l].j;R.data[s].v=N.data[l].v;l++;s++;}}while(k<=M.tu){ R.data[s].i=M.data[k].i;R.data[s].j=M.data[k].j;R.data[s].v=M.data[k].v;k++;s++;}while(l<=N.tu){ R.data[s].i=N.data[l].i;R.data[s].j=N.data[l].j;R.data[s].v=N.data[l].v;l++;s++;}}printf("请输出稀疏矩阵M和稀疏矩阵N的和矩阵R中非零元素的行号、列号和元素的值:\n");for(k=1;k<s;k++)printf("%d%3d%3d\n",R.data[k].i,R.data[k].j,R.data[k].v);}}void MultSMatrix(RLSMatrix M){ RLSMatrix D,Q;int num1[MAXSIZE],num2[MAXSIZE],ctemp[MAXSIZE],arow,brow,ccol,p,q,tp,t; printf("请输入稀疏矩阵D的行数、列数和非零元素个数:");scanf("%d%d%d",&D.mu,&D.nu,&D.tu);printf("请输入稀疏矩阵D中非零元素的行号、列号和元素的值:\n");for(t=1;t<=D.tu;t++)scanf("%d%d%d",&D.data[t].i,&D.data[t].j,&D.data[t].v);for(ccol=1;ccol<=M.mu;ccol++)num1[ccol]=0;for(t=1;t<=M.tu;t++)num1[M.data[t].i]++;M.rpos[1]=1;for(ccol=2;ccol<=M.mu;ccol++)M.rpos[ccol]=M.rpos[ccol-1]+num1[ccol-1];for(ccol=1;ccol<=D.mu;ccol++)num2[ccol]=0;for(t=1;t<=D.tu;t++)num2[D.data[t].i]++;D.rpos[1]=1;for(ccol=2;ccol<=D.mu;ccol++)D.rpos[ccol]=D.rpos[ccol-1]+num2[ccol-1];if(M.nu!=D.mu) printf("错误\n");else{ Q.mu=M.mu;Q.nu=D.nu;Q.tu=0;if(M.tu*D.tu!=0){ for(arow=1;arow<=M.mu;arow++){ for(ccol=1;ccol<=Q.nu;ccol++)ctemp[ccol]=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;if(brow<D.mu) t=D.rpos[brow+1];else t=D.tu+1;for(q=D.rpos[brow];q<t;q++){ ccol=D.data[q].j;ctemp[ccol]+=M.data[p].v*D.data[q].v;}}for(ccol=1;ccol<=Q.nu;ccol++)if(ctemp[ccol]!=0){ if(++Q.tu>MAXSIZE) printf("错误\n");else{ Q.data[Q.tu].i=arow;Q.data[Q.tu].j=ccol;Q.data[Q.tu].v=ctemp[ccol];}}}}}printf("请输出稀疏矩阵M和稀疏矩阵D的乘积矩阵Q中非零元素的行号、列号和元素的值:\n");for(ccol=1;ccol<=Q.tu;ccol++)printf("%d%3d%3d\n",Q.data[ccol].i,Q.data[ccol].j,Q.data[ccol].v);}void FastTransposeSMatrix(RLSMatrix M){ RLSMatrix T;int num[MAXSIZE],cpot[MAXSIZE],col,p,q,t;T.mu=M.mu;T.nu=M.nu;T.tu=M.tu;if(T.tu!=0){ for(col=1;col<=M.mu;col++)num[col]=0;for(t=1;t<=M.tu;t++)num[M.data[t].j]++;cpot[1]=1;for(col=2;col<=M.nu;col++)cpot[col]=cpot[col-1]+num[col-1];for(p=1;p<=M.tu;p++){ col=M.data[p].j;q=cpot[col];T.data[q].i=M.data[p].j;T.data[q].j=M.data[p].i;T.data[q].v=M.data[p].v;cpot[col]++;}}printf("请输出将稀疏矩阵M转置后的稀疏矩阵T中非零元素的行号、列号和元素的值:\n");for(col=1;col<=T.tu;col++)printf("%d%3d%3d\n",T.data[col].i,T.data[col].j,T.data[col].v);}。
稀疏矩阵压缩的存储方法
稀疏矩阵压缩的存储方法
稀疏矩阵压缩存储方法是一种针对只有少量非零元素的矩阵进行存储的方法,以减少存储空间。
常见的稀疏矩阵压缩存储方法有三种:
1. COO(Coordinate Representation)坐标表示法:
将非零元素的行、列以及值分别存储起来。
可以用一个三元组的列表来表示,每个三元组包含非零元素的行、列和值。
这种方法的优点是简单直观,适用于非常稀疏的矩阵。
缺点是存储空间相对较大,查找和计算比较复杂。
2. CSR(Compressed Sparse Row)压缩行表示法:
将矩阵的行指针、列索引和非零元素的值分别存储起来。
行指针数组存储每一行的第一个非零元素在值数组中的索引位置,列索引和值数组分别存储每一个非零元素的列索引和值。
这种方法的优点是存储空间较小,查找和计算比较高效。
缺点是构造过程相对复杂,删除或插入元素可能导致数组的重新分配。
3. CSC(Compressed Sparse Column)压缩列表示法:
类似于CSR,只是做了行和列的交换。
列指针数组存储每一列的第一个非零元素在值数组中的索引位置,行索引和值数组分别存储每一个非零元素的行索引和值。
这种方法适用于以列为主要操作的稀疏矩阵运算。
注:以上方法仅是三种常见的压缩存储方法,实际上还有其他一些方法,如DIA (Diagonal)对角线表示法、ELL(Ellpack-Itpack)等,不同的方法适用于不同情况下的稀疏矩阵存储。
稀疏矩阵存储和操作稀疏矩阵的数据结构与算法
稀疏矩阵存储和操作稀疏矩阵的数据结构与算法稀疏矩阵是指具有大量零元素和少量非零元素的矩阵。
在实际场景中,由于矩阵中大部分元素为零,传统的矩阵存储方式会造成大量的存储空间的浪费以及数据操作的低效性。
因此,为了节省存储空间和提高数据操作的效率,稀疏矩阵的存储和操作需要借助于特定的数据结构和算法。
一、稀疏矩阵存储的数据结构1.1. 压缩存储方法压缩存储方法是一种常用的稀疏矩阵存储方法。
常见的压缩存储方法有三种:行压缩法(CSR)、列压缩法(CSC)和十字链表法。
1.1.1. 行压缩法(CSR)行压缩法是通过两个数组来存储稀疏矩阵的非零元素。
第一个数组存储非零元素的值,第二个数组存储非零元素在矩阵中的位置信息。
1.1.2. 列压缩法(CSC)列压缩法与行压缩法相似,只是存储方式不同。
列压缩法是通过两个数组来存储稀疏矩阵的非零元素。
第一个数组存储非零元素的值,第二个数组存储非零元素在矩阵中的位置信息。
1.1.3. 十字链表法十字链表法是一种更加灵活的稀疏矩阵存储方法。
通过使用链表的方式,将非零元素存储在链表中,并且每个非零元素还具有行和列的指针,方便进行数据操作。
1.2. 坐标存储法坐标存储法是一种简单直观的稀疏矩阵存储方法。
每个非零元素包括行列坐标和元素值,通过三元组的方式进行存储。
二、稀疏矩阵的操作算法2.1. 矩阵转置矩阵转置是指将原矩阵的行变为列,列变为行的操作。
对于稀疏矩阵,常用的转置算法为快速转置算法。
该算法通过统计每列非零元素的个数,并根据列的非零元素个数确定每个非零元素转置后的位置。
2.2. 矩阵相加矩阵相加是指将两个矩阵对应位置上的元素相加得到一个新的矩阵。
对于稀疏矩阵的相加,可以遍历两个矩阵的非零元素,对相同位置上的元素进行相加。
2.3. 矩阵相乘矩阵相乘是指将两个矩阵相乘得到一个新的矩阵。
对于稀疏矩阵的相乘,常用的算法为稀疏矩阵乘法算法。
该算法通过遍历两个矩阵的非零元素,按照矩阵乘法的规则计算得到新矩阵的非零元素。
稀疏矩阵的压缩存储方法与应用场景
稀疏矩阵的压缩存储方法与应用场景稀疏矩阵指的是矩阵中绝大部分元素为0的情况下,只保存非零元素及其对应的坐标的一种存储方式。
相比于一般的矩阵存储方式,稀疏矩阵的压缩存储方法可以有效节省存储空间,并提高运算效率。
本文将介绍一些常见的稀疏矩阵的压缩存储方法以及其应用场景。
一、行压缩存储法(CRS)行压缩存储法(CRS,Compressed Row Storage)是一种经典的稀疏矩阵压缩存储方法。
在CRS中,矩阵的非零元素按行优先的顺序存储,并记录每行非零元素的开始位置及其列号。
由于CRS只存储非零元素及其对应的行列坐标,因此可以大大减少存储空间。
CRS适用于行操作较多的场景,比如图像处理、有限元分析等。
在这些场景下,常常需要对稀疏矩阵进行行操作,例如行相加、行相减、行乘以常数等。
CRS可以通过迅速定位非零元素所在的行并对其进行操作,提高计算效率。
二、列压缩存储法(CCS)列压缩存储法(CCS,Compressed Column Storage)是另一种常见的稀疏矩阵压缩存储方法。
在CCS中,矩阵的非零元素按列优先的顺序存储,并记录每列非零元素的开始位置及其行号。
与CRS相比,CCS可以更加高效地进行列操作,如列相加、列相减、列乘以常数等。
CCS常用于图论、网络分析等领域。
例如,在图论中,常常需要对邻接矩阵进行列操作,如计算图的邻接节点、计算图的度数等。
CCS 可以快速对非零元素所在的列进行操作,提高计算效率。
三、对角线压缩存储法(Diagonal Storage)对角线压缩存储法是一种适用于具有特殊结构的稀疏矩阵的压缩存储方法。
在对角线压缩存储法中,只存储矩阵的非零主对角线元素以及非零副对角线元素,其余元素均为0。
通过存储非零对角线元素及其位置,可以进一步减少存储空间。
对角线压缩存储法适用于具有对称或反对称性质的矩阵。
在数值计算、网络传输等领域,经常需要处理对称或反对称矩阵。
对角线压缩存储法可以有效存储这类特殊结构的矩阵,并提高运算效率。
稀疏矩阵压缩的存储方法是
稀疏矩阵压缩的存储方法是稀疏矩阵压缩是一种数据结构,可以有效地占用存储空间,合理地存储稀疏矩阵。
通常来说,稀疏矩阵的元素大部分为0,只有少部分非零,所以采用压缩存储方法可以大大减少存储空间的使用。
稀疏矩阵的压缩存储方法有三种:顺序表压缩、链表压缩和十字链表压缩。
下面将对这三种方法进行详细介绍。
1.顺序表压缩方法:顺序表压缩方法是使用一个一维数组来存储稀疏矩阵。
数组的第一行存储矩阵的行数、列数、非零元素的个数。
数组的后续元素按行优先顺序存储矩阵的每一个非零元素。
例如,对于一个3*3的稀疏矩阵:1 0 00 0 23 0 0它的顺序表压缩形式为:3 3 2 第一行分别为行数、列数和非零元素个数1 1 1 第1个非零元素在第1行第1列,值为12 3 2 第2个非零元素在第2行第3列,值为23 1 3 第3个非零元素在第3行第1列,值为3在这个例子中,非零元素的个数为3,而原先需要占据9个空间的矩阵,现在只需要使用7个元素的数组就可以存储。
2.链表压缩方法:链表压缩方法首先将稀疏矩阵存储在单链表中。
单链表中的每一个节点包含4个数据域:行数,列数,元素值和指针域。
其中,指针域指向下一个非零元素节点。
例如,对于一个5*5的稀疏矩阵:0 0 0 0 03 0 0 0 00 0 1 0 00 0 0 2 00 0 0 0 0它的链表表示形式如下:(1,2,3)->(2,1,3)->(3,3,1)->(4,4,2)其中,每个元素依次表示行数、列数和元素值。
指针域则指向下一个非零元素。
相对于顺序表压缩,链表压缩更适用于稀疏矩阵比较大时,且存在大量的非零元素。
因为链表压缩能够动态分配存储空间,可以严格掌控存储空间的使用效率。
3.十字链表压缩方法:十字链表压缩是一种特殊的链表压缩方式,因为它在存储矩阵的同时,能够比较直观地表示矩阵的结构信息。
下面是一个矩阵以十字链表方式存储的示例:首先,将矩阵按行、列分别建立链表。
稀疏矩阵压缩存储方法
稀疏矩阵压缩存储方法嘿,朋友们!今天咱来唠唠这个稀疏矩阵压缩存储方法。
你说啥是稀疏矩阵呀?就好比你有一大筐苹果,大部分都是空的位置,只有那么几个苹果在那,这就很稀疏嘛!那对于这样的矩阵,咱要是傻乎乎地全存起来,多浪费空间呀,就像你非得把那一大筐空位置也当宝贝一样存着。
这时候压缩存储方法就闪亮登场啦!它就像是个聪明的整理大师,能把那些重要的、有实际意义的元素好好地归置起来,而那些没啥用的空位置就不管啦。
比如说有一种方法叫三元组顺序表。
想象一下,这就像是给每个重要的元素都贴上一个小标签,标签上写着它在哪行哪列,还有它的值是多少。
这样不就把关键信息都抓住了嘛,还不占太多地方。
还有一种叫十字链表法呢!这就好比是给矩阵里的元素织了一张特别的网,把它们都串起来,让它们之间的关系变得清清楚楚。
这样找起元素来可方便啦,就跟你在一堆杂物里能快速找到你想要的东西一样。
咱为啥要用这压缩存储方法呀?你想想,要是数据量超级大,那得占多少存储空间呀!这就好比你有一个超级大的房间,要是不懂得合理利用空间,那不是浪费嘛!用了这方法,就像给房间做了个巧妙的收纳,一下子就整洁多了。
而且呀,在处理数据的时候,这压缩存储方法可太有用啦!能让计算速度变快,就像给你的电脑加了个小火箭,跑得飞快。
你说这多好呀!既节省了空间,又提高了效率。
这就像是你出门旅行,只带了最必要的东西,又轻松又方便。
所以呀,可别小瞧了这稀疏矩阵压缩存储方法,它可是数据处理里的一把好手呢!它能让我们更高效地处理那些看似杂乱无章的数据,让它们变得井井有条。
咱可得好好利用起来,让我们的工作和学习变得更轻松、更高效呀!这难道不是很值得我们去研究和掌握的吗?原创不易,请尊重原创,谢谢!。
稀疏矩阵的压缩计算
稀疏矩阵的压缩计算稀疏矩阵是指矩阵中绝大多数元素都是0的矩阵,即非零元素远小于矩阵元素总数的矩阵。
在实际应用中,稀疏矩阵非常常见,比如图像处理、自然语言处理、推荐系统等领域的数据处理。
但是由于稀疏矩阵的特殊性,其存储和计算都会带来额外的开销。
因此,稀疏矩阵的压缩计算变得至关重要。
为了有效地存储和计算稀疏矩阵,研究者提出了多种压缩算法,其中最常用的有三种:压缩行(CSR)、压缩列(CSC)和亚正规(ELL)压缩算法。
压缩行(CSR)算法将稀疏矩阵的每行非零元素及其列索引存储在两个数组中。
一个数组用于存储每行第一个非零元素在第二个数组中的索引位置,第二个数组按非零元素出现的顺序存储矩阵的非零元素值和对应的列索引。
这种方式的好处是能够高效地进行矩阵向量乘法运算,但是在进行矩阵转置和矩阵矩阵相乘时效率较低。
压缩列(CSC)算法与压缩行算法类似,不同之处在于将矩阵的每列非零元素及其行索引存储在两个数组中。
这种方式适用于矩阵转置和矩阵矩阵相乘等操作,但是在矩阵向量乘法中效率较低。
亚正规(ELL)压缩算法综合了压缩行和压缩列算法的优点,将稀疏矩阵的每行的非零元素及其列索引存储在两个二维数组中。
第一个二维数组用于存储每行非零元素的值,第二个二维数组用于存储每行非零元素的列索引。
由于每行的非零元素个数可能不同,因此需要对二维数组进行补齐。
这种方式能够高效地进行矩阵向量乘法和矩阵转置,但是对于矩阵矩阵相乘效率较低。
除了上述的三种压缩算法,还有其他一些针对特定稀疏矩阵特点的压缩算法,如对角线压缩(DIA)算法,将矩阵的对角线及其对应的值存储在数组中,适用于具有对角线分布特点的矩阵;块压缩(BSC)算法,将矩阵按照行或列分块存储在多个数组中,适用于矩阵具有块状结构的情况。
总结来说,稀疏矩阵压缩计算是应对稀疏矩阵存储和计算的重要方法。
通过选择合适的压缩算法,可以充分利用稀疏矩阵的特点,减少存储开销和计算复杂度,提高计算效率。
稀疏矩阵及其压缩存储方法
稀疏矩阵及其压缩存储方法1.基本概念稀疏矩阵(SparseMatrix):是矩阵中的一种特殊情况,其非零元素的个数远小于零元素的个数。
设m行n列的矩阵含t个非零元素,则称以二维数组表示高阶的稀疏矩阵时,会产生零值元素占的空间很大且进行了很多和零值的运算的问题。
特殊矩阵:值相同的元素或0元素在矩阵中的分布有一定的规律。
如下三角阵、三对角阵、稀疏矩阵。
压缩存储:为多个值相同的元素只分配一个存储空间;对0元素不分配空间。
目的是节省大量存储空间。
n x n的矩阵一般需要n2个存储单元,当为对称矩阵时需要n(1+n)/2个单元。
2.三元组顺序表——压缩存储稀疏矩阵方法之一(顺序存储结构)三元组顺序表又称有序的双下标法,对矩阵中的每个非零元素用三个域分别表示其所在的行号、列号和元素值。
它的特点是,非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算。
当矩阵中的非0元素少于1/3时即可节省存储空间。
(1)稀疏矩阵的三元组顺序表存储表示方法#define MAXSIZE 12500 // 假设非零元个数的最大值为12500typedef struct {int i, j; // 该非零元的行下标和列下标ElemType e; //非零元素的值} Triple; // 三元组类型typedef union { //共用体Triple data[MAXSIZE + 1]; // 非零元三元组表,data[0]未用int mu, nu, tu; // 矩阵的行数、列数和非零元个数} TSMatrix; // 稀疏矩阵类型(2)求转置矩阵的操作◆用常规的二维数组表示时的算法for (col=1; col<=nu; ++col)for (row=1; row<=mu; ++row)T[col][row] = M[row][col];其时间复杂度为: O(mu×nu)◆用三元组顺序表表示时的快速转置算法Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T) {// 采用三元组顺序表存储表示,求稀疏矩阵M的转置矩阵TT.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) ++num[M.data[t].j];// 求M 中每一列所含非零元的个数cpot[1] = 1;for (col=2; col<=M.nu; ++col) cpot[col] = cpot[col-1] + num[col-1];// 求M 中每一列的第一个非零元在b.data 中的序号for (p=1; p<=M.tu; ++p) { // 转置矩阵元素col = M.data[p].j; q = cpot[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; ++cpot[col];} // for} // ifreturn OK;} // FastTransposeSMatrix其时间复杂度为: O(mu +nu)3.行逻辑联接的顺序表——压缩存储稀疏矩阵方法之二(链接存储结构)行逻辑联接的顺序表:稀疏矩阵中为了随机存取任意一行的非0元素,需要知道每一行的第一个非0元素在三元组表中的位置,因此将上述快速转置算法中指示行信息的辅助数组cpot 固定在稀疏矩阵的存储结构中,让每一行对应一个单链表,每个单链表都有一个表头指针,这种“带行链接信息”的三元组表即称为行逻辑联接的顺序表。
稀疏矩阵的压缩存储节省存储空间的数据结构
稀疏矩阵的压缩存储节省存储空间的数据结构在计算机科学和数据处理领域,稀疏矩阵是指大部分元素都是零的矩阵。
由于稀疏矩阵中存在大量的零元素,传统的二维数组表示方法会浪费大量的存储空间。
为了解决这个问题,人们引入了稀疏矩阵的压缩存储技术,旨在减少存储空间的占用,并提高数据的访问效率。
稀疏矩阵的压缩存储是通过对非零元素的位置和数值进行编码,并以一种更简洁的数据结构存储。
常见的稀疏矩阵压缩存储方式有三种:行压缩存储(CSR)、列压缩存储(CSC)和对角线存储(DIA)。
一、行压缩存储(CSR)行压缩存储使用三个一维数组来表示稀疏矩阵。
第一个数组存储非零元素的值,第二个数组存储非零元素所在的列号,第三个数组存储每行的起始位置。
这种存储方式适用于按行顺序遍历矩阵的场景,可以有效地减少存储空间的使用。
二、列压缩存储(CSC)列压缩存储与行压缩存储相似,只是将行和列的角色互换。
通过使用三个一维数组,分别存储非零元素的值、非零元素所在的行号和每列的起始位置,可以提高按列访问矩阵元素的效率。
三、对角线存储(DIA)对角线存储是一种针对特殊类型稀疏矩阵的压缩存储方法。
对于具有规律性的稀疏矩阵,可以只存储其中的有效元素和其对应的位置。
一般来说,对角线存储适用于具有较多对角线元素的稀疏矩阵。
稀疏矩阵的压缩存储方法可以大大减少存储空间的使用,从而提高数据处理的效率和性能。
这对于那些需要处理大规模稀疏矩阵的应用非常重要。
例如,在图形处理、线性代数计算和网络分析等领域,稀疏矩阵经常出现,并且占据了大量的存储和计算资源。
需要注意的是,稀疏矩阵的压缩存储方式虽然减少了存储空间的占用,但在访问非零元素时需要进行一定的计算和索引操作,可能会影响一些对数据访问速度要求较高的应用。
因此,在选择和使用压缩存储结构时,需要综合考虑存储空间和计算效率之间的平衡。
总结而言,稀疏矩阵的压缩存储技术为处理稀疏矩阵提供了一种高效的方式。
通过选择适当的存储结构,可以显著降低存储空间的占用,并提高数据的访问效率。
稀疏矩阵的压缩存储
稀疏矩阵的压缩存储什么是稀疏矩阵?稀疏矩阵指的是矩阵中绝大部分元素都为0的情况。
这种情况在某些特定的领域中比较常见,如文本处理、网络流分析等等。
在实际的计算过程中,由于存在很多0,导致了计算资源和存储空间的浪费。
因此,为了节省计算和存储资源,必须对稀疏矩阵进行压缩存储。
稀疏矩阵的压缩存储稀疏矩阵的压缩存储有三种方式:顺序表(一维数组)、链表以及顺序表+链表混合存储方式。
1.顺序表压缩顺序表压缩又叫COO压缩方式,即Coordinate(坐标)压缩。
这种方式的主要思想是只存储非0元素的值及其坐标。
具体实现方式是通过三个数组分别存储非零元素的值、行坐标和列坐标。
举个例子,如下所示的一个3x3的矩阵:\begin{bmatrix} 3 & 0 & 0 \\ 0 & 0 & 2 \\ 0 & 4 & 0\end{bmatrix}通过顺序表压缩,可以得到如下的三个数组:值数组:[3, 2, 4]行坐标数组:[1, 2, 3]列坐标数组:[1, 3, 2]这样,我们就可以通过这三个数组还原出原始的稀疏矩阵。
优点:在稀疏矩阵中非零元素比例较小的情况下,能够节省存储空间。
缺点:如果非零元素比例较大,那么存储空间会变得非常庞大,而且由于数组长度不可变,可能造成时间上的浪费。
2.链表压缩链表压缩即CSR(Compressed Sparse Row)压缩方式。
这种方式的主要思想是将矩阵按照行划分,每一行用一个单向链表来存储非零元素的值和列坐标。
这种方式的存储结构如下:-数组A:存储所有非零元素的值,按照行优先排列;-数组IA:存储所有非零元素在A中的下标,以及每行的起始下标(非零元素个数加上上一行的起始下标);-数组JA:存储所有非零元素的列坐标。
还是以前面那个例子为例,用链表压缩方式得到:- A数组:[3, 2, 4]- IA数组:[1, 1+1, 1+1+0, 1+1+0+1]- JA数组:[1, 3, 2]其中,IA数组的4个元素分别表示第1、2、3行以及最后一个非零元素在A数组中的下标。
稀疏矩阵的压缩存储上
第3讲 稀疏矩阵压缩存储上——教学讲义稀疏矩阵是指矩阵中大多数元素为零的矩阵。
从直观上讲,当非零元素个数低于总元素的30 %时,这样的矩阵为稀疏矩阵。
如下图所示的矩阵M 、 N 中,非零元素个数均为8个,矩阵元素总数均为6 ×7 =42 ,显然8 /42 <30 %,所以M 、 N 都是稀疏矩阵。
1 稀疏矩阵的三元组表表示法 ( 1 ) 稀疏矩阵的三元组存储表示对于稀疏矩阵的压缩存储,采取只存储非零元素的方法。
由于稀疏矩阵中非零元素aij 的分布没有规律 ,因此,要求在存储非零元素值的同时还必须存储该非零元素在矩阵中所处的行号和列号的位置信息,这就是稀疏矩阵的三元组表表示法。
每个非零元素在一维数组中的表示形式如下图所示。
说明:为处理方便,将稀疏矩阵中非零元素对应的三元组按“行序为主序”用一维结构体数组进行存放,将矩阵的每一行(行由小到大)的全部非零元素的三元组按列号递增存放。
由此得到矩阵M 、 N 的三元组表A 和B 。
如下图所示。
0 12 9 0 0 0 0 0 0 0 0 0 0 0 -3 0 0 0 0 14 0 0 0 24 0 0 0 0 0 18 0 0 0 0 0 15 0 0 -7 0 0 0M=6×7 0 0 -3 0 0 15 12 0 0 0 18 0 9 0 0 24 0 0 00 0 0 0 -7 0 0 0 0 0 0 00 14 0 0 0 00 0 0 0 07×6N= 稀疏矩阵M 和N三元组的结构( 2 )稀疏矩阵三元组表的类型定义 稀疏矩阵三元组表类型定义如下:#define MAXSIZE 1000 /*设非零元素的个数最多为1000*/ typedef struct { int row, col; /*该非零元素的行下标和列下标*/ ElementType e ; /*该非零元素的值*/ }Triple; typedef struct{ Triple data[MAXSIZE+1]; /* 非零元素的三元组表。
稀疏矩阵的存储与压缩
稀疏矩阵的存储与压缩稀疏矩阵是指其中大部分元素为0的矩阵。
由于矩阵中存在大量的0元素,因此在存储和处理稀疏矩阵时,采用传统的二维数组存储方式会造成大量的存储空间浪费和计算时间过长。
为了高效地存储和处理稀疏矩阵,人们提出了各种稀疏矩阵的存储与压缩方法。
一、压缩存储稀疏矩阵的压缩存储方法主要包括行压缩存储(CSR)、列压缩存储(CSC)和对角线压缩存储(DIA)等。
1. 行压缩存储(CSR)行压缩存储是将稀疏矩阵的非零元素按行存储在一维数组中,并使用两个数组存储每一行的非零元素和其所在的列索引。
举个例子,假设有一个3×3的稀疏矩阵,其非零元素分别为a(1,2)=5、a(2,1)=3、a(2,3)=7和a(3,2)=4,那么行压缩存储的结果为:values = [5, 3, 7, 4]columns = [2, 1, 3, 2]row_pointers = [0, 1, 3, 4]其中values数组存储了非零元素的值,columns数组存储了非零元素所在的列索引,row_pointers数组存储了每一行的非零元素在values 和columns数组中的起始位置。
该压缩存储方法可以有效地节省存储空间,并且便于进行行遍历。
2. 列压缩存储(CSC)列压缩存储与行压缩存储类似,只是将稀疏矩阵的非零元素按列存储在一维数组中,并使用两个数组存储每一列的非零元素和其所在的行索引。
同样以上述的稀疏矩阵为例,列压缩存储的结果为:values = [3, 5, 7, 4]rows = [2, 1, 2, 3]column_pointers = [0, 1, 3, 4]其中values数组存储了非零元素的值,rows数组存储了非零元素所在的行索引,column_pointers数组存储了每一列的非零元素在values 和rows数组中的起始位置。
列压缩存储方法在列遍历时具有较好的性能。
3. 对角线压缩存储(DIA)对角线压缩存储适用于具有某种特定结构的稀疏矩阵,例如对角线稀疏矩阵等。
稀疏矩阵压缩的存储方法
稀疏矩阵压缩的存储方法稀疏矩阵是在大多数元素为零的矩阵中只存储非零元素的一种矩阵表示方法。
稀疏矩阵压缩的存储方法旨在减少内存和存储空间的占用,同时保持矩阵的有效性。
以下是一些常见的稀疏矩阵压缩存储方法:1.压缩行存储(Compressed Row Storage,CRS):该方法将矩阵分为三个数组:值数组、列索引数组和行偏移数组。
值数组存储非零元素的值。
列索引数组存储每个非零元素所在的列索引。
行偏移数组存储每一行的第一个非零元素在值数组中的位置。
这种方法适用于稀疏矩阵中非零元素的分布较为均匀的情况。
2.压缩列存储(Compressed Column Storage,CCS):与CRS相似,但它将列作为主要的单位进行压缩。
值数组、行索引数组和列偏移数组分别存储非零元素的值、行索引和每一列的第一个非零元素在值数组中的位置。
这种方法适用于需要按列进行操作的情况。
3.坐标列表(COO):COO方法以三个数组的形式存储稀疏矩阵的非零元素:行索引、列索引和值。
这种方法的优势在于可以方便地添加和删除元素,但对于大型稀疏矩阵可能会浪费大量内存。
4.对角线存储(Diagonal Storage):如果稀疏矩阵是对称的,并且只存储对角线上和它下面的元素,这种存储方法可能非常有效。
只需存储对角线元素和它们的下面的元素,而忽略上面的元素。
5.分层压缩(Hierarchical Storage):对于大型稀疏矩阵,可以将矩阵分成多个较小的块,并使用其他稀疏矩阵压缩方法对每个块进行单独压缩。
这种方法有助于减小每个块的大小,从而提高存储和检索效率。
选择适当的稀疏矩阵压缩方法取决于矩阵的特点、应用需求和存储资源。
不同的方法在内存占用和操作效率方面都有各自的优劣。
根据具体情况,可以选择最适合的方法以最大程度地减小存储空间。
稀疏矩阵的压缩存储方法及主要运算的实现
稀疏矩阵的压缩存储方法及主要运算的实现稀疏矩阵是指矩阵中大部分元素都是0的矩阵。
由于在实际应用中,很多矩阵的元素大部分都是0,而且矩阵的规模很大,因此可以对稀疏矩阵采用压缩存储方法,减少存储空间的占用。
1.顺序表压缩法:顺序表压缩法是将矩阵中的每个非零元素按顺序存储在一维数组中。
对于每个非零元素,在数组中存储其数值及其在矩阵中的行和列的下标信息。
2.链表压缩法:链表压缩法是使用两个一维数组,一个用于存储非零元素的值,另一个用于存储非零元素所在的行和列的下标。
通过链表将这两个数组连接起来,实现对非零元素的存储和检索。
3.三元组顺序表压缩法:三元组顺序表压缩法是将矩阵中的非零元素及其位置信息以三元组的形式存储在一维数组中,每个三元组包含三个信息:行号、列号和元素的值。
在稀疏矩阵的运算中,主要涉及到矩阵的加法、减法和乘法运算。
在压缩存储的基础上,可以通过对稀疏矩阵进行特定的运算方式来实现这些运算。
1.矩阵加法:对于两个稀疏矩阵A和B,可以先将它们转换成对应的压缩存储方式。
然后对于两个矩阵中的每个非零元素,将它们的值相加得到结果矩阵的对应元素的值。
2.矩阵减法:与矩阵加法类似,对于两个稀疏矩阵A和B,也可以先将它们转换成对应的压缩存储方式。
然后对于两个矩阵中的每个非零元素,将它们的值相减得到结果矩阵的对应元素的值。
3.矩阵乘法:矩阵乘法是比较复杂的稀疏矩阵运算。
对于两个稀疏矩阵A和B,可以先将它们转换成对应的压缩存储方式。
然后通过循环遍历A的行和B的列,并在每次迭代中计算结果矩阵中的对应元素的值。
具体的计算方式是,将A的当前行和B的当前列对应的非零元素进行乘积,并将得到的结果累加到结果矩阵中的对应元素的值。
需要注意的是,由于稀疏矩阵的特殊性,压缩存储方式在空间上会减少存储空间的占用,但在一些具体的运算中,可能会导致运算的效率降低。
因此,在选择稀疏矩阵的压缩存储方式时,需要综合考虑存储空间和运算效率两个方面的因素。
稀疏矩阵压缩存储
稀疏矩阵压缩存储介绍稀疏矩阵是指矩阵中大部分元素为0的矩阵。
由于稀疏矩阵中存在着大量无用的0元素,传统的存储方法会带来较大的存储空间浪费。
稀疏矩阵压缩存储技术就是通过一些有效的方法来压缩存储稀疏矩阵,减少存储空间的占用。
传统存储方法传统的存储方法是将稀疏矩阵直接以二维数组的形式存储,其中包含了大量的0元素。
这种方法的缺点在于浪费了大量的存储空间,尤其对于规模较大且稀疏性较高的矩阵来说,存储效率非常低下。
因此,需要寻求更加高效的存储方法。
压缩存储方法为了解决存储空间浪费的问题,研究者们提出了多种压缩存储方法,常见的方法有行压缩存储和列压缩存储。
下面将详细介绍这两种方法。
行压缩存储(CSR)行压缩存储方法(Compressed Sparse Row,CSR)是最常见的稀疏矩阵压缩存储方法之一。
该方法将稀疏矩阵分为三个部分来存储:数据部分、列指针部分和行偏移部分。
1.数据部分:数据部分存储了矩阵中所有非零元素的值,依次排列。
2.列指针部分:列指针部分存储了每列中非零元素在数据部分中的位置,即指向数据部分的指针。
3.行偏移部分:行偏移部分记录了每行中的第一个非零元素在数据部分中的位置,依次排列。
使用CSR方法存储稀疏矩阵可以有效地压缩存储空间。
然而,该方法需要通过索引来访问矩阵元素,因此在随机访问的情况下性能较低。
列压缩存储(CSC)列压缩存储方法(Compressed Sparse Column,CSC)是另一种常见的稀疏矩阵压缩存储方法。
与CSR方法相比,CSC方法将稀疏矩阵按列进行压缩存储。
1.数据部分:数据部分存储了矩阵中所有非零元素的值,依次排列。
2.行指针部分:行指针部分存储了每行中非零元素在数据部分中的位置,即指向数据部分的指针。
3.列偏移部分:列偏移部分记录了每列中的第一个非零元素在数据部分中的位置,依次排列。
CSC方法相对于CSR方法,在随机访问的情况下性能更好,但在矩阵乘法等操作中性能较低。
稀疏矩阵压缩编码
稀疏矩阵压缩编码是一种针对矩阵中非零元素进行压缩的方法,广泛应用于大规模科学计算、图像处理和机器学习等领域。
由于稀疏矩阵中非零元素数量较少,因此可以通过压缩编码技术去除矩阵中的冗余信息,降低存储和计算复杂度。
常见的稀疏矩阵压缩编码方法包括:
1.三元组方法:将稀疏矩阵中的非零元素以及其行列下标存储起来,形成一个
三元组结构。
这种方法存储简单,但无法高效利用矩阵的非零特征进行压
缩。
2.行链表法:将每一行的非零元素连接起来,形成一个链表。
对于稀疏矩阵,
这种方法可以显著减少存储空间,但需要遍历每一行来恢复原始矩阵。
3.列链表法:类似于行链表法,但按列存储非零元素。
同样适用于稀疏矩阵的
存储,但需要遍历每一列来恢复原始矩阵。
4.十字链表法:在行链表法和列链表法基础上发展而来,将每个非零元素既作
为行链表的结点又作为列链表的结点,形成十字交叉的链表结构。
这种方法能够更高效地压缩稀疏矩阵,同时支持快速矩阵运算和恢复。
在实际应用中,可以根据具体需求选择适合的压缩编码方法。
例如,对于大规模科学计算中的稀疏矩阵存储和传输,行链表法和列链表法可以显著降低存储空间和传输带宽;对于图像处理中的稀疏矩阵表示,十字链表法能够更好地利用图像的非零特征进行压缩,同时支持快速图像处理操作。
稀疏矩阵的压缩存储及运算
稀疏矩阵的压缩存储及运算一、实验内容实现稀疏矩阵的压缩存储方法以及在特定存储方法下的基本运算二、实验母的掌握数组的应用,包括稀疏矩阵、特殊矩阵的压缩存储方法。
矩阵的基本运算的实现,包括矩阵相加、转置、乘法等。
三、问题描述1)用行逻辑链接顺序表和十字链表分别实现稀疏矩阵的压缩存储2)编程实现矩阵的转置运算和乘法运算(运用行逻辑链接顺序表或十字链表作为存储结构)四、问题的实现稀疏矩阵的抽象数据类型定义:ADT SpareseMatrix{数据对象:;,,2,1;,,2,1|{n j m i D a ij ===},,列数分别称为矩阵的行数和和n m ElemSet a j i ∈数据关系: :}1,11|,{}11,1|,{},{,1,1,,n j m i Col n j m i Row Col Row R a a a a j i j i j i j i ≤≤-≤≤><=-≤≤≤≤><==++基本操作:CreateSMatrix(&M);操作结果:创建稀疏矩阵M 。
PrintSMatrix(M);初始条件:稀疏矩阵M 存在。
操作结果:输出稀疏矩阵M 。
AddSMatrix(M ,N ,&Q);初始条件:稀疏矩阵M 和N 的行数和列数对应相等。
操作结果:求稀疏矩阵的和Q=M+N 。
MultSMatrix(M ,N ,&Q);初始条件:稀疏矩阵M 的列数等于N 的行数。
操作结果:求稀疏矩阵乘积Q=M*N 。
TransposeSMatrix(M,&T);初始条件:稀疏矩阵M 存在。
操作结果:求稀疏矩阵M 的转置矩阵T 。
}ADT SpareseMatrix五、主要源程序代码#include <iostream>using namespace std;#define MAXSIZE 100;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 CreatSMatrix_OL(CrossList &M){int i,j,e;OLink q;OLink p;cout<<"请输入稀疏矩阵的行数,列数,非零元素的个数:";cin>>M.mu;cin>>M.nu;cin>>M.tu;M.rhead=(OLink *)malloc((M.mu+1)*sizeof(OLNode));M.chead=(OLink *)malloc((M.nu+1)*sizeof(OLNode));for(i=1;i<=M.mu;i++) M.rhead[i]=NULL;for(i=1;i<=M.nu;i++) M.chead[i]=NULL;cout<<"请输入稀疏矩阵,若为空,则退出"<<endl;cin>>i;cin>>j;cin>>e;while (i!=0){p=(OLink)malloc(sizeof(OLNode));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{q=M.rhead[i];while (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{q=M.chead[j];while (q->down && q->down->i<i)q=q->down;p->down=q->down;q->down=p;}cin>>i;cin>>j;cin>>e;}} //创建十字链表void TurnSMatrix_OL(CrossList &M){int a,b;OLink p,q;for(a<1;a<=M.mu;a++){q=p=M.rhead[a];while(q){b=p->i;p->i=p->j;p->j=b;q=p->right;p->right=p->down;p->down=q;}}} //十字链表实现稀疏矩阵转置int AddSMatrix_OL(CrossList *A,CrossList *B){OLNode *pa,*pb,*p,*pre,*cp[100];int i,j,t;t=A->tu+B->tu;for(j=1;j<=A->nu;j++) cp[j]=A->chead[j];for(i=1;i<=A->mu;i++){pa=A->rhead[i];pb=B->rhead[i];pre=NULL;while(pb){if(pa==NULL || pa->j>pb->j){p=(OLink)malloc(sizeof(OLNode));if(!pre)A->rhead[i]=p;else pre->right=p;p->right=pa;pre=p;p->i=i;p->j=pb->j;p->e=pb->e;if(!A->chead[p->j]){A->chead[p->j]=cp[p->j]=p;p->down=NULL;}else{cp[p->j]->down=p;cp[p->j]=p;}pb=pb->right;}else if(pa->j<pb->j) {pre=pa;pa=pa->right;}else if(pa->e+pb->e){t--;pa->e+=pb->e;pre=pa;pa=pa->right;pb=pb->right;}else{t=t-2;if(!pre)A->rhead[i]=pa->right;else pre->right=pa->right;p=pa;pa=pa->right;if(A->chead[p->j]==p) A->chead[p->j]=cp[p->j]=p->down;else cp[p->j]->down=p->down;free(p);pb=pb->right;}}}A->mu=A->mu>B->mu? A->mu:B->mu;A->nu=A->nu>B->nu? A->nu:B->nu;return 1;} //十字链表实现两稀疏矩阵相加int MultSMatrix_OL(CrossList M,CrossList N,CrossList &Q){int i,j,e;OLink p0,q0,p,p1,p1a;if(M.nu!=N.mu){cout<<"稀疏矩阵A的列数和B的行数不相等,不能相乘";return 0;}Q.mu=M.mu;Q.nu=N.nu;Q.tu=0;if(!(Q.rhead=(OLink *)malloc((Q.mu+1)*sizeof(OLink))))exit(-2);if(!(Q.chead=(OLink *)malloc((Q.nu+1)*sizeof(OLink))))exit(-2);for(i=1;i<=Q.mu;i++) Q.rhead[i]=NULL;for(i=1;i<=Q.nu;i++) 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(p0->j>q0->i) q0=q0->down;else if(p0->j<q0->i) p0=p0->right;else{e+=p0->e*q0->e;q0=q0->down;p0=p0->right;}}if(e){if(!(p=(OLink)malloc(sizeof(OLNode))))exit(-2);Q.tu++;p->i=i;p->j=j;p->e=e;p->right=NULL;p->down=NULL;if(Q.rhead[i]==NULL)Q.rhead[i]=p1=p;else p1->right=p;p1=p;if(Q.chead[j]==NULL)Q.chead[j]=p;else{p1a=Q.chead[j];while(p1a->down)p1a=p1a->down;p1a->down=p;}}}return 1;} //十字链表实现两稀疏矩阵相乘int ShowSMatrix(CrossList *A){int a;OLink p;for(a=1;a<=A->mu;a++)if(A->rhead[a]) {p=A->rhead[a];}while(p){printf("%3d%3d%3d\n",p->i,p->j,p->e);p=p->right;}return 1;} //十字链表显示void main(){int n;char c;CrossList MM,TT,SS;CreatSMatrix_OL(MM);cout<<"您输入的稀疏矩阵(只列出非零元素):"<<endl;cout<<"行列大小"<<endl;ShowSMatrix(&MM);cout<<"请选择操作:"<<endl;cout<<"1:实现稀疏矩阵的转置"<<endl;cout<<"2:实现两稀疏矩阵的相加"<<endl;cout<<"3:实现两稀疏矩阵的相乘"<<endl;cout<<"4:退出程序"<<endl;cin>>n;switch(n){case 1:TurnSMatrix_OL(MM);cout<<"转置后的稀疏矩阵:行列大小"<<endl;ShowSMatrix(&MM);break;case 2:cout<<"请输入另一个稀疏矩阵:"<<endl;CreatSMatrix_OL(TT);AddSMatrix_OL(&MM,&TT);cout<<"相加后的矩阵为:"<<endl;ShowSMatrix(&MM);break;case 3:cout<<"请输入另一个稀疏矩阵:"<<endl;CreatSMatrix_OL(TT);MultSMatrix_OL(MM,TT,SS);cout<<"相乘后的矩阵为:"<<endl;ShowSMatrix(&SS);break;case 4:exit(0);default:cout<<"error!"<<endl;}system("pause");}六、总结整个实验中学会了稀疏矩阵的压缩存储方法,用十字链表来存储,以及在特定存储方法下的基本运算。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
稀疏矩阵及其压缩存储方法1.基本概念稀疏矩阵(SparseMatrix):是矩阵中的一种特殊情况,其非零元素的个数远小于零元素的个数。
设m行n列的矩阵含t个非零元素,则称以二维数组表示高阶的稀疏矩阵时,会产生零值元素占的空间很大且进行了很多和零值的运算的问题。
特殊矩阵:值相同的元素或0元素在矩阵中的分布有一定的规律。
如下三角阵、三对角阵、稀疏矩阵。
压缩存储:为多个值相同的元素只分配一个存储空间;对0元素不分配空间。
目的是节省大量存储空间。
n x n的矩阵一般需要n2个存储单元,当为对称矩阵时需要n(1+n)/2个单元。
2.三元组顺序表——压缩存储稀疏矩阵方法之一(顺序存储结构)三元组顺序表又称有序的双下标法,对矩阵中的每个非零元素用三个域分别表示其所在的行号、列号和元素值。
它的特点是,非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算。
当矩阵中的非0元素少于1/3时即可节省存储空间。
(1)稀疏矩阵的三元组顺序表存储表示方法#define MAXSIZE 12500 // 假设非零元个数的最大值为12500typedef struct {int i, j; // 该非零元的行下标和列下标ElemType e; //非零元素的值} Triple; // 三元组类型typedef union { //共用体Triple data[MAXSIZE + 1]; // 非零元三元组表,data[0]未用int mu, nu, tu; // 矩阵的行数、列数和非零元个数} TSMatrix; // 稀疏矩阵类型(2)求转置矩阵的操作◆用常规的二维数组表示时的算法for (col=1; col<=nu; ++col)for (row=1; row<=mu; ++row)T[col][row] = M[row][col];其时间复杂度为: O(mu×nu)◆用三元组顺序表表示时的快速转置算法Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T) {// 采用三元组顺序表存储表示,求稀疏矩阵M的转置矩阵TT.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) ++num[M.data[t].j];// 求M 中每一列所含非零元的个数cpot[1] = 1;for (col=2; col<=M.nu; ++col) cpot[col] = cpot[col-1] + num[col-1];// 求M 中每一列的第一个非零元在b.data 中的序号for (p=1; p<=M.tu; ++p) { // 转置矩阵元素col = M.data[p].j; q = cpot[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; ++cpot[col];} // for} // ifreturn OK;} // FastTransposeSMatrix其时间复杂度为: O(mu +nu)3.行逻辑联接的顺序表——压缩存储稀疏矩阵方法之二(链接存储结构)行逻辑联接的顺序表:稀疏矩阵中为了随机存取任意一行的非0元素,需要知道每一行的第一个非0元素在三元组表中的位置,因此将上述快速转置算法中指示行信息的辅助数组cpot 固定在稀疏矩阵的存储结构中,让每一行对应一个单链表,每个单链表都有一个表头指针,这种“带行链接信息”的三元组表即称为行逻辑联接的顺序表。
(1)行逻辑联接的顺序表的表示法#define MAXMN 500 // 假设矩阵行数和列数的最大值为500typedef struct {Triple data[MAXSIZE + 1]; // 非零元三元组表,data[0]未用int rpos[MAXMN + 1]; // 指示各行第一个非零元的位置int mu, nu, tu; // 矩阵的行数、列数和非零元个数} RLSMatrix; // 行逻辑链接顺序表类型(2)求矩阵乘法的操作◆矩阵乘法的精典算法:for (i=1; i<=m1; ++i)for (j=1; j<=n2; ++j) {Q[i][j] = 0;for (k=1; k<=n1; ++k) Q[i][j] += M[i][k] * N[k][j];}其时间复杂度为:O(m1 n1 n2)◆用行逻辑联接的顺序表表示时的矩阵乘法Status MultSMatrix(RLSMatrix M, RLSMatrix N, RLSMatrix &Q) {//求矩阵乘积Q=M*N,采用行逻辑链接存储表示。
if (M.nu != N.mu) return ERROR;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的每一行ctemp[] = 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<M.rpos[arow+1];++p) {//对当前行中每一个非零元找到对应元在N中的行号brow=M.data[p].j;if (brow < N.nu ) 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 ERROR;Q.data[Q.tu] = {arow, ccol, ctemp[ccol]};} // if} // for arow} // ifreturn OK;} // MultSMatrix上述算法的时间复杂度分析:◆累加器ctemp初始化的时间复杂度为O (M.mu x N.mu)◆求Q的所有非零元的时间复杂度为O (M.tu x N.tu/N.mu)◆进行压缩存储的时间复杂度为O (M.mu x N.nu)总的时间复杂度就是O (M.mu x N.nu + M.tu x N.tu/N.mu)。
若M是m行n列的稀疏矩阵,N是n行p列的稀疏矩阵,则M中非零元的个数M.tu = d M x m x n,N中非零元的个数N.tu = d N x n x p,相乘算法的时间复杂度就是O (m x p x(1+nd Md N)) ,当d M<0.05 和d N<0.05及n <1000时,相乘算法的时间复杂度就相当于O (mxp)。
显然,这是一个相当理想的结果。
如果事先能估算出所求乘积矩阵Q不再是稀疏矩阵,则以二维数组表示Q,相乘的算法也就更简单了。
4. 十字链表——压缩存储稀疏矩阵方法之三(链接存储结构)(1)基本概念十字链表:是既带行指针又带列指针的链接存储方式,每个三元组结点处于所在行单链表与列单链表的交点处,当矩阵的非零元个数和位置在操作过程中变化较大时,用这种存储结构更为恰当。
在十字链表中,每个非零元可用一个含五个域的结点表示,其中i, j 和e 三个域分别表示该非零元所在的行、列和非零元的值,向右域right 用以链接同一行中下一个非零元,向下域down 用以链接同一列中下一个非零元。
同一行的非零元通过right 域链接成一个线性链表,同一列的非零元通过down 域链接成一个线性链表,每个非零元既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表,故称这样的存储结构为十字链表,可用两个分别存储行链表的头指针和列链表的头指针的一维数组表示之。
例如:矩阵M的十字链表如下图所示。
假设非空指针pa和pb分别指向矩阵A和B中行值相同的两个结点,pa ==NULL 表明矩阵A在该行中没有非零元,则上述四种情况的处理过程为:(1) 若pa==NULL或pa->j 〉pb->j,则需要在A矩阵的链表中插入一个值为bi,j的结点。
此时,需改变同一行中前一结点的right域值,以及同一列中前一结点的down域值。
(2) 若pa->j〈pb->j,则只要将pa指针往右推进一步。
(3) 若pa->j == pb->j且pa->e+pb->e !=0,则只要将ai,j+bi,j 的值送到pa所指结点的e域即可,其它所有域的值都不变。
(4) 若pa->j == pb->j且pa->e+pb->e == 0,则需要在A矩阵的链表中删除pa所指的结点。
此时,需改变同一行中前一结点的right域值,以及同一列中前一结点的down域值。
为了便于插入和删除结点,还需要设立一些辅助指针。
其一是,在A的行链表上设pre 指针,指示pa所指结点的前驱结点;其二是,在A的每一列的链表上设一个指针hl[j],它的初值和列链表的头指针相同,即hl[j]=chead[j]。
(2)稀疏矩阵的十字链表表示与建立的算法(P:104)(3)两个矩阵相加的算法描述(1) 初始令pa和pb分别指向A和B的第一行的第一个非零元素的结点,即pa=A.rhead[1]; pb=B.rhead[1]; pre = NULL;且令hl初始化for (j=1; j<=A.nu; ++j) hl[j]=A.chead[j];(2) 重复本步骤,依次处理本行结点,直到B的本行中无非零元素的结点,即pb==NULL 为止:①若pa==NULL或pa->j〉pb->j(即A的这一行中非零元素已处理完),则需在A中插入一个pb所指结点的复制结点。
假设新结点的地址为p,则A的行表中的指针作如下变化:if pre == NULL rhead[p->i]=p;else { pre->right=p; }p->right=pa; pre = p;A的列链表中的指针也要作相应的改变。