数据结构-稀疏矩阵-静态分配的三元组顺序存储

假设在m*n的矩阵中,有t个元素不为0,令a=t/m*n 称a为矩阵的稀疏因子。通常认为 a<= 0.05时称为稀疏矩阵。

按照压缩存储的概念,只存储稀疏矩阵的非零元。因此,除了存储非零元的值之外,还必须同时几下它所在行和列的位置(i,j)。反之

一个三元组(i,j,aij)唯一确定了矩阵A的一个非零元。因此,稀疏矩阵可由表示非零元的三元组及其行列数唯一确定。

首先是辅助宏的定义:

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define UNDERFLOW -2
#define MAXSIZE 12500 //假设非零元个数的最大值为12500
#define MAXMN   12500//假设最大列数 12500

稀疏矩阵的三元组顺序表存储表示:

//稀疏矩阵的三元组顺序表存储表示
typedef struct{ 
    int i,j; //该非0元的行下标和列下标 
    ElemType e;//非0元的值
}Triple;//三元组类型
typedef struct{
    Triple data[MAXSIZE+1]; //非零元三元组表,data[0] 未采用
    int rpos[MAXMN+1]; //记录各行第一个非0元的位置
    int mu,nu,tu;//矩阵的行数 列数 和非零元个数
}RLSMatrix;//行逻辑链接顺序表类型

创建稀疏矩阵M.

Status CreateSMatrix(RLSMatrix &M){
	//创建稀疏矩阵M
    int i,j,a,flag=0;
    M.tu=0;
    scanf("%d %d",&M.mu,&M.nu);
    if(M.mu<1||M.nu<1)
	return ERROR;
    for(i=1;i<=M.mu;i++){
	M.rpos[i]=0;
        for(j=1;j<=M.nu;j++){
            scanf("%d",&a);
            if(a!=0) {
                M.tu++; //数目增加
                if(!flag) {//flag==0判断是这一行第一个元素 是就赋给M.rpos 并将flag赋1
                    M.rpos[i]=M.tu;
                    flag=1;
                }
                M.data[M.tu].i=i;
                M.data[M.tu].j=j;
                M.data[M.tu].e=a;
            }   
        }
        flag=0;//下一行flag赋0
    }    
     return OK;      
}

销毁稀疏矩阵M.

Status DestroySMatrix(RLSMatrix &M){
    //销毁稀疏矩阵M
    M.mu=0;
    M.nu=0;
    M.tu=0; 
    return OK;
}

输出稀疏矩阵M。

void PrintRLSMatrix(RLSMatrix &M){
    //输出稀疏矩阵M
    int i,j,k=1;
    if(!M.mu||!M.nu||!M.tu)
        printf("空矩阵\n");
    else{
	for(i=1;i<=M.mu;i++){
	   for(j=1;j<=M.nu;j++){
	        if(M.data[k].i==i&&M.data[k].j==j) //行数列数相等
	            printf("%3d",M.data[k++].e);
	        else
	            printf("  0");//否则输出0
           } 
	   printf("\n");  
        } 
    }
    printf("\n"); 
}

由稀疏矩阵M复制得到T.

Status CopySMatrix(RLSMatrix M,RLSMatrix &T){
    //由稀疏矩阵M复制得到T
    T=M;
    return OK;
}

稀疏矩阵Q=M+N.

Status AddSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q){
   //稀疏矩阵Q=M+N
    if(M.mu!=N.mu||M.nu!=N.nu) //M与N 的行数或列数不相等
         return ERROR;
    int i,j,k1=1,k2=1;//k1 M中元素位置 k2 N中元素位置
    Q.tu=0;
    Q.mu=M.mu;
    Q.nu=N.nu;
    for(i=1;i<=M.mu;i++)
       for(j=1;j<=M.nu;j++){
           if(M.data[k1].i==i&&M.data[k1].j==j){//如果M此位置元素非零
		if(N.data[k2].i==i&&N.data[k2].j==j){//如果N此位置元素也非零   
		     if(M.data[k1].e+N.data[k2].e){ //如果两者相加和不为0 赋给Q.data
                         Q.tu++;    
		         Q.data[Q.tu].i=i;
                         Q.data[Q.tu].j=j;
		         Q.data[Q.tu].e=M.data[k1].e+N.data[k2].e;
		     }			           
		     k1++; //下一个非零元素
	             k2++;    
	         } 
	         else { //N中此位置元素为0 
	             Q.tu++;
	             Q.data[Q.tu].i=i;
                     Q.data[Q.tu].j=j;
		     Q.data[Q.tu].e=M.data[k1++].e;    //M中元素赋给Q,data
                 }			         
            } 
            else if(N.data[k2].i==i&&N.data[k2].j==j){//如果N中此位置有非零元素  且M中此位置为0
               Q.tu++;
               Q.data[Q.tu].i=i;
               Q.data[Q.tu].j=j;
               Q.data[Q.tu].e=N.data[k2++].e; //N中元素赋给Q,data
            }  
        }
    return OK;
}

求稀疏矩阵的差Q=M-N.

Status SubtMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q){
    //求稀疏矩阵的差Q=M-N
    if(M.mu!=N.mu||M.nu!=N.nu)//矩阵的行或列不相等
         return ERROR;
    int i,j,k1=1,k2=1;//k1 M中元素位置 k2 N中元素位置
    Q.tu=0;
    Q.mu=M.mu;
    Q.nu=N.nu;
    for(i=1;i<=M.mu;i++)
       for(j=1;j<=M.nu;j++){
           if(M.data[k1].i==i&&M.data[k1].j==j){ //如果M此位置元素非零
		if(N.data[k2].i==i&&N.data[k2].j==j){//如果N此位置元素也非零		 
		    if(M.data[k1].e-N.data[k2].e){//如果两者相加差不为0 赋给Q.data
                        Q.tu++;
                        Q.data[Q.tu].i=i;
                        Q.data[Q.tu].j=j;
                        Q.data[Q.tu].e=M.data[k1].e-N.data[k2].e;
		    }  			           
	            k1++;//下一个非零元素
	            k2++;    
		 } 
	         else{//N中此位置元素为0 
                     Q.tu++;
                     Q.data[Q.tu].i=i;
                     Q.data[Q.tu].j=j;
	             Q.data[Q.tu].e=M.data[k1++].e;        //M中元素赋给Q,data
	         }			     
	    } 
	    else if(N.data[k2].i==i&&N.data[k2].j==j){//如果N中此位置有非零元素  且M中此位置为0
	        Q.tu++;
                Q.data[Q.tu].i=i;//N中元素赋给Q,data
                Q.data[Q.tu].j=j;
		Q.data[Q.tu].e=N.data[k2++].e*-1; 
            }
       }
    return OK;
}

求稀疏矩阵的转置矩阵T.

列号col 从1变到M.tu 扫描M.data每个元素 对于列号等于j的三元组,将其行标列标互换后依次放入T.data中.

Status TransposeSMatrix(RLSMatrix M,RLSMatrix &T)
{
    /*求稀疏矩阵的转置矩阵T
    列号col 从1变到M.tu 扫描M.data每个元素 对于列号等于j的三元组
    ,将其行标列标互换后依次放入T.data中*/
    T.mu=M.nu;
    T.nu=M.mu;
    T.tu=M.tu;
    if(T.tu)//如果不是空矩阵
    {
         int j,k=1,q=1;//q对目标三元组顺序表当前元素计数
	 for(j=1;j<=M.nu;j++)
	      for(k=1;k<=M.tu;k++)
	          if(M.data[k].j==j){//如果当前元素列数等于j M的元素赋给T.data 并把i,j互换
	               T.data[q].e=M.data[k].e;
		       T.data[q].i=M.data[k].j;
		       T.data[q].j=M.data[k].i;
		       q++;
	          }
   } 
   return OK;
}

复杂度O(M.nu*M.tu),当足够稀疏时算法更有效,否则最坏O(M.nu^2*M.mu)。

关键原因在于要重复遍历多次顺序表,能否先遍历一次,求出A的元素在B中应该有的位置,之后直接放入呢?

快速求稀疏矩阵的转置矩阵T:

确定M中的每一列的非零元素的个数 计入数组num M中第col列的第一个元素在T中的位置cpot[col]满足 cpot[col]=cpot[col-1]+num[col-1] cpot[1]=1  用p遍历M 第一次遇到列标为col的元素 放入T中第cpot[col] 个位置 没插入一个cpot[col]加一 后遇到clo直接插入cpot[col]。

Status FastTransposeSMatrix(RLSMatrix M,RLSMatrix &T)
{
     /*快速求稀疏矩阵的转置矩阵T 
     确定M中的每一列的非零元素的个数 计入数组num
     M中第col列的第一个元素在T中的位置cpot[col]满足 cpot[col]=cpot[col-1]+num[col-1] cpot[1]=1
     用p遍历M 第一次遇到列标为col的元素 放入T中第cpot[col] 个位置 没插入一个cpot[col]加一 后遇到clo直接插入cpot[col]*/
     T.mu=M.nu;
     T.nu=M.mu;
     T.tu=M.tu;
     if(T.tu){//不是空矩阵
         int col,t,q;//col 列号 t 元素位置 
	 int * num=(int *)malloc((M.nu+1)*sizeof(int));//0不用 所以多分配一个
	 if(!num) //存储分配失败
	     exit(OVERFLOW);
	 for(col=1;col<=M.nu;col++)
	     num[col]=0; //num赋0
         for(t=1;t<=M.tu;t++)
	     num[M.data[t].j]++;
         int * cpot=(int *)malloc((M.nu+1)*sizeof(int));
         if(!cpot)//存储分配失败
	     exit(OVERFLOW);
         cpot[1]=1;//M中第一个列标为1的非零元素必在T的第一位置
         for(col=2;col<=M.nu;col++)
             cpot[col]=cpot[col-1]+num[col-1];
         for(t=1;t<=M.tu;t++) {
             col=M.data[t].j;//求列号
	     q=cpot[col];//求插入位置
	     T.data[q].e=M.data[t].e;
	     T.data[q].j=M.data[t].i;
	     T.data[q].i=M.data[t].j;
             cpot[col]++;//插入位置自增
	 }
	 free(num);//销毁清空
	 free(cpot);
	 num=NULL;
	 cpot=NULL;
     }
     return OK;
}

复杂度:O(M.nu+M.tu) 空间多了num[M.nu+1]  cpot[M.nu+1] ,O(M.nu)

给定下标 求元素的指定值:

ElemType Value(RLSMatrix M,int r,int c){
   //给定下标 求元素的指定值
   int k=M.rpos[r];   //r行第一个非零元素的位置
   while(M.data[k].j

求稀疏矩阵乘积Q=M*N。

遍历M中当前行非零元M.data[rpos[Mrow]..rpos[Mrow+1]-1],设在j列遍历N中第j行非零元N.data[rpos[j]...rpos[j+1]-1],设坐标为[j][col]计算M.data[Mrow][j]*N.data[j][col]累计至Qtemp[col]

Status MultSMatrix(RLSMatrix M,RLSMatrix N,RLSMatrix &Q){
   //求稀疏矩阵乘积Q=M*N
   if(M.nu!=N.mu) //M列数不等于N的行数
       return ERROR;
   Q.mu=M.mu;//Q初始化
   Q.nu=N.nu;
   Q.tu=0;
   int *ctrmp=(int *)malloc((N.nu+1)*sizeof(int)); 
   if(!ctrmp) //存储分配失败
       exit(OVERFLOW);
   if(M.tu*N.tu!=0) {//Q是非零矩阵
   int arow,blow,tp,p,t,q,i,ccol,j;
   for(arow=1;arow<=M.mu;arow++){//逐行求积
       for(i=1;i<=N.nu;i++)
           ctrmp[i]=0;//Q中各行累加器归零
       Q.rpos[arow]=Q.tu+1; //Q的rpos赋值
       for(j=arow;jMAXSIZE) 
                  return ERROR; //超出最大容量
	      Q.data[Q.tu].e=ctrmp[ccol];
              Q.data[Q.tu].i=arow;
              Q.data[Q.tu].j=ccol;
	   } 
       }//for arow
   }//if
   return OK;
}

 

 

 

 

 

 

你可能感兴趣的:(数据结构)