(10)稀疏矩阵的三元组表存储方法
- 格式:ppt
- 大小:370.50 KB
- 文档页数:25
数据结构之稀疏矩阵稀疏矩阵的存储方式和操作分析稀疏矩阵是指矩阵中大部分元素为零的特殊矩阵。
在实际应用中,稀疏矩阵经常出现,如图像处理、网络分析和科学计算等领域。
对于稀疏矩阵的存储和操作是数据结构中的重要内容。
本文将介绍稀疏矩阵的存储方式和相关操作的分析。
一、稀疏矩阵存储方式稀疏矩阵的存储方式有多种,其中三元组顺序表和二维数组是比较常用的方法。
1. 三元组顺序表三元组顺序表是一种基于行优先存储的方式,可以将稀疏矩阵以非零元素的形式存储起来。
主要包括行号、列号和元素值三个信息。
以一个4x5的稀疏矩阵为例,其中有三个非零元素分别为A[1][2]=3, A[2][3]=4, A[3][4]=5。
可以使用三元组顺序表来存储:```行号列号元素值1 2 32 3 43 4 5```三元组顺序表的优点是可以节省存储空间,同时也方便进行矩阵的操作。
但是在进行元素的查找和修改时,效率较低。
2. 二维数组二维数组是一种常见的矩阵表示方法,可以直接使用二维数组来表示稀疏矩阵。
其中非零元素的位置用实际的值表示,其余位置用零值表示。
以同样的4x5的稀疏矩阵为例,使用二维数组存储如下:```0 0 0 0 00 0 3 0 00 0 0 4 00 0 0 0 5```二维数组的优点是简单直观,并且可以快速进行元素的查找和修改。
但当稀疏矩阵的规模较大时,会造成较高的存储资源浪费。
二、稀疏矩阵的操作分析对于稀疏矩阵的操作,主要包括矩阵的转置、相加、相乘等。
1. 转置操作稀疏矩阵的转置是指将原始矩阵的行与列对调。
对于三元组顺序表来说,转置操作主要涉及到行号和列号的交换。
而对于二维数组来说,可以直接在取值的时候将行号和列号对调即可。
2. 相加操作稀疏矩阵的相加操作是指将两个矩阵对应位置的元素相加。
对于三元组顺序表来说,可以通过遍历两个矩阵的非零元素,并将其对应位置的元素相加。
而对于二维数组来说,可以直接将对应位置的元素相加即可。
3. 相乘操作稀疏矩阵的相乘操作是指将两个矩阵相乘得到一个新的矩阵。
三元组表示稀疏矩阵本节介绍稀疏矩阵三元序列表的压缩存储方式。
通过《矩阵的压缩存储》一节我们知道,稀疏矩阵的压缩存储,至少需要存储以下信息:•矩阵中各非 0 元素的值,以及所在矩阵中的行标和列标;•矩阵的总行数和总列数;图 1 稀疏矩阵示意图例如,图 1 是一个稀疏矩阵,若对其进行压缩存储,矩阵中各非 0 元素的存储状态如图 2 所示:图 2 稀疏矩阵的压缩存储示意图在图2的数组中,存储了一个三元组(即一组三个部分的数据),分别表示组中的数据(行标签、列标签和元素值)。
注意,这里矩阵的行和列标签都是从1开始的。
C 语言中,三元组需要用结构体实现,如下所示://三元组结构体typedef struct {int i,j;//行标i,列标jint data;//元素值}triple;由于稀疏矩阵中非 0 元素有多个,因此需要建立 triple 数组存储各个元素的三元组。
除此之外,考虑到还要存储矩阵的总行数和总列数,因此可以采用以下结构表示整个稀疏矩阵:#define number 20//矩阵的结构表示typedef struct {triple data[number];//存储该矩阵中所有非0元素的三元组int n,m,num;//n和m分别记录矩阵的行数和列数,num 记录矩阵中所有的非0元素的个数}TSMatrix;可以看到,TSMatrix 是一个结构体,其包含一个三元组数组,以及用于存储矩阵总行数、总列数和非 0 元素个数的变量。
假设采用 TSMatrix 结构体存储图 1 中的稀疏矩阵,其 C 语言实现代码应该为:#include<stdio.h>#define number 3typedef struct {int i,j;int data;}triple;typedef struct {triple data[number];int n,m,num;}TSMatrix;//输出存储的稀疏矩阵void display(TSMatrix M);int main() {TSMatrix M;M.m=3;M.n=3;M.num=3;M.data[0].i=1;M.data[0].j=1;M.data[0].data=1;M.data[1].i=2;M.data[1].j=3;M.data[1].data=5;M.data[2].i=3;M.data[2].j=1;M.data[2].data=3;display(M);return 0;}void display(TSMatrix M){for(int i=1;i<=M.n;i++){for(int j=1;j<=M.m;j++){int value =0;for(int k=0;k<M.num;k++){if(i == M.data[k].i && j ==M.data[k].j){printf("%d ",M.data[k].data); value =1;break;}}if(value == 0)printf("0 ");}printf("\n");}}输出结果为:1 0 00 0 53 0 0。
稀疏矩阵——三元组顺序表⽬录稀疏矩阵假设m*n的矩阵中,有t的⾮零元,令s=t/m * n,当,s<=0.05时,称此矩阵为稀疏矩阵,简单理解就是⾮零元特别少的矩阵//⼀般矩阵a1 2 3a= 4 5 67 8 9//稀疏矩阵s0 0 0 0 00 2 0 0 5s= 0 0 3 0 00 0 0 0 4矩阵的转置⼀个m * n的矩阵转置后变为 n * m的矩阵//3*2的矩阵-转置前1 24 57 8//转置后变为2*31 4 72 5 8转置后的矩阵每个元素的下表与原来的下表刚好相反,例如上⾯4转置前的下标为(2,1),转置后变为(1,2);矩阵压缩存储-三元组顺序表之所以引⼊三元组顺序表,是因为,对于稀疏矩阵⽽⾔,⽤传统的存储⽅法会造成存储空间的浪费0 12 9 0 0 0 00 0 0 0 0 0 0-3 0 0 0 0 14 0M= 0 0 24 0 0 0 00 18 0 0 0 0 015 0 0 -7 0 0 0//上⾯矩阵⽤三元组表⽰i j v1 2 121 3 93 1 -33 6 144 3 245 2 186 1 156 4 -7typedef 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 v1 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 v1 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 7num[col] 2 2 2 1 0 1 0cpot[col] 1 3 5 7 8 8 9//规律copt[1]=1copt[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){//初始化每列⾮零元个数为0for(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){//初始化每列⾮零元个数为0for(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:1 2 121 3 93 1 -33 6 144 3 245 2 186 1 156 4 -7转置后的矩阵:i j v1 3 -31 6 152 1 122 5 183 1 93 4 244 6 -76 3 14转置后的矩阵:i j v1 3 -31 6 152 1 122 5 183 1 93 4 244 6 -76 3 14Program ended with exit code: 0*/我不⽣产代码,我只是代码的搬运⼯。
=====实习报告三“稀疏矩阵的三元组存储”演示程序======(一)、程序的功能和特点1. 程序功能:建立稀疏矩阵的三元组存储,可以键盘输入所要存储的稀疏矩阵,能将输入的稀疏矩阵显示输出。
2. 程序特点:采用java面向对象语言,将三元组和稀疏矩阵用类进行封装。
能方便的储存稀疏,方便的显示稀疏矩阵。
(二)、程序的算法设计算法一:“显示输出稀疏矩阵”算法:1.【逻辑结构与存储结构设计】逻辑结构:线性结构。
存储结构:顺序存储结构。
数组采用三元组顺序存储方法存储该表。
2.【基本操作设计】3.【算法设计】i j v1 1 1 152 1 4 223 1 6 -154 2 2 115 2 3 36 3 4 67 5 1 91 三元组表15 0 0 22 0 -150 11 3 0 0 00 0 0 60 00 0 0 00 091 0 0 00 00 0 0 00 0稀疏矩阵A=开始输出命令输出该稀疏矩阵的行数和列数。
利用for循环按先行后列顺序输出矩阵循环访问稀疏矩阵的每一个元素,通过行号和列号找到稀疏矩阵的在三元组表中是否有存储,若有则输出其值,若没有则输出0.文字说明:(1).首先输出稀疏矩阵的行数和列数。
(2).在通过for 循环依次访问该稀疏矩阵的每一个元素,比较行号和列号,如果行号和列号和三元组所存储的相同,则输出其值;(3).如果不相同或三元数组没有储存则该元素值为零; (4).输出结束。
4.【高级语言代码】 //显示输出稀疏矩阵 void display(){ int i,j,k;System.out .println("稀疏矩阵的行数 "+Rows ); System.out .println("稀疏矩阵的列数 "+Cols ); //按先行后列顺序输出矩阵 for (i=0;i<Rows ;i++) { for (j=0;j<Cols ;j++) {for (k=0;k<Terms ;k++) //查三元组表if (i==smArray [k].row &&j==smArray [k].col ){ System.out .print(smArray [k].value +" "); break ; //打断k 循环 }if (k==Terms ) System.out .print("0.0 "); }System.out .println(); //换行 } }(三)、程序中类的设计“Trituple ”类:1.【逻辑结构与存储结构】 逻辑结构:线性结构。
三元组稀疏矩阵
三元组稀疏矩阵是指矩阵中大部分元素为0,非零元素只占据很小一部分的矩阵。
为了节省存储空间,在表示稀疏矩阵时,通常采用三元组的形式进行存储。
三元组稀疏矩阵的表示方法是将非零元素的值、行号和列号以三元组的形式存储起来。
具体来说,用一个二维数组来表示三元组矩阵,数组的每一行代表一个非零元素,包括三个部分:非零元素的值、行号和列号。
举个例子,假设有一个稀疏矩阵如下:
1 0 0 0
0 0 2 0
0 3 0 0
则可以用三元组稀疏矩阵表示为:
(1, 0, 0)
(2, 1, 2)
(3, 2, 1)
其中,(1, 0, 0)表示非零元素1在第0行第0列,(2, 1, 2)表示非零元素2在第1行第2列,(3, 2, 1)表示非零元素3在第2行第1列。
通过使用三元组表示稀疏矩阵,可以大大减少存储空间的占用,提高矩阵的存储效率。
稀疏矩阵的相关操作稀疏矩阵是指在一个矩阵中,大部分元素为0的矩阵。
由于大部分元素为0,而非零元素相对较少,稀疏矩阵的存储和处理具有一定的特殊性。
在实际应用中,经常需要对稀疏矩阵进行各种操作,如创建、存储、加法操作等。
本文将从这些方面详细介绍稀疏矩阵的相关操作。
首先,创建稀疏矩阵需要考虑两个关键因素:矩阵的大小和矩阵的稀疏性。
对于稀疏矩阵的大小,一般可以使用行数和列数来描述。
而对于稀疏矩阵的稀疏性,可以使用一个矩阵的非零元素个数与总元素个数的比值来衡量,一般使用稀疏度来表示,即非零元素个数与总元素个数的比值。
创建稀疏矩阵的方法有多种,下面介绍两种常见的方法。
1.压缩矩阵存储法:该方法将稀疏矩阵的非零元素和对应的行列坐标存储在一个矩阵中。
其中,矩阵的每一行存储一个非零元素的值、行和列坐标。
这种方法虽然节约了存储空间,但是在进行矩阵操作时,需要通过遍历矩阵找到对应的非零元素,因此操作效率较低。
2.链表存储法:该方法将稀疏矩阵的非零元素和对应的行列坐标存储在一个链表中。
链表的每个节点包含一个非零元素的值、行和列坐标,以及下一个非零元素的指针。
这种方法在插入和删除操作时比较方便,并且节约了存储空间。
但是,链表存储法在进行矩阵操作时,也需要通过遍历链表找到对应的非零元素,因此操作效率较低。
除了创建稀疏矩阵,还需要进行其他各种操作,如稀疏矩阵的加法、乘法、转置等。
稀疏矩阵的乘法操作较为复杂。
对于两个稀疏矩阵相乘,需要根据矩阵乘法的定义,将一个矩阵的行与另一个矩阵的列进行乘法运算,然后将结果相加得到最终的乘积矩阵。
由于稀疏矩阵的特殊性,可以采用稀疏矩阵乘法算法进行计算,提高乘法操作的效率。
1.三元组转置法:该方法将稀疏矩阵的非零元素和对应的行列坐标存储在三个数组中,分别是非零元素数组、行坐标数组和列坐标数组。
将这三个数组的元素进行转置,并重新组合成转置后的稀疏矩阵。
2.链表转置法:该方法将稀疏矩阵的非零元素和对应的行列坐标存储在链表中。
C语言以三元顺序表表示稀疏矩阵1. 引言稀疏矩阵是指大部分元素为零的矩阵,通常在实际应用中占据大量存储空间。
为了高效处理稀疏矩阵,我们通常会采用三元组顺序表的方式进行表示。
本文将探讨如何使用C语言以三元顺序表表示稀疏矩阵,深入理解其原理和实现方法。
2. 稀疏矩阵的表示方法在C语言中,我们可以使用三元组顺序表来表示稀疏矩阵。
三元组顺序表包括三个部分:行号、列号和元素值。
通过这种方式,我们可以有效地压缩稀疏矩阵,节省存储空间,并且方便进行相关的运算。
3. 三元顺序表的数据结构在C语言中,我们可以使用结构体来定义三元顺序表的数据结构。
具体而言,我们可以定义一个包含行号、列号和元素值的结构体,然后通过数组来存储这些结构体,从而表示整个稀疏矩阵。
4. 如何实现C语言表示稀疏矩阵在C语言中,我们可以通过以下步骤来实现稀疏矩阵的表示:1. 定义一个结构体来存储稀疏矩阵的三元组信息。
2. 创建一个数组,用来存储这些结构体,从而表示整个稀疏矩阵。
3. 编写相关的函数,实现稀疏矩阵的压缩、展开以及相关的运算操作。
5. 样例代码下面是一段简单的C语言代码,用来表示一个稀疏矩阵,并进行相关的计算操作:```#include <stdio.h>#define MAXSIZE 12500// 定义三元组结构体typedef struct {int row;int col;int value;} Triple;// 定义稀疏矩阵typedef struct {Triple data[MAXSIZE + 1]; // 0号单元存储矩阵的行数、列数和非零元个数int mu, nu, tu; // 矩阵的行数、列数和非零元个数} TSMatrix;// 主函数int main() {// 在这里编写相关的稀疏矩阵操作return 0;}```6. 总结与展望通过本文的讨论,我们深入了解了C语言以三元顺序表表示稀疏矩阵的原理和实现方法。