开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」第7天,点击查看活动详情 十字链表存稀疏矩阵的方法十分的简单粗暴,
这篇文章带你跳过不讲人话常规讲解的,
高效教会你什么是十字链表。
先上定义:
十字链表整体是一个结构体指针集合,这个集合有五个属性。
分别是,原稀疏矩阵的行数m,原稀疏矩阵的列数m,原稀疏矩阵的非0元素个数cnt
还有存每列 头一个非零元素地址的指针数组 chead(即col_head)
和存每行 头一个非零元素地址的指针数组 rhead(即row_head)
其中每个元素也有自己的数据结构,
每个元素有五个属性
分别是 行坐标,列坐标(指向本元素该列的下一个元素) 行指针(指向本元素该行的下一个元素)
这么说吧,如果原来的矩阵是这样的
我们发现 ,
矩阵的第1行第一列处有元素3, 同时第一行第四列还有一个元素5,
矩阵第二行第二列有元素-1,第三行第一列有元素2.
整理成三元组的形式(行坐标,列坐标,值)就是这样:
(1,1,3) (1,4,5) (2,2,-1) (3,1,2)
我们按顺序输入每个元素的三元组信息,然后我们看每个元素的行和列,
设置变量 id=这个元素的行值,如果rhead[id]为空,说明我们这行的第一个非零元素就是它了
直接把它的地址赋给rhead[id]就行。
倘若rhead[id]不为空的话,我们就从rhead[id]给的地址出发,跑下面这行代码
for (q = M->row_head[i]; q->right&&q->right->col < j; q = q->right);
这行循环的意思是 指针从rhead给出的地址出发,一直向右遍历,
直到找到列值比本元素大的元素,插在它前面就行
p->right = q->right; q->right = p;
以上过程对于列头指针数组也是一样的,就不过多赘述了
那么通过十字链表的表示方式,矩阵压缩的最终形态应该是这样的
部分代码实现:
#include <stdio.h>
#include <malloc.h>
/*十字链表的结构类型定义如下:*/
typedef struct Node
{
int row, col; /*非零元素的行和列下标*/
int value;
struct Node *right; /*非零元素所在行表、列表的后继链域*/
struct Node *down;
} *OLink;
typedef struct
{
OLink *row_head; /*行、列链表的头指针向量*/
OLink *col_head;
int m, n, len; /*稀疏矩阵的行数、列数、非零元素的个数*/
} CrossList;
void CreateCrossList(CrossList *M){
int m, n, t, i, j, e;
Node* q;
Node* p;
scanf("%d%d%d", &m, &n, &t);
M->m = m; M->n = n; M->len = t;
M->row_head = (OLink *)malloc(m * sizeof(OLink));
M->col_head = (OLink *)malloc(n * sizeof(OLink));
for (int h = 0; h <=m; h++) M->row_head[h] = NULL;
for (int t = 0; t <=n; t++) M->col_head[t] = NULL;
for ( scanf("%d%d%d", &i, &j, &e); e != 0; scanf("%d%d%d", &i, &j, &e)){
p = (Node *)malloc(sizeof(Node));
p->row = i; p->col = j; p->value = e;
if (M->row_head[i] == NULL)
M->row_head[i] = p,p->right = NULL;
else{//行
for (q = M->row_head[i]; q->right&&q->right->col < j; q = q->right); /*空循环体*/
p->right = q->right; q->right = p;
}
if (M->col_head[j] == NULL)
M->col_head[j] = p, p->down = NULL;
else{
for (q = M->col_head[j]; q->down&&q->down->row < i; q = q->down);
p->down = q->down;
q->down = p;
}
}
}