稀疏矩阵――三元组顺序表

匿名 (未验证) 提交于 2019-12-03 00:15:02

Ŀ¼

假设mn的矩阵中,有t的非零元,令s=t/m n,当,s<=0.05时,称此矩阵为稀疏矩阵,简单理解就是非零元特别少的矩阵

//一般矩阵a     1 2 3  a= 4 5 6     7 8 9 //稀疏矩阵s     0 0 0 0 0      0 2 0 0 5  s= 0 0 3 0 0     0 0 0 0 4

一个m * n的矩阵转置后变为 n * m的矩阵

//3*2的矩阵-转置前 1 2  4 5 7 8 //转置后变为2*3 1 4 7 2 5 8

转置后的矩阵每个元素的下表与原来的下表刚好相反,例如上面4转置前的下标为(2,1),转置后变为(1,2);

之所以引入三元组顺序表,是因为,对于稀疏矩阵而言,用传统的存储方法会造成存储空间的浪费

   0 12  9  0  0  0  0    0  0  0  0  0  0  0   -3  0  0  0  0 14  0 M= 0  0 24  0  0  0  0    0 18  0  0  0  0  0   15  0  0 -7  0  0  0  //上面矩阵用三元组表示 i  j  v       1  2  12 1  3  9 3  1  -3 3  6  14 4  3  24  5  2  18 6  1  15 6  4  -7
typedef  struct {     int i,j;     //行坐标、列坐标     ElemType e;  //元素 }Triple;  typedef struct {     Triple date[MAXSIZE+1];  //0不存储元素     int mu,nu,tu;      //行数、列数、非零元个数 }TSMatrix;

传统方法的转置算法时遍历矩阵的每一项,交换其下标值即可

for(col=1;col<=nu;col++) {   for(row=1;row<=mu;row++)   {     T[col][row]=M[row][col]   } }  //时间复杂度 : O(nu*mu)

利用三元组顺序表进行存储的稀疏矩阵要想实现转置显然不能用上面的算法,下面介绍两种方法:

//置换前       存储位置 i  j  v    1  2  12  ->  M.date[1] 1  3  9   ->  M.date[2] 3  1  -3  ->  M.date[3] 3  6  14  ->  M.date[4] 4  3  24  ->  M.date[5] 5  2  18  ->  M.date[6] 6  1  15  ->  M.date[7] 6  4  -7  ->  M.date[8] //置换后       存储位置 i  j  v    1  3  -3  ->  T.date[1] 1  6  15  ->  T.date[2] 2  1  12  ->  T.date[3] 2  5  18  ->  T.date[4] 3  1  9   ->  T.date[5] 3  4  24  ->  T.date[6] 4  6  -7  ->  T.date[7] 6  3  14  ->  T.date[8]
void TransposeSMatrix(TSMatrix *T1,TSMatrix *T2) {     T2->mu=T1->nu;T2->nu=T1->mu;T2->tu=T1->tu;     if(T1->tu)     {         int q=1,col,p;         for(col=1;col<=T1->nu;col++)  //矩阵列循环         {             for(p=1;p<=T1->tu;p++)    //遍历所有元素             {                 if(T1->date[p].j==col)  //当元素在col列时                 {                     T2->date[q].i=T1->date[p].j;                     T2->date[q].j=T1->date[p].i;                     T2->date[q].e=T1->date[p].e;                     q++;                 }             }         }     } } //上述代码,当矩阵运算为满时,即tu=mu*nu,其时间复杂度为O(nu*nu*mu) //这种情况与经典算法相比,虽节省了存储空间,但是效率较低

第一种算法是通过遍历所有元素的下标,从而确定其在转置后数组中的位置,快速转置的思想就是,预先确定每一列第一个非零元在对应转置后的数组date中的位置;因此需要两个辅助数组

num[]:用来存放每一列的非零元个数

cpot[]:存放第一个非零元在转置后数组date中的位置

num[]数组的值很好求,只需要遍历一次所有元素即可

for(t=1;t<=T1->tu;t++)     ++num[T1->date[t].j];

对于cpot[],有一个规律

     col  1 2 3 4 5 6 7 num[col]  2 2 2 1 0 1 0 cpot[col] 1 3 5 7 8 8 9         //规律 copt[1]=1 copt[col]=copt[col-1]+num[col-1]

代码:

void FastTransposeSMatrix(TSMatrix *T1,TSMatrix *T2) {     int num[T1->nu],cpot[T1->nu];     int col,p,q,t;     T2->mu=T1->nu;T2->nu=T1->mu;T2->tu=T1->tu;     if(T1->tu)     {         //初始化每列非零元个数为0         for(col=1;col<=T1->nu;col++)         {             num[col]=0;         }         //求每列非零元个数         for(t=1;t<=T1->tu;t++)         {             ++num[T1->date[t].j];         }         //求每列第一个非零元转置后的位置         cpot[1]=1;         for(col=2;col<=T1->nu;col++)         {             cpot[col]=num[col-1]+cpot[col-1];         }         //遍历所有元素         for(p=1;p<=T1->tu;p++)         {             col=T1->date[p].j;  //获取列坐标             q=cpot[col];        //获取新位置             T2->date[q].i=T1->date[p].j;             T2->date[q].j=T1->date[p].i;             T2->date[q].e=T1->date[p].e;             ++cpot[col];   //之所以这个地方要++,因为每列非零元可能不止一个         }       } }
#include <stdio.h> #include <stdlib.h>  #define  MAXSIZE 12500  //非零元个数的最大值  typedef int ElemType;  typedef  struct {     int i,j;     ElemType e; }Triple;  typedef struct {     Triple date[MAXSIZE+1];     int mu,nu,tu; }TSMatrix; //输入元素 void Insert(TSMatrix *T) {     printf("请依次输入行数i、列数j、非零元个数sum:\n");     int sum ;     scanf("%d%d%d",&T->mu,&T->nu,&sum);     T->tu=sum;     int x,y,num;     printf("请依次输入矩阵非零元的行坐标i、列坐标j、元素值x:\n");     printf("i j v\n");     for(int i=1 ;i<=sum;i++)     {         scanf("%d%d%d",&x,&y,&num);         T->date[i].i=x;         T->date[i].j=y;         T->date[i].e=num;     } } //第一种转置方法 void TransposeSMatrix(TSMatrix *T1,TSMatrix *T2) {     T2->mu=T1->nu;T2->nu=T1->mu;T2->tu=T1->tu;     if(T1->tu)     {         int q=1,col,p;         for(col=1;col<=T1->nu;col++)         {             for(p=1;p<=T1->tu;p++)             {                 if(T1->date[p].j==col)                 {                     T2->date[q].i=T1->date[p].j;                     T2->date[q].j=T1->date[p].i;                     T2->date[q].e=T1->date[p].e;                     q++;                 }             }         }     } } //输出矩阵非零元 void Show(TSMatrix *T) {     printf("转置后的矩阵:\n");     printf("i j v\n");     for(int i=1;i<=T->tu;i++)     {         printf("%d %d %d\n",T->date[i].i,T->date[i].j,T->date[i].e);     } } //快速转置 void FastTransposeSMatrix(TSMatrix *T1,TSMatrix *T2) {     int num[T1->nu],cpot[T1->nu];     int col,p,q,t;     T2->mu=T1->nu;T2->nu=T1->mu;T2->tu=T1->tu;     if(T1->tu)     {         //初始化每列非零元个数为0         for(col=1;col<=T1->nu;col++)         {             num[col]=0;         }         //求每列非零元个数         for(t=1;t<=T1->tu;t++)         {             ++num[T1->date[t].j];         }                  cpot[1]=1;         for(col=2;col<=T1->nu;col++)         {             cpot[col]=num[col-1]+cpot[col-1];         }                  for(p=1;p<=T1->tu;p++)         {             col=T1->date[p].j;             q=cpot[col];             T2->date[q].i=T1->date[p].j;             T2->date[q].j=T1->date[p].i;             T2->date[q].e=T1->date[p].e;             ++cpot[col];         }              } }  int main() {     TSMatrix T,T1,*q,*p;     p=&T;q=&T1;     Insert(p);     //测试第一种转置方法     TransposeSMatrix(p, q);       Show(q);     //测试快速转置     FastTransposeSMatrix(p, q);     Show(q); } /*  测试 请依次输入行数i、列数j、非零元个数sum: 6 7 8 请依次输入矩阵非零元的行坐标i、列坐标j、元素值x: i j v 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 转置后的矩阵: i j v 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7 6 3 14 转置后的矩阵: i j v 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7 6 3 14 Program ended with exit code: 0 */

我不生产代码,我只是代码的搬运工

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!