稀疏矩阵的实现

什么是稀疏矩阵,怎么定义才是稀疏矩阵?假设在m x n的矩阵中,有t个不为0的元素。令z=t/(m x n),若z<=0.05则称此矩阵为稀疏矩阵。由于稀疏矩阵的非0元素较少,所以如果用大容量存储必定会造成内存浪费,因此只需存储非0元素值即可,以下列出了常用的三种存储稀疏矩阵的方法。

三元组顺序表

三元组顺序表的实现用顺序存储结构来实现。定义一个数组的结构体,存储的是三元组(即由 3 部分数据组成的集合),组中数据分别表示(行标,列标,元素值)。结构体的实现如下:

//三元组结构体
typedef struct {int i,j;//行标i,列标jint data;//元素值
}triple;
//矩阵的结构表示
typedef struct {triple data[number];//存储该矩阵中所有非0元素的三元组int n,m,num;//n和m分别记录矩阵的行数和列数,num记录矩阵中所有的非0元素的个数
}TSMatrix;


如上图所示即为依次再数组中插入的 三元表。具体实现过程如下所示:

#include <stdio.h>
#define MAXSIZE 100
#define OK 1
#define ERROR 0
#define ELEMTYPE inttypedef struct {int i;   //行int j;   //列ELEMTYPE e; //元素
}Triple;
typedef struct {Triple data[MAXSIZE+1];int mu, nu, tu;
}TSmatrix;
void display(TSmatrix *s);
int main(void)
{TSmatrix s;s.mu = 3;s.nu = 3;s.tu = 3;s.data[0].i = 3;s.data[0].j = 3;s.data[0].e = 6;s.data[1].i = 2;s.data[1].j = 3;s.data[1].e = 8;s.data[2].i = 2;s.data[2].j = 1;s.data[2].e = 4;display(&s);getchar();return 0;
}void display(TSmatrix *s)
{for (int i = 1; i <= s->mu; i++){for (int j = 1; j <= s->nu; j++){int value = 0;            //用来判断是否到了指定的(i,j)位置for (int k = 0; k < s->tu; k++)//遍历数组中的三元表值{if (s->data[k].i == i && s->data[k].j == j) //若遍历至指定(i,j)就打印元素值{value = 1;printf("%d ", s->data[k].e);break;}}if(value==0)  //若不为三元表中存储的值就打印0printf("%d ", 0);}printf("\n");}
}


结果如上图所示,检查矩阵可知打印的位置是没有问题的。
如上所示的方法能够实现稀疏矩阵的存储,但是在数据提取方面效率比较低,现在只是3x3的矩阵可能看不出来,但若是m和n都以千万计的情况下稀疏矩阵中的非0元素个数近似于n,那么时间复杂度就会达到O(m x n xn),这将非常浪费时间。因此在此方法上改进有了下面的方法。

行逻辑链接的顺序表

行逻辑链接顺序表示基于上种方法的改进,在上面的基础上再增加一个数组用来存储用来用于存储三元表的数组中每一行第一个非0元素的位置,这样就无需遍历整个三元表数组,只需要遍历对应行的数据就可以了,大大提高了效率。


使用数组 rpos 记录矩阵中每行第一个非 0 元素在一维数组中的存储位置。遍历的具体过程如下所示:
由 rpos 数组可知,第一行首个非 0 元素位于data[1],因此在遍历此行时,可以直接从第 data[1] 的位置开始,一直遍历到下一行首个非 0 元素所在的位置(data[3]之前;
同样遍历第二行时,由 rpos 数组可知,此行首个非 0 元素位于 data[3],因此可以直接从第 data[3] 开始,一直遍历到下一行首个非 0 元素所在的位置(data[4])之前;
遍历第三行时,由 rpos 数组可知,此行首个非 0 元素位于 data[4],由于这是矩阵的最后一行,因此一直遍历到 rpos 数组结束即可(也就是 data[tu],tu 指的是矩阵非 0 元素的总个数)。

#include <stdio.h>
#define MAXSIZE 100
#define MAXSD  100
#define ELEMTYPE inttypedef struct {int i;int j;ELEMTYPE e;
}Triple;
typedef struct {Triple data[MAXSIZE];int rpos[MAXSD];  //定义rpos数组用于存储每一行第一个非0元素int mu, nu, tu;
}RLSmatrix;
void display(RLSmatrix *s);
int main(void)
{RLSmatrix s;s.mu = 4;s.nu = 3;s.tu = 4;s.data[1].i = 1;s.data[1].j = 1;s.data[1].e = 3;s.data[2].i = 2;s.data[2].j = 2;s.data[2].e = 4;s.data[3].i = 3;s.data[3].j = 3;s.data[3].e = 6;s.data[4].i = 4;s.data[4].j = 3;s.data[4].e = 3;s.rpos[1] = 1;s.rpos[2] = 2;s.rpos[3] = 3;s.rpos[4] = 4;display(&s);getchar();return 0;}void display(RLSmatrix *s)
{for (int i = 1; i <= s->mu; i++){for (int j = 1; j <= s->nu; j++){int value = 0;if(i+1<=s->mu) //假设一共i行则前面的i-1行遍历对应行的元素{for (int k = s->rpos[i]; k < s->rpos[i + 1]; k++) //遍历数组中对应行的非0元素即可{if (s->data[k].i == i && s->data[k].j == j) {value = 1;printf("%d ", s->data[k].e);break;}if (value == 0)printf("0 ");}}else  //最后一行只需遍历到最后一个非0元素即可{for (int k = s->rpos[i]; k <=s->tu; k++){if (s->data[k].i == i && s->data[k].j == j){value = 1;printf("%d ", s->data[k].e);break;}if (value == 0)printf("0 ");}}}printf("\n");}
}

十字链表法存储稀疏矩阵

上面两种存储方式用于固定存储时可以很好的起作用,但是当要涉及非0元素的插入或者删除的时候回引起元素值的移动,例如两矩阵相加的操作,这种时候用链式存储表示三元组更为恰当,该存储方式采用的是 “链表+数组” 结构。


由上图可以看到,非0元素用一个含有五个域的节点表示,两个指针与分别用来指向同一列和同一行的元素。再用两个存储行链表和列链表的一维数组存储这些链表。每一个非0元既是某行链表的一个节点,又是列链表的一个节点。整个矩阵构成了一个十字交叉的链表。

#include<stdio.h>
#include<stdlib.h>
typedef struct OLNode
{int i, j, e; //矩阵三元组i代表行 j代表列 e代表当前位置的数据struct OLNode *right, *down; //指针域 右指针 下指针
}OLNode, *OLink;
typedef struct
{OLink *rhead, *chead; //行和列链表头指针int mu, nu, tu;  //矩阵的行数,列数和非零元的个数
}CrossList;
CrossList CreateMatrix_OL(CrossList M);
void display(CrossList M);
int main()
{CrossList M;M.rhead = NULL;M.chead = NULL;M = CreateMatrix_OL(M);printf("输出矩阵M:\n");display(M);return 0;
}
CrossList CreateMatrix_OL(CrossList M)
{int m, n, t;int i, j, e;OLNode *p, *q;printf("输入矩阵的行数、列数和非0元素个数:");scanf("%d%d%d", &m, &n, &t);M.mu = m;M.nu = n;M.tu = t;if (!(M.rhead = (OLink*)malloc((m + 1) * sizeof(OLink))) || !(M.chead = (OLink*)malloc((n + 1) * sizeof(OLink)))){printf("初始化矩阵失败");exit(0);}for (i = 1; i <= m; i++){M.rhead[i] = NULL;}for (j = 1; j <= n; j++){M.chead[j] = NULL;}for (scanf("%d%d%d", &i, &j, &e); 0 != i; scanf("%d%d%d", &i, &j, &e)) {if (!(p = (OLNode*)malloc(sizeof(OLNode)))){printf("初始化三元组失败");exit(0);}p->i = i;p->j = j;p->e = e;//链接到行的指定位置if (NULL == M.rhead[i] || M.rhead[i]->j > j){p->right = M.rhead[i];M.rhead[i] = p;}else{for (q = M.rhead[i]; (q->right) && q->right->j < j; q = q->right);p->right = q->right;q->right = p;}//链接到列的指定位置if (NULL == M.chead[j] || M.chead[j]->i > i){p->down = M.chead[j];M.chead[j] = p;}else{for (q = M.chead[j]; (q->down) && q->down->i < i; q = q->down);p->down = q->down;q->down = p;}}return M;
}
void display(CrossList M) {for (int i = 1; i <= M.nu; i++){if (NULL != M.chead[i]){OLink p = M.chead[i];while (NULL != p){printf("%d\t%d\t%d\n", p->i, p->j, p->e);p = p->down;}}}
}

数据结构 稀疏矩阵的实现方法相关推荐

  1. 稀疏矩阵 c语言,C语言数据结构 稀疏矩阵

    <C语言数据结构 稀疏矩阵>由会员分享,可在线阅读,更多相关<C语言数据结构 稀疏矩阵(4页珍藏版)>请在人人文库网上搜索. 1.实验十 稀疏矩阵#include #defin ...

  2. 殷人昆 数据结构(用面向对象方法与C++语言描述)(第二版)实现汇总(持续更新)

    殷人昆 数据结构(用面向对象方法与C++语言描述)(第二版)实现汇总 殷人昆 数据结构(用面向对象方法与C++语言描述)(第二版)实现汇总 第二章 线性表 第二章 线性表 约瑟夫问题(线性表实现)约瑟 ...

  3. noj数据结构稀疏矩阵的加法十字链表_数据结构学习(C )稀疏矩阵(十字链表1)

    CSDN 先说说什么叫稀疏矩阵. 你说, 这个问题很简单吗, 那你一定不知道中国学术界的嘴皮子仗, 对一个字眼的"抠"将会导致两种相反的结论.这是清华 2000 年的一道考研题:& ...

  4. noj数据结构稀疏矩阵的加法十字链表_一个算法毁了一款好游戏?算法和数据结构到底有多重要?...

    来源 | 异步 | 文末赠书 前段时间大火的国产游戏--<太吾绘卷>,由于创新的玩法和精良的制作一度广受好评,然而随着玩家游戏的深入和时长的积累,发现该游戏在玩的过程中游戏外的问题很多很多 ...

  5. 脑电分析系列[MNE-Python-2]| MNE中数据结构Epoch及其创建方法

    Epoch概念简介 相信很多人第一次接触epoch时,都会有疑惑,这个词在EEG中到底指的是什么. 下面将详细说明一下. 从连续的脑电图信号中提取一些特定时间窗口的信号,这些时间窗口可以称作为epoc ...

  6. c++矩阵转置_C语言:数据结构-稀疏矩阵的压缩存储

    (1)稀疏矩阵的特点 在一个m×n的矩阵中,设矩阵中有i个元素不为零,并令△=i/(m×n),称△为稀疏因子.通常当△≤0.05时.认为该矩阵为稀疏矩阵. 对这类矩阵实现压缩存储的基本思路是只需要存储 ...

  7. 数据结构稀疏矩阵的加法十字链表_学习数据结构和算法的框架思维

    ----------- 通知:如果本站对你学习算法有帮助,请收藏网址,并推荐给你的朋友.由于 labuladong 的算法套路太火,很多人直接拿我的 GitHub 文章去开付费专栏,价格还不便宜.我这 ...

  8. 面向数据结构的分析设计方法(JSD)

    一,程序设计语言: 1,程序设计语言的分类: 2,面向机器的语言:机器语言,汇编语言 3,高级语言:基础语言,现代语言,专用语言 4,基高级语言:第四代语言(面向对象) 5,从你语言的内在特征来说: ...

  9. 稀疏矩阵的存储方法(DOK、LIL、COO、CSR, CRS)

    存储稀疏矩阵 经常用二维数组来存储矩阵. 用数组的ai,ja_{i,j}ai,j​可以用索引值iii和jjj访问.通常,iii是 行索引,从上往下编号,jjj是列索引,从左到右进行编号.对于m×nm ...

最新文章

  1. String、StringBuffer、StringBuilder介绍
  2. 高并发场景下的缓存有哪些常见的问题?
  3. DSW:面向AI研发的集成开发平台
  4. 基于JAVA+SpringMVC+Mybatis+MYSQL的医学药品信息管理系统
  5. 自动驾驶即将迎来下一个飞跃?
  6. 洛谷——P1652 圆
  7. 解析几何 —— 经典题解
  8. python面对对象实验_实验题目:python面向对象程序设计
  9. 再谈和字体有关的几个问题
  10. 最新语言表示方法XLNet
  11. hone hone clock创意前端时钟
  12. 马斯克在 Clubhouse 上「开房」,讲创业、公司进展,还当了回记者
  13. diy公益拍卖会 杨宗纬吴尊林俊杰s.h.e等拼人气
  14. Android-UI 开源控件
  15. 巴西龟饲养日志----黑壳虾繁殖
  16. C和指针_第16章_标准数函数库_学习笔记
  17. Predict(生成图像)
  18. 负载均衡之LoadBalancer
  19. jvm-sandbox:基础了解及demo演示
  20. php天气城市切换怎么实现,PHP 调用接口生成天气预报 三级联动城市列表 仿中国天气网界面...

热门文章

  1. Leetcode 392. 判断子序列 (每日一题 20210929)
  2. 第二篇:阿里数据中台之OneData体系1
  3. Tableau系列之构建和浏览数据视图
  4. python杨辉三角_干货|杨辉三角与二项式定理
  5. 基于LSTM电商评论情感分析-多评价指标可视化版(内附源码)【自然语言处理NLP-100例】
  6. Anaconda安装jieba方法
  7. 技改之路:从单块应用到微服务,我的血泪总结--转
  8. eclipse 常见问题及解决
  9. 源代码解读Cas实现单点登出(single sign out)功能实现原理--转
  10. 资深算法工程师万宫玺:Java工程师转型AI的秘密法宝——深度学习框架Deeplearning4j | 分享总结