【详解】稀疏矩阵的十字链表????

发布时间:2024年01月12日

目录

引言:

稀疏矩阵的十字链表表示

第一步:创结点存数据

第二步:将头结点同数据结点串起来

第三步:创建一个总头结点构成循环链表

总代码如下:

运行结果如下:

结语:


引言:

接上一小结稀疏矩阵的三元组表示(循序表表示),一般有循序表示就有链表表示,今天我们要介绍的就是稀疏矩阵的链表表示???

稀疏矩阵的十字链表表示

十字链表是稀疏矩阵的一种链式存储结构(我前一章写的三元组循序表是稀疏矩阵的一种循序存储结构),如果对三元组不了解的同学可以去我前面一章先看(超详细?)

接着让我们进入十字链表的创建步骤

为了方便大家理解我先给出图片大家可以先看看,行和列都到h【5】

第一步:创结点存数据

既然是链表那么就一定有结点,对于稀疏矩阵中的每个非零元素创建一个结点存放它,存放的数据包括(1)元素行数(2)元素列数(3)元素值

代码如下 (因为增加通用性,故用ElemType方便修改)

union里面有value 和 link两个数据,其中value是存放数据结点的元素值,link是头结点的下一个结点,这里就体现了头结点的重要性,头结点-->link就是下一个结点,头结点-->right就是数据节点了,这样就可以把头结点和数据结点区分开来。

typedef int ElemType;
typedef struct mtxn 
{ 
	int row;					//行号
	int col;					//列号
   	struct mtxn *right,*down;	//向右和向下的指针
	union 
	{
		ElemType value;
		struct mtxn *link;
	} tag;
} MatNode;			//十字链表类型

第二步:将头结点同数据结点串起来

将同一行所有结点串成一个带头结点的循环单链表,将同一列所有结点串成一个带头结点的循环单链表,那么这里我们是不是可以合并呢,将行和列头结点放在一个数据结构里,这样是不是能跟方便一些呢,故我们只需创建MAX(行,列)个结点数,里面有行结点和列结点,这里是用right和down来实现的,头结点始终就那MAX(行,列)个,这里要好好理解。

void CreatMat(MatNode *&mh,ElemType a[][N])	//创建a的十字链表
{
	int i,j;
	MatNode *h[Max],*p,*q,*r;
	mh=(MatNode *)malloc(sizeof(MatNode));//创建十字链表的头结点
	mh->row=M;mh->col=N;
	r=mh;					//r指向尾结点
	for (i=0;i<Max;i++)		//采用尾插法创建头结点h1,h2,…循环链表
	{
		h[i]=(MatNode *)malloc(sizeof(MatNode));
		h[i]->down=h[i]->right=h[i];		//将down和right方向置为循环的
		r->tag.link=h[i];					//将h[i]加到链表中
		r=h[i];
	}
	r->tag.link=mh;							//置为循环链表
	for (i=0;i<M;i++)						//处理每一行
	{
		for (j=0;j<N;j++)					//处理每一列
		{
			if (a[i][j]!=0)					//处理非零元素
			{
				p=(MatNode *)malloc(sizeof(MatNode));	//创建一个新结点
				p->row=i;p->col=j;p->tag.value=a[i][j];
				q=h[i];      					//查找在行表中的插入位置
                while (q->right!=h[i] && q->right->col<j) 
                  	q=q->right;
				p->right=q->right;q->right=p;	//完成行表的插入
				q=h[j];      					//查找在列表中的插入位置
				while (q->down!=h[j] && q->down->row<i) 
					q=q->down;
				p->down=q->down;q->down=p;  	//完成列表的插入
			}
		}
	}
}

第三步:创建一个总头结点构成循环链表

创建一个总头结点方便进行插入删除的各种操作,并有利于查找数据,大家在刷力扣题时,有碰到链表一般都要自己创建一个头结点。

图画如下

以上便是稀疏矩阵的十字链表的创建方法。

创建完那么我们就要开始学习它的基本运算啦~~~~~🎉🎉🎉


创建上面已经给出故这里跳过

void DestroyMat(MatNode *&mh)?? ??? ?//销毁十字链表

一定要注意先后顺序,先释放数据结点再释放头结点循序不能乱,不然内存会泄露(不要内存泄漏🙅?),最后不要忘了要把总结点free掉哦。

void DestroyMat(MatNode *&mh)		//销毁十字链表
{
	MatNode *pre,*p,*mp;
	mp=mh->tag.link;				//mp指向h[i]
	while (mp!=mh)					//释放所有数据结点
	{
		pre=mp->right;				//pre指向h[i]的行首结点
		if (pre!=mp)				//h[i]不空
		{
			p=pre->right;			//p指向结点pre的后继结点
			while (p!=mp)
			{
				free(pre);
				pre=p; p=p->right;
			}
		}
		mp=mp->tag.link;			//mp指向下一个头结点
	}
	//释放所有的头结点
	pre=mh->tag.link;				//pre指向h[i]
	p=pre->tag.link;				//p指向h[i+1]
	while (p!=mh)
	{
		free(pre);
		pre=p; p=p->tag.link;
	}
	free(mh);
}

void DispMat(MatNode *mh)?? ??? ?//输出十字链表

这应该是大家最希望看到的吧,不然我们这么知道我们到底做了些上面呢

注意注意这里是按行开始打印,可以按列哦

用一个循环将所有数据全部输出即可

void DispMat(MatNode *mh)		//输出十字链表
{
	MatNode *p,*q;
	printf("行=%d  列=%d\n", mh->row,mh->col);
	p=mh->tag.link;
	while (p!=mh) 
	{	
		q=p->right;
		while (p!=q) 		//输出一行非零元素
		{
			printf("%d\t%d\t%d\n", q->row,q->col,q->tag.value);
			q=q->right;
		}
		p=p->tag.link;
	}
}

总代码如下:

先创建再打印后销毁,前面最开头一定不要忘了头文件,和#define各项数据哦👌

创建是先头结点后数据结点,销毁是先数据结点后头结点,打印是用头结点去找数据结点,并按照行或列进行打印。

#define  _CRT_SECURE_NO_WARNINGS 1
//稀疏矩阵的十字链表表示
#include <stdio.h>
#include <stdlib.h>
#define M 3
#define N 4
#define Max 4
typedef int ElemType;
typedef struct mtxn
{
	int row;
	int col;
	struct mtxn* right, * down;
	union {
		ElemType value;
		struct mtxn* link;
	}tag;
}MatNode;
void CreateMat(MatNode* mh, ElemType a[][N])
{
	MatNode* h[Max];
	mh->row = M; mh->col = N;
	MatNode* r = mh;
	for (int i = 0; i < Max; i++)
	{
		h[i] = (MatNode*)malloc(sizeof(MatNode));
		h[i]->down = h[i]->right = h[i];
		r->tag.link = h[i];
		r = h[i];
	}
	r->tag.link = mh;
	for(int i =0;i<M;i++)
		for (int j = 0; j < N; j++)
		{
			if (a[i][j] != 0)
			{
				MatNode* p = (MatNode*)malloc(sizeof(MatNode));
				p->row = i; p->col = j; p->tag.value = a[i][j];
				MatNode* q = h[i];
				while(q->right != h[i] && q->right->col < j) q = q->right;
				p->right = q->right; q->right = p;
				q = h[j];
				while (q->down != h[j] && q->down->row < i) q = q->down;
				p->down = q->down; q->down = p;
			}
		}
}
void DispMat(MatNode* mh)		//输出十字链表
{
	MatNode* p, * q;
	printf("行=%d  列=%d\n", mh->row, mh->col);
	p = mh->tag.link;
	while (p != mh)
	{
		q = p->right;
		while (p != q) 		//输出一行非零元素
		{
			printf("%d\t%d\t%d\n", q->row, q->col, q->tag.value);
			q = q->right;
		}
		p = p->tag.link;
	}
}
void DestroyMat(MatNode* mh)
{
	MatNode* pre, * p, * mp;
	mp = mh->tag.link;
	while (mp != mh)
	{
		pre = mp->right;
		while (pre != mp)
		{
			p = pre->right;
			free(pre);
			pre = p;
		}
		mp = mp->tag.link;
	}
	pre = mh->tag.link;
	while (pre != mh)
	{
		p = pre->tag.link;
		free(pre);
		pre = p;
	}
	free(mh);
}
int main()
{
	ElemType a[M][N] = { {1,0,0,2},{0,0,3,0},{0,0,0,4} };
	MatNode* t = (MatNode*)malloc(sizeof(MatNode));
	CreateMat(t,a);
	DispMat(t);
	DestroyMat(t);
	return 0;
}

运行结果如下:

😃😃😃😃😃

总结:我们可以看到稀疏矩阵的十字链表是三元组的改进,运用这两种方法可以很好的解决稀疏矩阵的存储问题,从而节省空间,至于这两种要选择哪一个要看具体情况和自身对那个比较熟练。

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

文章来源:https://blog.csdn.net/2301_80035594/article/details/135540435
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。