我们把数组与链表相结合的存储方法称为邻接表(AdjacencyList)。
邻接表的处理办法是这样的:
图中顶点用一个一维数组存储,当然顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便。另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便以查找该顶点的信息。
图中每个顶点Vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
如图1-1就是一个无向图的邻接表结构。
图1-1
.
从图中我们知道,顶点表的各个结点由data和firstedge两个域表示,data是数据域,存储顶点的信息,fitstedge是指针域,指向边表的第一个结点,即此顶点的第一个邻接点。边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某顶点的邻接点在顶点表中的下标,next则存储指向边表中下一个结点的指针。比如v1顶点与v0,v2互为邻接点,则在v1的边表中,adjvex分别为v0的0和v2的2.。
这样的结构,对于我们要获得图的相关信息也是很方便的。比如我们要想知道某个顶点的度,就去查找这个顶点的边表中结点的个数。若要判断顶点vi到vj是否存在边,只需要测试顶点vi的边表中adjvex是否存在结点vj的下标j就行了。若求顶点的所有邻接点,其实就是对此顶点的边表进行遍历,得到的adjvex域对应的顶点就是邻接点。
若是有向图,邻接表结构是类似的,比如图1-2中的第一幅图的邻接表就是第二幅图。但是要要注意的是有向图由于有方向,我们是以顶点为弧尾来存储边表的。这样很容易得到每个顶点的出度。但也有时为了便于确定定的入度或义顶点为弧头的弧,我们可以建立一个有向图的逆邻接表,即每个顶点vi都建立一个链接为vi为弧头的表。如图1-2的第三幅图所示。
图1-2
此时我们很容易就可以算出某个顶点的入度或出度是多少。判断两顶点是否存在弧也很容易实现。
对于带权值的网图,可以在边表结点定义中在增加一个weight的数据域,存储权值信息即可。如图1-3所示。
图1-3
有了这写结构的图,下面关于结点定义的代码就很好理解了。
#include"stdio.h"#include"stdlib.h"#include"io.h"#include"math.h"#include"time.h"#defineOK1#defineERROR0#defineTRUE1#defineFALSE0#defineMAXVEX/*最大顶点数,应由用户定义*/typedefintStatus;/*Status是函数的类型,其值是函数结果状态代码,如OK等*/typedefcharVertexType;/*顶点类型应由用户定义*/typedefintEdgeType;/*边上的权值类型应由用户定义*/typedefstructEdgeNode/*边表结点*/{intadjvex;/*邻接点域,存储该顶点对应的下标*/EdgeTypeinfo;/*用于存储权值,对于非网图可以不需要*/structEdgeNode*next;/*链域,指向下一个邻接点*/}EdgeNode;typedefstructVertexNode/*顶点表结点*/{VertexTypedata;/*顶点域,存储顶点信息*/EdgeNode*firstedge;/*边表头指针*/}VertexNode,AdjList[MAXVEX];typedefstruct{AdjListadjList;intnumNodes,numEdges;/*图中当前顶点数和边数*/}GraphAdjList;/*建立图的邻接表结构*/voidCreateALGraph(GraphAdjList*G){inti,j,k;EdgeNode*e;printf("输入顶点数和边数:\n");scanf("%d,%d",G-numNodes,G-numEdges);/*输入顶点数和边数*/for(i=0;iG-numNodes;i++)/*读入顶点信息,建立顶点表*/{scanf(G-adjList.data);/*输入顶点信息*/G-adjList.firstedge=NULL;/*将边表置为空表*/}for(k=0;kG-numEdges;k++)/*建立边表*/{printf("输入边(vi,vj)上的顶点序号:\n");scanf("%d,%d",i,j);/*输入边(vi,vj)上的顶点序号*/e=(EdgeNode*)malloc(sizeof(EdgeNode));/*向内存申请空间,生成边表结点*/e-adjvex=j;/*邻接序号为j*/e-next=G-adjList.firstedge;/*将e的指针指向当前顶点上指向的结点*/G-adjList.firstedge=e;/*将当前顶点的指针指向e*/e=(EdgeNode*)malloc(sizeof(EdgeNode));/*向内存申请空间,生成边表结点*/e-adjvex=i;/*邻接序号为i*/e-next=G-adjList[j].firstedge;/*将e的指针指向当前顶点上指向的结点*/G-adjList[j].firstedge=e;/*将当前顶点的指针指向e*/}}intmain(void){GraphAdjListG;CreateALGraph(G);return0;}
原文链接: