图文并茂的十字链表存储法讲解

212 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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; 
   	}
   }
}