7-1 稀疏矩阵 (30 分)
如果一个矩阵中,0元素占据了矩阵的大部分,那么这个矩阵称为“稀疏矩阵”。对于稀疏矩阵,传统的二维数组存储方式,会使用大量的内存来存储0,从而浪费大量内存。为此,可以用三元组的方式来存放一个稀疏矩阵。
对于一个给定的稀疏矩阵,设第r行、第c列值为v,且v不等于0,则这个值可以表示为 <r,v,c>。这个表示方法就称为三元组。那么,对于一个包含N个非零元素的稀疏矩阵,就可以用一个由N个三元组组成的表来存储了。
如:{<1, 1, 9>, <2, 3, 5>, <10, 20, 3>}就表示这样一个矩阵A:A[1,1]=9,A[2,3]=5,A[10,20]=3。其余元素为0。
要求查找某个非零数据是否在稀疏矩阵中,如果存在则输出其所在的行列号,不存在则输出ERROR。
输入格式:
共有N+2行输入: 第一行是三个整数m, n, N(N<=500),分别表示稀疏矩阵的行数、列数和矩阵中非零元素的个数,数据之间用空格间隔; 随后N行,输入稀疏矩阵的非零元素所在的行、列号和非零元素的值; 最后一行输入要查询的非0数据k。
输出格式:
如果存在则输出其行列号,不存在则输出ERROR。
输入样例:
在这里给出一组输入。例如:
10 29 3
2 18 -10
7 1 98
8 10 2
2
输出样例:
在这里给出相应的输出。例如:
8 10
解题思路:实际上这道题用三元组写轻松解决,但是这里想讲的是十字链表;
十字链表的图大致如下:
那么如何去实现呢;
看以下代码:因为下面都有注释,这里便不赘述了。
1 #include<iostream> 2 #include<stdio.h> 3 using namespace std; 4 5 struct OLNod{ 6 int i ; //该非零元的行下标; 7 int j ; //该非零元 的列下标; 8 int value ; //该非零元的数值; 9 struct OLNod *right ,*down ;//该非零元所在的行表和列表的后继链域; 10 }; 11 struct CrossL{ 12 OLNod **rhead, **sead; 13 //十字链表的行头指针和列头指针; 定义为指向指针的指针; 14 int row; //稀疏矩阵的行数; 15 int col; //稀疏矩阵的列数; 16 int num; //稀疏矩阵的非零个数; 17 }; 18 19 int InitSMatrix(CrossL *M) //初始化M(CrossL)类型的变量必须初始化; 20 { 21 (*M).rhead = (*M).sead = NULL; 22 (*M).row = (*M).col = (*M).num = 0; 23 return 1; 24 } 25 26 int DestroysMatrix(CrossL *M) //销毁稀疏矩阵M; 27 { 28 int i ; 29 OLNod *p,*q; 30 for( i = 1 ; i <= (*M).row;i++) 31 { 32 p = *((*M).rhead+i); //p指针不断向右移; 33 while(p!=NULL) 34 { 35 q = p ; 36 p = p ->right; 37 delete q; //删除q; 38 } 39 } 40 delete((*M).rhead); //释放行指针空间; 41 delete((*M).sead); //释放列指针空间; 42 (*M).rhead = (*M).sead = NULL; //并将行、列头指针置为空; 43 (*M).num = (*M).row = (*M).col = 0; //将非零元素,行数和列数置为0; 44 return 1; 45 } 46 int CreatSMatrix(CrossL *M) 47 { 48 int i , j , m , n , t; 49 int value; 50 OLNod *p,*q; 51 if((*M).rhead!=NULL) 52 DestroysMatrix(M); 53 cin>>m>>n>>t; //输入稀疏矩阵的行数、列数和非零元个数; 54 (*M).row = m; 55 (*M).col = n ; 56 (*M).num = t; 57 //初始化行链表头; 58 (*M).rhead = new OLNod*[m+1];//为行头指针申请一个空间; 59 if(!(*M).rhead) //如果申请不成功,则退出程序; 60 exit(0); 61 //初始化列链表头; 62 (*M).sead = new OLNod*[n+1];//为列表头申请一个空间; 63 if(!(*M).sead) //如果申请不成功,则退出程序; 64 exit(0); 65 for(int k = 1 ; k <= m ; k++) 66 { 67 (*M).rhead[k] = NULL;//初始化行头指针向量;各行链表为空链表; 68 } 69 for(int k = 1 ; k <= n ;k++) 70 { 71 (*M).sead[k] = NULL;//初始化列头指针向量;各列链表为空链表; 72 } 73 for(int k = 0 ; k < t ;k++) //输入非零元素的信息; 74 { 75 cin>>i>>j>>value;//输入非零元的行、列、数值; 76 p = new OLNod();//为p指针申请一个空间; 77 if(!p) //e如果申请不成功; 78 exit(0); //退出程序; 79 p->i = i; 80 p->j = j; 81 p->value = value; 82 if((*M).rhead[i]==NULL) //如果行头指针指向的为空; 83 { 84 //p插在该行的第一个结点处; 85 p->right = (*M).rhead[i]; 86 (*M).rhead[i] = p; 87 }else //如果不指向空 88 { 89 for(q = (*M).rhead[i];q->right; q = q->right); 90 p->right = q->right; 91 q->right = p; 92 93 } 94 if((*M).sead[j]==NULL)//如果列头指针指向的为空; 95 { 96 //p插在该行的第一个结点处; 97 p->down = (*M).sead[j]; 98 (*M).sead[j] = p; 99 }else//如果不指向空 100 { 101 for(q = (*M).sead[j];q->down;q = q->down); 102 p->down = q->down; 103 q->down = p; 104 } 105 } 106 return 1; 107 } 108 int PrintSMatrix(CrossL *M) 109 { 110 int flag = 0; 111 int val ;//要查找的元素的值; 112 cin>>val; //输入要查找的s值; 113 OLNod *p; 114 for(int i = 1 ; i <= (*M).row ;i++) 115 { 116 for(p = (*M).rhead[i];p;p = p->right) //从行头指针开始找,不断向右找 117 { 118 if(p->value==val) //如果能找到 119 { 120 cout<<p->i<<" "<<p->j; //输出行下标和列下标 121 flag = 1; //标记找到该元素; 122 } 123 } 124 } 125 126 127 if(flag==0) //如果找不到
128 { 129 cout<<"ERROR\n"; 130 } 131 132 } 133 int main() 134 { 135 CrossL A; //定义一个十字链表; 136 InitSMatrix(&A); //初始化; 137 CreatSMatrix(&A); //创建; 138 PrintSMatrix(&A); //输出; 139 DestroysMatrix(&A); //销毁; 140 return 0; 141 }