1
邻接矩阵法有向图、无向图和网对应的邻接矩阵如下图所示:
![abc5204047e19b45223d3ddbac3629fe.png](https://i-blog.csdnimg.cn/blog_migrate/67f9a4ba83a533a456970a4437aa01f1.png)
![f6389abc3361d27c67bd43451e83bb42.png](https://i-blog.csdnimg.cn/blog_migrate/8cecfe2445e6d242e800f9d29b910f79.png)
![259b8d0efd76151db7849b654bd71792.png](https://i-blog.csdnimg.cn/blog_migrate/f35295a1bc2ecf1c40339bab7f7f2769.png)
邻接矩阵存储结构的定义如下:
#define MaxVertexNum 100 //顶点数目的最大值typedef char VertexType; //顶点的数据类型typedef int EdgeType; //带权图中边上权值的数据类型typedef struct{ VertexType Vex [MaxVertexNum] ; //顶点表 EdgeType Edge [MaxVertexNum] [MaxVertexNum]; //邻接矩阵,边表 int vexnum, arcnum; //图的当前顶点数和弧数}MGraph;
2
邻接表法图的邻接表存储方式:
![b2bc0656c8628ee518b9ab0a58d3f705.png](https://i-blog.csdnimg.cn/blog_migrate/29672f51e4bab4f2e956fdfaf8f600e1.png)
邻接表的存储结构的定义如下:
typedef struct ArcNode{ int adjvex; //该边所指向结点的位置 struct ArcNode *next;指向下一条边的指针} ArcNode ;typedef struct{char data; //顶点信息ArcNode *firstarc //指向第一条边的指针}VNode;typedef struct{VNode adjlist[maxSize]; //邻接表int n,e; //顶点数和边数}AGraph;
算法1:将图的邻接矩阵表示法转换为邻接表表示法
思路:先初始化邻接表顶点,再利用嵌套循环遍历邻接矩阵,当邻接矩阵的某个位置有元素时,则将其链入相应的邻接表中。
void AdjMatrixToAdjList( AdjMatrix gm, AdjList gl )//将图的邻接矩阵表示法转换为邻接表表示法。{ for (i=1;i<=n;i++) //邻接表表头向量初始化。 { scanf(&gl[i].vertex); gl[i].firstarc=null; } for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (gm[i][j]==1) { p=(ArcNode *)malloc(sizeof(ArcNode)) ;//申请结点空间。 p->adjvex=j; p->next=gl[i].firstarc; gl[i].firstarc=p; //链入顶点i的邻接点链表中 } }
算法2:将图的邻接表转换成邻接矩阵的算法
思路:转化分两步,一个是顶点数组,一个是邻接矩阵。顶点数组直接循环邻接表的顶点数组赋值,邻接矩阵则需要对每一个顶点结点的firstArc进行判断,如果不是null就把邻接矩阵相应位置赋值为1,表示顶点之间有边,直到该顶点的next是null。
void AdjListToAdjMatrix(AdjList gl, AdjMatrix gm)//将图的邻接表表示转换为邻接矩阵表示。{ for (i=1;i<=n;i++) //设图有n个顶点,邻接矩阵初始化。 for (j=1;j<=n;j++) gm[i][j]=0; for (i=1;i<=n;i++) { p=gl[i].firstarc; //取第一个邻接点。 while (p!=null) { gm[i][p->adjvex]=1; p=p->next; }//下一个邻接点 }//for }//算法结束}
3
十字链表十字链表是有向图的一种链式存储结构。在十字链表中,对应于有向图中的每条弧有一个点,对应于每个顶点也有一个结点。这些结点的结构如下图所示。
![1a7606b1c522923bf15da30e0c1c2ed7.png](https://i-blog.csdnimg.cn/blog_migrate/dec5b822281899711de5289845bfdd5a.png)
弧结点中有5个域:尾域(tailvex) 和头域(headvex) 分别指示弧尾和弧头这两个顶点在图中的位置;链域hlink指向弧头相同的下一条弧;链域tlink指向弧尾相同的下一条弧;info域指向该弧的相关信息。这样,弧头相同的弧就在同一个链表上,弧尾相同的弧也在同一个链表上
顶点结点中有3个域:data域存放顶点相关的数据信息,如顶点名称;firstin和firstout两个域分别指向以该顶点为弧头或弧尾的第一个弧结点。
十字链表的表示方法如下:
![84dd81212439add48a7ba781cdb3e288.png](https://i-blog.csdnimg.cn/blog_migrate/7c9889ab7af2026b899a2b1a2c6b42f2.png)
注意:在十字链表中,既容易找到Vi为尾的弧,又容易找到Vi为头的弧,因而容易求得顶点的出度和入度。图的十字链表表示是不唯一的,但一个十字链表表示确定一个图。
4
邻接多重表邻接多重表是无向图的另一种链式存储结构。在邻接表中,容易求得顶点和边的各种信息,但在邻接表中求两个顶点之间是否存在边而对边执行删除等操作时,需要分别在两个顶点的边表中遍历,效率较低。与十字链表类似,在邻接多重表中,每条边用一个结点表示,其结构如下所示。
![a446d4bd8c253b284de43372da2418ae.png](https://i-blog.csdnimg.cn/blog_migrate/2034dab17664206fcd64279f23084ba6.png)
弧结点中有5个域:尾域(tailvex) 和头域(headvex) 分别指示弧尾和弧头这两个顶点在图中的位置;链域hlink指向弧头相同的下一条弧;链域tlink指向弧尾相同的下一条弧;info域指向该弧的相关信息。这样,弧头相同的弧就在同一个链表上,弧尾相同的弧也在同一个链表上。
![538397561ee3a34acec1d1d6b1b4efd6.png](https://i-blog.csdnimg.cn/blog_migrate/cc8e360dbdaad316f04524f6920e1917.png)
其中,data域存储该顶点的相关信息,firstedge 域指示第一条 依附于该顶点的边。
在邻接多重表中,所有依附于同一顶点的边串联在同一链表中,由于每条边依附于两个顶点,因此每个边结点同时链接在两个链表中。对无向图而言,其邻接多重表和邻接表的差别仅在于,同一条边在邻接表中用两个结点表示,而在邻接多重表中只有一个结点。
无向图的邻接多重表表示如下:
![11de6063d4da58e06a08c36a2000821a.png](https://i-blog.csdnimg.cn/blog_migrate/2ec1f183bc03237bd31fba51d73c88f4.png)