存图的方式有两种:
一.邻接矩阵法(或关联矩阵)
就是一个简单的 整数型 二维数组。
二.邻接表法 (重点讲解)
它是一种顺序存储(结构体数组)和链式存储(链表)结合的存储方法,它由顶点表(结构体数组)和边表(链表)两个相结合组成。
顶点表 结构体定义
typedef struct Vnode { PtrToAdjVNode FirstEdge; // 存 边表表头 的指针 int Date; // 存顶点的数据(如果这个点有带数据就开)一般用不上。 }AdjList[MAXN]; // 顶点表 第下标i数组存的是 第i点的边表头指针
边表 结构体定义
typedef struct AdjVNode *PtrToAdjVNode; struct AdjVNode { int AdjV; // 邻接点的下标 int Weight; // 顶点到邻接点的 权重 PtrToAdjVNode Next; // 指向下一个邻接点的指针 };
对于 整个图 而言
// 边的定义,输入 两点和其对应边的权重 typedef struct ENode *PtrToENode; struct ENode { int V1,V2; int Weight; // 边的权重 }; typedef PtrToENode Edge; // 图的定义 typedef struct GNode *PtrToGNode; struct GNode { int Nv; // 图的点数 int Ne; // 图的边数 AdjList G; // 邻接表数组 }; typedef PtrToGNode LGraph;
邻接表 可以统计每个点的出度,逆邻接表统计每个点的入度(出入度的大小就是链表的长度)
生成邻接表法如下
LGraph CreateGraph(int VertexNum) { // 初始化一个有 VertexNum 个顶点但没确定边数的图 LGraph Graph; Graph = (LGraph)malloc(sizeof(struct GNode)); Graph->Nv = VertexNum; // 顶点数 Graph->Ne = 0; // 边数 for (int i = 0; i < Graph->Nv; i ++) // 顶点编号从 0->N-1 Graph->G[i].FirstEdge = NULL;// 图 的 顶点表结构体数组 的 边表结构体指针 return Graph; } void InsertEdge(LGraph Graph, Edge E) // 图 和 边权结构体 { PtrToAdjVNode NewNode; // 插入边<V1,V2> ,为V2建立新的邻接点(在边表中) NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); NewNode->AdjV = E->V2; NewNode->Weight = E->Weight; // 把V2邻接点的地址插入到V1的表头中(顶点表中存地址的 FirstEdge 中) NewNode->Next = Graph->G[E->V1].FirstEdge; Graph->G[E->V1],FirstEdge = NewNode; //把最新的V2地址保存在顶点表中,V2的下一个地址就是上一个V2的地址 //相当于插入的邻接点排在边链表的后面 // 如果是无向图,还需要重复上面操作,插入<v2,v1> PtrToAdjVNode NewNode; // 插入边<V2,V1> ,为V1建立新的邻接点 NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); NewNode->AdjV = E->V1; NewNode->Weight = E->Weight; NewNode->Next = Graph->G[E->V2].FirstEdge; Graph->G[E->V2],FirstEdge = NewNode; } LGraph BuildGraph() //生成一个图,用邻接表存 { LGraph Graph; Edge E; int Nv; scanf("%d",&Nv); // 输入顶点个数 Graph = CreateGraph(Nv); scanf("%d",&Graph->Ne); // 输入边数 if (Graph->Ne) // 如果有边 { E = (Edge)malloc(sizeof(struct ENode)); for (int i = 0; i < Graph->Ne; i ++) { scanf("%d %d %d",&E->V1,&E->V2,&E->Weight); InsertEdge(Graph, E); } } return Graph; }
梳理一下: 用 邻接表方法 保存 一个图
用 BuildGraph() 函数,在该函数中,依次调用 CreateGraph() 生成一个有点无边 邻接表,InsertEgde() 把边关系和权值 插入邻接表的边表(链表)中。两个二级函数中,用到了最上面的四个结构体。 最后 BuildGraph() return了 Graph 就是一个完整的 邻接表。
额,,,还是要说一下,我写这些都是为了自己更好的理解,出发点不是为了讲解知识点,如果有人看见这篇文章请别当作学习参考。