稀疏矩阵及其压缩存储方法

合集下载

python稀疏矩阵存储

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.十字链表压缩方法:十字链表压缩是一种特殊的链表压缩方式,因为它在存储矩阵的同时,能够比较直观地表示矩阵的结构信息。

下面是一个矩阵以十字链表方式存储的示例:首先,将矩阵按行、列分别建立链表。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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的列链表中的指针也要作相应的改变。

相关文档
最新文档