本章介绍邻接表无向图。在"图的理论基础"中已经对图进行了理论介绍,这里就再也不对图的概念进行重复说明了。和以往同样,本文会先给出C语言的实现;后续再分别给出C++和Java版本的实现。实现的语言虽不一样,可是原理一模一样,选择其中之一进行了解便可。若文章有错误或不足的地方,请不吝指出! html
目录 node
1. 邻接表无向图的介绍
2. 邻接表无向图的代码说明
3. 邻接表无向图的完整源码git转载请注明出处:http://www.cnblogs.com/skywang12345/github
更多内容:数据结构与算法系列 目录算法
邻接表无向图是指经过邻接表表示的无向图。数组
上面的图G1包含了"A,B,C,D,E,F,G"共7个顶点,并且包含了"(A,C),(A,D),(A,F),(B,C),(C,D),(E,G),(F,G)"共7条边。数据结构
上图右边的矩阵是G1在内存中的邻接表示意图。每个顶点都包含一条链表,该链表记录了"该顶点的邻接点的序号"。例如,第2个顶点(顶点C)包含的链表所包含的节点的数据分别是"0,1,3";而这"0,1,3"分别对应"A,B,D"的序号,"A,B,D"都是C的邻接点。就是经过这种方式记录图的信息的。ui
1. 基本定义spa
// 邻接表中表对应的链表的顶点 typedef struct _ENode { int ivex; // 该边所指向的顶点的位置 struct _ENode *next_edge; // 指向下一条弧的指针 }ENode, *PENode; // 邻接表中表的顶点 typedef struct _VNode { char data; // 顶点信息 ENode *first_edge; // 指向第一条依附该顶点的弧 }VNode; // 邻接表 typedef struct _LGraph { int vexnum; // 图的顶点的数目 int edgnum; // 图的边的数目 VNode vexs[MAX]; }LGraph;
(01) LGraph是邻接表对应的结构体。
vexnum是顶点数,edgnum是边数;vexs则是保存顶点信息的一维数组。指针
(02) VNode是邻接表顶点对应的结构体。
data是顶点所包含的数据,而first_edge是该顶点所包含链表的表头指针。
(03) ENode是邻接表顶点所包含的链表的节点对应的结构体。
ivex是该节点所对应的顶点在vexs中的索引,而next_edge是指向下一个节点的。
2. 建立矩阵
这里介绍提供了两个建立矩阵的方法。一个是用已知数据,另外一个则须要用户手动输入数据。
2.1 建立图(用已提供的矩阵)
/* * 建立邻接表对应的图(用已提供的数据) */ LGraph* create_example_lgraph() { char c1, c2; char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; char edges[][2] = { {'A', 'C'}, {'A', 'D'}, {'A', 'F'}, {'B', 'C'}, {'C', 'D'}, {'E', 'G'}, {'F', 'G'}}; int vlen = LENGTH(vexs); int elen = LENGTH(edges); int i, p1, p2; ENode *node1, *node2; LGraph* pG; if ((pG=(LGraph*)malloc(sizeof(LGraph))) == NULL ) return NULL; memset(pG, 0, sizeof(LGraph)); // 初始化"顶点数"和"边数" pG->vexnum = vlen; pG->edgnum = elen; // 初始化"邻接表"的顶点 for(i=0; i<pG->vexnum; i++) { pG->vexs[i].data = vexs[i]; pG->vexs[i].first_edge = NULL; } // 初始化"邻接表"的边 for(i=0; i<pG->vexnum; i++) { // 读取边的起始顶点和结束顶点 c1 = edges[i][0]; c2 = edges[i][1]; p1 = get_position(*pG, c1); p2 = get_position(*pG, c2); // 初始化node1 node1 = (ENode*)malloc(sizeof(ENode)); node1->ivex = p2; // 将node1连接到"p1所在链表的末尾" if(pG->vexs[p1].first_edge == NULL) pG->vexs[p1].first_edge = node1; else link_last(pG->vexs[p1].first_edge, node1); // 初始化node2 node2 = (ENode*)malloc(sizeof(ENode)); node2->ivex = p1; // 将node2连接到"p2所在链表的末尾" if(pG->vexs[p2].first_edge == NULL) pG->vexs[p2].first_edge = node2; else link_last(pG->vexs[p2].first_edge, node2); } return pG; }
createexamplelgraph()的做用是建立一个邻接表无向图。实际上,该方法建立的无向图,就是上面图G1。
2.2 建立图(本身输入)
/* * 建立邻接表对应的图(本身输入) */ LGraph* create_lgraph() { char c1, c2; int v, e; int i, p1, p2; ENode *node1, *node2; LGraph* pG; // 输入"顶点数"和"边数" printf("input vertex number: "); scanf("%d", &v); printf("input edge number: "); scanf("%d", &e); if ( v < 1 || e < 1 || (e > (v * (v-1)))) { printf("input error: invalid parameters!\n"); return NULL; } if ((pG=(LGraph*)malloc(sizeof(LGraph))) == NULL ) return NULL; memset(pG, 0, sizeof(LGraph)); // 初始化"顶点数"和"边数" pG->vexnum = v; pG->edgnum = e; // 初始化"邻接表"的顶点 for(i=0; i<pG->vexnum; i++) { printf("vertex(%d): ", i); pG->vexs[i].data = read_char(); pG->vexs[i].first_edge = NULL; } // 初始化"邻接表"的边 for(i=0; i<pG->vexnum; i++) { // 读取边的起始顶点和结束顶点 printf("edge(%d): ", i); c1 = read_char(); c2 = read_char(); p1 = get_position(*pG, c1); p2 = get_position(*pG, c2); // 初始化node1 node1 = (ENode*)malloc(sizeof(ENode)); node1->ivex = p2; // 将node1连接到"p1所在链表的末尾" if(pG->vexs[p1].first_edge == NULL) pG->vexs[p1].first_edge = node1; else link_last(pG->vexs[p1].first_edge, node1); // 初始化node2 node2 = (ENode*)malloc(sizeof(ENode)); node2->ivex = p1; // 将node2连接到"p2所在链表的末尾" if(pG->vexs[p2].first_edge == NULL) pG->vexs[p2].first_edge = node2; else link_last(pG->vexs[p2].first_edge, node2); } return pG; }
create_lgraph()是读取用户的输入,将输入的数据转换成对应的无向图。
点击查看:源代码