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

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/82956082

假设在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<c&&M.data[k].i==r)
        k++;
   if(M.data[k].i==r&&M.data[k].j==c)
        return M.data[k].e;
   return 0;
}

求稀疏矩阵乘积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;j<M.mu;j++){
			if(M.rpos[j+1]){  //给tp赋值给M中下一个有非零元的位置 找到就跳出循环
		      tp=M.rpos[j+1];   
		      break;
			} 
		}
	    if(j==M.mu) //没找到就赋给元素非零元素总数加一
		   tp=M.tu+1;
        for(p=M.rpos[arow];p<tp;p++){//对当前行中的每一个非零元
			if(p){//如果非零元存在
			    blow=M.data[p].j;//找到对应元在N中的行号
				for(j=blow;j<N.mu;j++){//给t赋值N中下一个非零元的位置
		            if(N.rpos[j+1]) { 
		               t=N.rpos[j+1];   
		               break;
					}
				}  
	            if(j==N.mu)
		            t=N.tu+1;
				for(q=N.rpos[blow];q<t;q++){//遍历N中blow行中每一个非零元
                    if(q){//如果非零元存在
			            ccol=N.data[q].j;//乘积元素在Q中列号
			            ctrmp[ccol]+=M.data[p].e*N.data[q].e;//计算当前行的积并存入ctrmp
					} 
			        else//否则跳出循环
                       break;
				}//for q			
			}//创建稀疏矩阵M
			else //否则跳出循环
				break;		    
		}//for p
        for(ccol=1;ccol<=N.nu;ccol++)//遍历ctrmp 如果不为零就压缩存储中Q.data
           if(ctrmp[ccol]){
              if(++Q.tu>MAXSIZE) 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;
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/82956082