为节省存储空间并且加快处理速度,需要对这类矩阵进行压缩存储,压缩存储的原则是:不重复存储相同元素;不存储零值元素。
一、相关概念
㈠特殊矩阵:矩阵中存在大多数值相同的元,或非0元,且在矩阵中的分布有一定规律。
⒈对称矩阵:矩阵中的元素满足
aij=aji 1≤i,j≤n
⒉三角矩阵:上(下)三角矩阵指矩阵的下(上)三角(不包括对角线)中的元素均为常数c或0的n阶矩阵。
⒊对角矩阵(带状矩阵):矩阵中所有非0元素集中在主对角线为中心的区域中。
㈡稀疏矩阵:非0元素很少(≤ 5%)且分布无规律。
二、存储结构及算法思想
1、对称矩阵
存储分配策略: 每一对对称元只分配一个存储单元,即只存储下三角(包括对角线)的元,所需空间数为: n(n+1)/2。
存储分配方法: 用一维数组sa[n(n+1)/2]作为存储结构。
sa[k]与aij之间的对应关系为:
2、三角矩阵
也是一个n阶方阵,有上三角和下三角矩阵。下(上)三角矩阵是主对角线以上(下)元素均为零的n阶矩阵。设以一维数组sb[0..n(n+1)/2]作为n阶三角矩阵B的存储结构,仍采用按行存储方案,则B中任一元素bi,j和sb[k]之间仍然有如上的对应关系,只是还需要再加一个存储常数c的存储空间即可。如在下三角矩阵中,用n(n+1)/2的位置来存储常数。
对特殊矩阵的压缩存储实质上就是将二维矩阵中的部分元素按照某种方案排列到一维数组中,不同的排列方案也就对应不同的存储方案
2、稀疏矩阵
常见的有三元组表示法、带辅助行向量的二元组表示法(也即行逻辑链表的顺序表),十字链表表示法等。
1)、三元组表示法
三元组表示法就是在存储非零元的同时,存储该元素所对应的行下标和列下标。稀疏矩阵中的每一个非零元素由一个三元组(i,j,aij)唯一确定。矩阵中所有非零元素存放在由三元组组成的数组中。
在此,da
以下看如何利用三元组表示法来实现矩阵的转置。
(1)按照b.da
2)、带辅助行向量的二元组表示法及十字链表表示法在下一节中学习介绍。
三、存储结构及C语言描述
1、三元组表示法
(1)按照b矩阵中的行次序依次在a.da
(2)快速转置:按照a.da
恰当位置的确定:首先计算M矩阵的每一列(即T的每一行)中非0元的个数,然后求得M矩阵每一列第一个非0元在b.da
算法基本思想:
设置两个向量:
num[col]:第col列的非零元素个数。
cpot[col]:第col列第一个非零元在b.da
在转置过程中,指示该列下一个非零元在b.da
1、num[col]的计算:
顺序扫描a.da
2、cpot[col]计算:
2)、带辅助行向量的二元组表示法及十字链表表示法在下一节中学习介绍。
四、算法的C语言实现
#include "stdio.h"
#include "stdlib.h"
#define MAXSIZE 12500
#define OK 1
typedef int ElemType;
typedef struct
{
int i,j;
ElemType e;
}Triple;
typedef struct
{
Triple da
int mu,nu,tu; //矩阵行数,列数和非0元个数
}TSMatrix;
int cpot[MAXSIZE+1],num[MAXSIZE+1];
int TransposeSMatrix(TSMatrix M,TSMatrix &T)
{
T.mu=M.nu;
T.nu=M.mu;
T.tu=M.tu;
if(T.tu)
{
int q=1;
for(int col=1;col<=M.nu;++col)
for(int p=1;p<=M.tu;++p)
if(M.da
{
T.da
T.da
T.da
++q;
}//if
}//if
return OK;
}//TransposeSMatrix
int InPutM(TSMatrix &M)
{
printf("input nu mu tu(With a space interval)of a Matrix:\n");
scanf("%d %d %d",&M.nu,&M.mu,&M.tu); //row,colume,and tu
printf("Please input the da
for(int c=1;c<=M.tu;c++)
{
scanf("%d",&M.da
scanf("%d",&M.da
scanf("%d",&M.da
}//for
return 1;
}//InPut
int PrintM(TSMatrix T)
{
printf("Matrix after transpose is:\n");
for(int c=1;c<=T.tu;c++)
{
printf("%d %d %d\n",T.da
}//for
return 1;
}//InPut
int FastTransposeSMatrix(TSMatrix M,TSMatrix &T)
{
T.mu=M.nu;
T.nu=M.mu;
T.tu=M.tu;
if(T.tu)
{
for(int col=1;col<=M.mu;++col) num[col]=0;
for(int t=1;t<=M.tu;++t) ++num[M.da
//非0元的个数
cpot[1]=1;
//求第col列中第一个非零元在b.da
for(int col=2;col<=M.mu;++col)
cpot[col]=cpot[col-1]+num[col-1];
for(int p=1;p<=M.tu;++p)
{
int col=M.da
int q=cpot[col];
T.da
T.da
T.da
++cpot[col];
}//for
}//if
return OK;
}//FastTransposeSMatrix
int main()
{
TSMatrix M,T;
InPutM(M);
//TransposeSMatrix(M,T);
FastTransposeSMatrix(M,T);
PrintM(T);
return OK;
}
上一节中我们讨论的是稀疏矩阵的转置,现在我们讨论稀疏矩阵的相乘,相加,相减。如果预先知道不是稀疏矩阵,则用二维数组相乘法就可以了。如果是,则我们用来存储矩阵的结构称之为行逻辑连接的顺序表,就是加入一个行表来记录稀疏矩阵中每行的非零元素在三元组表中的起始位置。
一、算法思想
在M.da
在此,我们引入rpos[row]用来指示矩阵N的第row行中第一个非零元在N.da
如上图中,N的rpos值为:
二、C语言描述
三、C语言实现
#include "stdio.h"
#include "stdlib.h"
#define MAXSIZE 12500
#define MAXRC 100
#define OK 1
#define ERROR -1
typedef int ElemType;
typedef int Status;
typedef struct
{
int i,j;
ElemType e;
}Triple;
typedef struct
{
Triple da
int rpos[MAXRC+1];//各行第一个非零元的位置表
int mu,nu,tu; //矩阵行数,列数和非0元个数
}RLSMatrix;
int cpot[MAXSIZE+1],num[MAXSIZE+1];
Status CreateSMatrix(RLSMatrix &M)
{ // 创建稀疏矩阵M
int i;
Triple T;
Status k;
printf("请输入矩阵的行数,列数,非零元素数:(Separated by commas)\n");
scanf("%d,%d,%d",&M.mu,&M.nu,&M.tu);
M.da
for(i=1;i<=M.tu;i++)
{
do
{
printf("请按行序顺序输入第%d个非零元素所在的行(1~%d),列(1~%d),元素值:",i,M.mu,M.nu);
printf("the 3 num Separated by commas\n");
scanf("%d,%d,%d",&T.i,&T.j,&T.e);
k=0;
if(T.i<1||T.i>M.mu||T.j<1||T.j>M.nu) // 行、列超出范围
k=1;
if(T.i<M.da
k=1; //&&优先级比||高
}while(k); // 当输入有误,重新输入
M.da
}
for(i=1;i<=M.tu;i++) // 计算rpos[]
if(M.da
for(T.i=0;T.i<M.da
M.rpos[M.da
for(i=M.da
M.rpos[i]=M.tu+1;
return OK;
}//CreateSMatrix
void DestroySMatrix(RLSMatrix &M)
{ // 销毁稀疏矩阵M(使M为0行0列0个非零元素的矩阵)
M.mu=0;
M.nu=0;
M.tu=0;
}//DestroySMatrix
void PrintSMatrix(RLSMatrix M)
{ // 输出稀疏矩阵M
int i;
printf("%d行%d列%d个非零元素。\n",M.mu,M.nu,M.tu);
printf("行 列 元素值\n");
for(i=1;i<=M.tu;i++)
printf("%2d%4d%8d\n",M.da
for(i=1;i<=M.mu;i++)
printf("第%d行的第一个非零元素是本矩阵第%d个元素\n",i,M.rpos[i]);
}//PrintSMatrix
Status MultSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q)
{ // 求稀疏矩阵乘积Q=M*N。
int arow,brow,p,q,ccol,ctemp[MAXRC+1];
if(M.nu!=N.mu) // 矩阵M的列数应和矩阵N的行数相等
return ERROR;
Q.mu=M.mu; // Q初始化
Q.nu=N.nu;
Q.tu=0;
M.rpos[M.mu+1]=M.tu+1; // 为方便后面的while循环临时设置
N.rpos[N.mu+1]=N.tu+1;
if(M.tu*N.tu!=0) // M和N都是非零矩阵
{
for(arow=1;arow<=M.mu;++arow)
{ //从M的第一行开始,到最后一行,arow是M的当前行
for(ccol=1;ccol<=Q.nu;++ccol)
ctemp[ccol]=0; //Q的当前行的各列元素累加器清零
Q.rpos[arow]=Q.tu+1; //Q当前行的第1个元素位于上1行最后1个元素之后
for(p=M.rpos[arow];p<M.rpos[arow+1];++p)
{ // 对M当前行中每一个非零元
brow=M.da
for(q=N.rpos[brow];q<N.rpos[brow+1];++q)
{
ccol=N.da
ctemp[ccol]+=M.da
}//for
} //求得Q中第arow行的非零元
for(ccol=1;ccol<=Q.nu;++ccol) //压缩存储该行非零元
if(ctemp[ccol])
{
if(++Q.tu>MAXSIZE)
return ERROR;
Q.da
Q.da
Q.da
}//if
}//for
}//if
return OK;
}//MultSMatrix
int main()
{
RLSMatrix M,N,Q;
CreateSMatrix(M);
CreateSMatrix(N);
MultSMatrix(M,N,Q);
PrintSMatrix(Q);
DestroySMatrix(M);
DestroySMatrix(N);
DestroySMatrix(Q);
return OK;
}
转自:http://blog.163.com/zhoumhan_0351/blog/static/39954227201001112526244/