数据结构之---C/C++实现稀疏矩阵的十字链表

首先这里介绍什么是矩阵的十字链表,大家可以理解稀疏矩阵是顺序存储的,那么这个就是链式存储的。

如图:

存储该矩阵

那么应该是如下的格式:

我们知道稀疏矩阵的三元组存储方式的实现很简单,每个元素有三个域分别是col,row, e。代表了该非零元的行号、列号以及值。那么在十字链表的存储方式下,首先这三个域是肯定少不了的,不然在进行很多操作的时候都要自己使用计数器,很麻烦。而十字链表的形式大家可以理解成每一行是一个链表,而每一列又是一个链表

通过上面的图我们可以知道,每个结点不止要存放row, col, e。还要存放它横向的下一个结点的地址以及纵向的下一个结点的地址。形成一个类似十字形的链表的结构。

注意Rhead与Chead的类型,它们是指向指针的指针,也就是说,它们是指向我们定义的OLNode结构的结点的指针的指针。

两个版本C语言:

//稀疏矩阵的十字链表存储表示
//杨鑫
#include <stdio.h>
#include <stdlib.h>
typedef int ELemType;
typedef struct OLNode
{
	ELemType e;
	int i, j;
	struct OLNode *right, *down;
}OLNode, *OLink;
typedef struct
{
	OLink *rhead, *chead;
	int mu, nu, tu;
}CrossList;

int create_SMatrix(CrossList *M)
{
	int i, j, m, n, t;
	int k, flag;
	ELemType e;
	OLNode *p, *q;
	if(M->rhead)
	{
		do
		{
			flag = 1;
			printf("输入要创建矩阵的行数,列数,以及非零元素的个数:\n");
			scanf("%d%d%d", &m, &n, &t);
			if(m < 0 || n < 0 || t < 0 || t > m * n)
					flag = 0;
		}while(!flag);
		M->mu = m;
		M->nu = n;
		M->tu = t;
		M->rhead = (OLink *)malloc((m + 1) * sizeof(OLink));
		if(!M->rhead)
				exit(-1);
		M->chead = (OLink *)malloc((n + 1) * sizeof(OLink));
		if(!(M->chead))
				exit(-1);
		for(k = 1; k <= m; k++)
				M->rhead[k] = NULL;
		for(k = 1; k <= n; k++)
				M->chead[k] = NULL;
		for (k=1; k<=t; ++k)
 		{
  			do {
   					flag = 1;
  					printf("输入第%d个结点行号、列号以及值:\n", k);
   					scanf("%d%d%d", &i, &j, &e);
   					if (i<=0 || j<=0)
    				flag = 0;
  			}while (!flag);
			p = (OLink) malloc (sizeof(OLNode));
			if (NULL == p)
  				 exit(-1);
  			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 1;
	}
}

int main()
{
	CrossList M;
    create_SMatrix(&M);
	return 0;
}

如图:

C++版本:

#include<iostream>
#include <stdlib.h>
using namespace std;

typedef int ElemType;
typedef struct _NODE_
{
  int i,j;//行和列下标
  ElemType e;//元素值

  struct _NODE_ *pRight;
  struct _NODE_ *pDown;
}Node,*pNode;
typedef struct _CROSSLIST_
{
  pNode *RowHead,*ColHead;//行和列链表头指针向量
  int iRow,iCol,nodeCount;//矩阵行数,列数,非零元个数
}CrossList,*pCrossList;

//------------------------------------------------
void CreateCrossList(pCrossList pCrossListTemp);//创建十字链表
void PrintCrossList(pCrossList pCrossListTemp);//打印十字链表
//------------------------------------------------

void CreateCrossList(pCrossList pCrossListTemp)
{
  //1.输入行数列数以及非零元个数
  cout<<"输入矩阵几行,几列,几个非零元素:\n";
  cin>>pCrossListTemp->iRow;
  cin>>pCrossListTemp->iCol;
  cin>>pCrossListTemp->nodeCount;
  if(pCrossListTemp->nodeCount > pCrossListTemp->iRow*pCrossListTemp->iCol)
  {
    return;
  }
  //2.动态申请行和列指针数组
  pCrossListTemp->RowHead = (pNode *)malloc(sizeof(pNode)*pCrossListTemp->iRow);
  if(pCrossListTemp->RowHead == NULL)
  {
    return;
  }
  pCrossListTemp->ColHead = (pNode *)malloc(sizeof(pNode)*pCrossListTemp->iCol);
  if(pCrossListTemp->ColHead == NULL)
  {
    free(pCrossListTemp->RowHead);
    return;
  }
  //3.初始化这两个数组
  int i,j;
  for(i = 0; i < pCrossListTemp->iRow; i++)
  {
    pCrossListTemp->RowHead[i] = NULL;
  }
  for(j = 0; j < pCrossListTemp->iCol; j++)
  {
    pCrossListTemp->ColHead[j] = NULL;
  }
  //4.创建节点并连接到十字链表上
  for(i = 0; i < pCrossListTemp->nodeCount; i++)
  {
    //4.1创建节点
    pNode pNodeTemp = (pNode)malloc(sizeof(Node));
    if(pNodeTemp == NULL)
    {
      return;
    }
    cout<<"输入 行 列 元素"<<endl;
    cin>>pNodeTemp->i;
    cin>>pNodeTemp->j;
    cin>>pNodeTemp->e;
    pNodeTemp->pDown = NULL;
    pNodeTemp->pRight = NULL;
    //4.2连接
    //连接行
    //如果该行并没有连接任何节点(NULL)或者该行连接的第一个节点的列值大于当前待连接的节点则直接将当前节点连接到该行第一个节点的位置
    if(pCrossListTemp->RowHead[pNodeTemp->i] == NULL || pCrossListTemp->RowHead[pNodeTemp->i]->j>pNodeTemp->j)
    {
      pNodeTemp->pRight = pCrossListTemp->RowHead[pNodeTemp->i];
      pCrossListTemp->RowHead[pNodeTemp->i] = pNodeTemp;
    }else//否则遍历该行找到合适的位置插入
    {
      pNode pNodeTravel = pCrossListTemp->RowHead[pNodeTemp->i];//指向第一个节点,从第一个节点开始遍历
      while(pNodeTravel->pRight != NULL && pNodeTravel->pRight->j < pNodeTemp->j)//遍历到前一个节点
      {
        pNodeTravel = pNodeTravel->pRight;
      }
      //连接
      pNodeTemp->pRight = pNodeTravel->pRight;
      pNodeTravel->pRight = pNodeTemp;
    }
    //连接列,逻辑跟连接行一致
    if(pCrossListTemp->ColHead[pNodeTemp->j]==NULL || pCrossListTemp->ColHead[pNodeTemp->j]->i>pNodeTemp->i)
    {
      pNodeTemp->pDown = pCrossListTemp->ColHead[pNodeTemp->j];
      pCrossListTemp->ColHead[pNodeTemp->j] = pNodeTemp;
    }else
    {
      pNode pNodeTravel = pCrossListTemp->ColHead[pNodeTemp->j];
      while(pNodeTravel->pDown != NULL && pNodeTravel->pDown->i < pNodeTemp->i)
      {
        pNodeTravel = pNodeTravel->pDown;
      }
      pNodeTemp->pDown = pNodeTravel->pDown;
      pNodeTravel->pDown = pNodeTemp;
    }
  }
}
void PrintCrossList(pCrossList pCrossListTemp)
{
  int i,j;
  pNode pTemp;
  for(i = 0; i < pCrossListTemp->iRow; i++)
  {
    pTemp = pCrossListTemp->RowHead[i];
    for(j = 0; j < pCrossListTemp->iCol; j++)
    {
      if(pTemp != NULL && pTemp->j == j)
      {
        cout<<pTemp->e<<" ";
        pTemp = pTemp->pRight;
      }else
      {
        cout<<"0 ";
      }
    }
    cout<<endl;
  }
  cout<<endl;
}

int main()
{
  CrossList c;
  CreateCrossList(&c);
  cout<<"================分割线========="<<endl;
  PrintCrossList(&c);
  return 0;
}

如图:

时间: 2024-08-02 17:42:31

数据结构之---C/C++实现稀疏矩阵的十字链表的相关文章

看数据结构写代码(21) 稀疏矩阵(十字链表方式)

写完 这个样例,花费了 我不少时间.大部分时间 花费在 调试 内存问题上. 比如在销毁十字链表时.多次释放节点空间,造成 _CrtIsValidHeapPointer(pUserData) 异常. 当使用malloc 分配 一个 空间时,会将这个空间的起始地址和长度 加到一个链表中去.free(p)的时候 ,会从 链表里 查找 是否 有 这个地址空间,找到了就将这个节点从链表中删除._CrtIsValidHeapPointer(pUserData)  这个函数 正是 检查 这个空间是否 在链表里

javascript实现数据结构:稀疏矩阵的十字链表存储表示

当矩阵的非零个数和位置在操作过程中变化大时,就不宜采用顺序存储结构来表示三元组的线性表.例如,在作"将矩阵B加到矩阵A上"的操作时,由于非零元的插入或删除将会引起A.data中元素的移动.为此,对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当. 在链表中,每个非陵园可用一个含5个域的结点表示,其中i,j和e这3个域分别表示该非零元所在的行,列和非零元的值,向右域right用以链接同一行中下一个非零元,向下域down用以链接同一列中下一个非零元.同一行的非零元通过right域

稀疏矩阵的十字链表存储表示

/* Name: 稀疏矩阵的十字链表存储表示 Copyright: Author: 巧若拙 Date: 29-10-14 21:25 Description: //------------------------------------------------------------------------- 除了用三元组顺序表来存储压缩矩阵,我们还可以用链表结构来存储,实际上后者应用更广泛, 因为当非零元素的数目较大时,三元组的时间复杂度实在太高.链表结构中最常见的是十字链表, 在十字链表中,

数据结构之---C++语言实现图的十字链表存储表示

最近一直忙着考研复习,很久都没有更新博客了,今天写一篇数据结构的存储. //有向图的十字链表存储表示 //杨鑫 #include <iostream> #include <cstdio> #include <stdlib.h> #include <cstring> using namespace std; #define MAX_VERTEX_NUM 20 #define OVERFLOW -2 #define OK 1 typedef int Status

[数据结构]图,邻接多重表,十字链表

十字链表 你会发现,要表示一个有向图,因为有 出度 和 入度 ,需要两个邻接表:邻接表和逆邻接表. 其实我们可以把这两个表整合在一起,也就是十字链表(Orthogonal List). 我们依然需要构造一种结构体A,用结构体A的数组来存放所有顶点-我们其实可以把它叫做 顶点表. 我们构造的结构体A如下: data firstin firstout 构造结构体B,用结构体B来记录与这个顶点 用边邻接的 顶点的相关信息,我们把它叫做 边表. tailvex headvex headlink tail

基于十字链表的两个稀疏矩阵相乘

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef int DataType;// 稀疏矩阵的十字链表存储表示 typedef struct LNode { int i,j; // 该非零元的行和列下标 DataType e; // 非零元素值 struct LNode *right,*down; // 该非零元所在行表和列表的后继链域 }LNode, *Link; typedef str

稀疏矩阵的加法(用十字链表实现A=A+B)

描写叙述: 输入两个稀疏矩阵A和B,用十字链表实现A=A+B,输出它们相加的结果. 输入: 第一行输入四个正整数,各自是两个矩阵的行m.列n.第一个矩阵的非零元素的个数t1和第二个矩阵的非零元素的个数t2,接下来的t1+t2行是三元组,各自是第一个矩阵的数据和第二个矩阵的数据, 三元组的第一个元素表示行,第二个元素表示列,第三个元素是该元素的值. 输出: 输出相加后的矩阵三元组. 输入例子: 3 4 3 2 1 1 1 1 3 1 2 2 2 1 2 1 2 2 3 输出例子: 1 1 1 1 

7-3-有向图的十字链表存储结构-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第7章  图 - 有向图的十字链表存储结构 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.Scanf.c.LinkQueue.c        

【算法与数据结构】图 -- 十字链表

图的[十字链表]表示法是一种链式存储结构,可以看成是[邻接表]和[逆邻接表]的组合 本文中用到的有向图 /************************************************************************ 有向图的存储:十字链表 有向图的十字链表存储结构,是有一种链式存储结构,可以看成是[邻接表]和[逆邻接表] 的结合. 图中每条弧对应一个[弧结点],每个顶点对应一个[顶点结点] 弧结点 -------------------------------