看数据结构写代码(36) 图的邻接表表示与实现

来源:互联网 发布:淘宝宝贝展示代码 编辑:程序博客网 时间:2024/04/28 10:33

图的邻接表表示法,是为每一个顶点建立一个链表,链表里存放着相同弧尾的 弧的信息,这些链表顺序存放在数组中。下面是无向图g2的邻接表 


邻接表 比 邻接矩阵 节省空间,同时 也带来一些操作上的 不便,例如 看 两个顶点是否 相邻,需要 遍历 链表,在 求 无向图顶点的度时,只需 遍历 顶点的链表,而 求 有向图 顶点的度 需要 遍历 整个图 查找 弧头 为这个顶点的 个数。 如果 不想这样做,可以 建立 逆邻接表,即 链表里 存放着 相同 弧头的 弧 的信息。 下一节 要说的 十字链表 类似于这种结构。

下面 上代码:

源代码网盘地址:点击打开链接

// Graph.cpp : 定义控制台应用程序的入口点。//图的邻接表 表示法#include "stdafx.h"#include <cstdlib>#include <climits>#define MAX_VERTEX_NUM 20#define INFINITY INT_MAXenum E_Graph_Kind  {      DG = 0,//有向图      DN,//有向网      UDG,//无向图      UDN,//无向网  };  struct ArcNode//边(弧){int adjVex;//顶点在数组中的位置ArcNode * nextAdj;int weight;//权值};typedef struct VNode//顶点{ArcNode * head;//头指针char vexName;//顶点名称}AdjList[MAX_VERTEX_NUM];struct Graph//图{AdjList list;//邻接表int arcNum,vexNum;E_Graph_Kind kind;};//顶点在数组中的位置int vexLocation(Graph g,char vex){for (int i = 0; i < g.vexNum; i++){if (g.list[i].vexName == vex){return i;}}return -1;}ArcNode * getHeadNode(){//获得头节点..ArcNode * node = (ArcNode*)malloc(sizeof(ArcNode));if (node != NULL){node->adjVex = -1;node->nextAdj = NULL;node->weight = INFINITY;}return node;}ArcNode * getArcNode(Graph g,char vexName){ArcNode * node = getHeadNode();if (node != NULL){int location = vexLocation(g,vexName);node->adjVex = location;}return node;}void createDG(Graph * graph);  void createDN(Graph * graph);  void createUDG(Graph * graph);  void createUDN(Graph * graph);    void graphCreate(Graph * graph){      E_Graph_Kind kind;      printf("请输入要创建的图的类型(有向图:0,有向网:1,无向图:2,无向网:3)\n");      scanf("%d",&kind);      switch (kind){      case DG:          createDG(graph);          break;      case DN:          createDN(graph);          break;      case UDG:          createUDG(graph);          break;      case UDN:          createUDN(graph);          break;      default:          break;      }  } //有向图void createDG(Graph * g){g->kind = DG;printf("输入图的顶点树 和 边(弧)树\n");scanf("%d%d%*c",&g->vexNum,&g->arcNum);      //构造顶点集      printf("请输入顶点集\n");      for (int i = 0; i < g->vexNum; i++){          char name;scanf("%c",&name);g->list[i].vexName = name;g->list[i].head = getHeadNode();//头指针指向头节点.    }      //构造顶点关系      fflush(stdin);      printf("请输入顶点的关系\n");      for (int i = 0; i < g->arcNum; i++){          char vex1,vex2;          scanf("%c%c%*c",&vex1,&vex2);  int location1 = vexLocation(*g,vex1);    ArcNode * node = getArcNode(*g,vex2);node->nextAdj = g->list[location1].head->nextAdj;g->list[location1].head->nextAdj = node;    }  }//有向网..void createDN(Graph * g){g->kind = DN;printf("输入图的顶点树 和 边(弧)树\n");scanf("%d%d%*c",&g->vexNum,&g->arcNum);      //构造顶点集      printf("请输入顶点集\n");      for (int i = 0; i < g->vexNum; i++){          char name;scanf("%c",&name);g->list[i].vexName = name;g->list[i].head = getHeadNode();    }      //构造顶点关系      fflush(stdin);      printf("请输入顶点的关系\n");      for (int i = 0; i < g->arcNum; i++){          char vex1,vex2;int weight;scanf("%c%c%d%*c",&vex1,&vex2,&weight);  int location1 = vexLocation(*g,vex1);ArcNode * node = getArcNode(*g,vex2);node->weight = weight;node->nextAdj = g->list[location1].head->nextAdj;g->list[location1].head->nextAdj = node;    }  }//无向图void createUDG(Graph * g){g->kind = UDG;printf("输入图的顶点树 和 边(弧)树\n");scanf("%d%d%*c",&g->vexNum,&g->arcNum);      //构造顶点集      printf("请输入顶点集\n");      for (int i = 0; i < g->vexNum; i++){          char name;scanf("%c",&name);g->list[i].vexName = name;g->list[i].head = getHeadNode();    }      //构造顶点关系      fflush(stdin);      printf("请输入顶点的关系\n");      for (int i = 0; i < g->arcNum; i++){          char vex1,vex2;scanf("%c%c%*c",&vex1,&vex2);  int location1 = vexLocation(*g,vex1);ArcNode * node1 = getArcNode(*g,vex2);node1->nextAdj = g->list[location1].head->nextAdj;g->list[location1].head->nextAdj = node1;int location2 = vexLocation(*g,vex2);ArcNode * node2 = getArcNode(*g,vex1);node2->nextAdj = g->list[location2].head->nextAdj;g->list[location2].head->nextAdj = node2;    }  }//无向网void createUDN(Graph * g){g->kind = UDN;printf("输入图的顶点树 和 边(弧)树\n");scanf("%d%d%*c",&g->vexNum,&g->arcNum);      //构造顶点集      printf("请输入顶点集\n");      for (int i = 0; i < g->vexNum; i++){          char name;scanf("%c",&name);g->list[i].vexName = name;g->list[i].head = getHeadNode();    }      //构造顶点关系      fflush(stdin);      printf("请输入顶点的关系\n");      for (int i = 0; i < g->arcNum; i++){          char vex1,vex2;int weight;scanf("%c%c%d%*c",&vex1,&vex2,&weight);  int location1 = vexLocation(*g,vex1);ArcNode * node1 = getArcNode(*g,vex2);node1->weight = weight;node1->nextAdj = g->list[location1].head->nextAdj;g->list[location1].head->nextAdj = node1;int location2 = vexLocation(*g,vex2);ArcNode * node2 = getArcNode(*g,vex1);node2->weight = weight;node2->nextAdj = g->list[location2].head->nextAdj;g->list[location2].head->nextAdj = node2;    }  }void graphDestory(Graph * g){for (int i = 0; i < g->vexNum; i++){ArcNode * next = g->list[i].head;while (next != NULL){ArcNode * freeNode = next;next = next->nextAdj;free(freeNode);}g->list[i].head = NULL;g->list[i].vexName = ' ';}g->vexNum = g->arcNum = 0;}//vex1 和 vex2是否相邻..bool grphIsAdj(Graph g,char vex1,char vex2){int location = vexLocation(g,vex1);ArcNode * next = g.list[location].head->nextAdj;//第一个节点是头结点的后继while (next != NULL){if (g.list[next->adjVex].vexName == vex2){return true;}next = next->nextAdj;}return false;}//顶点vex的度.//有向 = 出度 + 入度//无向 = 出度int graphDegree(Graph g,char vex){int degree = 0;int location = vexLocation(g,vex);ArcNode * next = g.list[location].head->nextAdj;while (next != NULL){//出度degree ++;next = next->nextAdj;}if (g.kind == DG || g.kind == DN){//有向图还需要遍历图,寻找入度.for (int i = 0; i < g.vexNum; i++){ArcNode * next = g.list[i].head->nextAdj;while (next != NULL){if (next->adjVex == location){degree ++;}next = next->nextAdj;}}}return degree;}//vex 的第一个邻接点char firstAdj(Graph g,char vex){int location = vexLocation(g,vex);ArcNode * next = g.list[location].head->nextAdj;if (next != NULL){return g.list[next->adjVex].vexName;}return ' ';}//vex1 相对于 vex2 的下一个邻接点。。。char nextAdj(Graph g,char vex1,char vex2){int location = vexLocation(g,vex1);ArcNode * next = g.list[location].head->nextAdj;while (next != NULL){//查找到 vex2if (g.list[next->adjVex].vexName == vex2){break;}next = next->nextAdj;}if (next != NULL){ArcNode * nextNode = next->nextAdj;if (nextNode != NULL){return g.list[nextNode->adjVex].vexName;}}return ' ';}//插入顶点void insertVex(Graph * g,char vex){if (g->vexNum < MAX_VERTEX_NUM){g->list[g->vexNum].vexName = vex;g->list[g->vexNum].head = getHeadNode();g->vexNum++;}}//删除顶点void deleteVex(Graph * g,char vex){int location = vexLocation(*g,vex);//释放空间ArcNode * next = g->list[location].head->nextAdj;int delNum = 0;while (next != NULL){ArcNode * freeNode = next;next = next->nextAdj;free(freeNode);delNum++;}//vex下面的 顶点上移for (int i = location + 1; i < g->vexNum; i++){g->list[i-1] = g->list[i];}g->vexNum --;//删除与顶点vex 相关的边(弧)(以及更新 所有节点的 adjVex )要遍历图..for (int i = 0; i < g->vexNum; i++){ArcNode * next = g->list[i].head->nextAdj;ArcNode * pre = g->list[i].head;while (next != NULL){if (next->adjVex == location){ArcNode * freeNode = next;next = next->nextAdj;pre->nextAdj = next;free(freeNode);delNum++;}else {if (next->adjVex > location){//在顶点下面的节点位置要减1next->adjVex --;}pre = next;next = next->nextAdj;}}}g->arcNum -= delNum;//有向if (g->kind == UDG || g->kind == UDN){g->arcNum += delNum/2;}}//插入边(弧)void insertArc(Graph * g,char vex1,char vex2){int location1 = vexLocation(*g,vex1);ArcNode * node1 = getArcNode(*g,vex2);node1->nextAdj = g->list[location1].head->nextAdj;g->list[location1].head->nextAdj = node1;//无向图需要插入另外一边.if (g->kind == UDG || g->kind == UDN){int location2 = vexLocation(*g,vex2);ArcNode * node2 = getArcNode(*g,vex1);node2->nextAdj = g->list[location2].head->nextAdj;g->list[location2].head->nextAdj = node2;}g->arcNum ++;}//删除边(弧)void deleteArc(Graph * g,char vex1,char vex2){g->arcNum--;int location1 = vexLocation(*g,vex1);int location2 = vexLocation(*g,vex2);ArcNode * next = g->list[location1].head->nextAdj;ArcNode * pre = g->list[location1].head;while (next != NULL){if (next->adjVex == location2){pre->nextAdj = next->nextAdj;free(next);break;}pre = next;next = next->nextAdj;}if (g->kind == UDG || g->kind == UDN ){//无向图还需要删除 另外一边next = g->list[location2].head->nextAdj;pre = g->list[location2].head;while (next != NULL){if (next->adjVex == location1){pre->nextAdj = next->nextAdj;free(next);break;}pre = next;next = next->nextAdj;}}}void printGrahp(Graph g){for (int i = 0; i < g.vexNum; i++){printf("%c的邻接点有:",g.list[i].vexName);ArcNode * next = g.list[i].head->nextAdj;while (next != NULL){printf("%c",g.list[next->adjVex].vexName);next = next->nextAdj;}printf("\n");}}int _tmain(int argc, _TCHAR* argv[]){Graph g;graphCreate(&g);printGrahp(g);printf("图的顶点数:%d,边(弧)树为:%d\n",g.vexNum,g.arcNum);char first = firstAdj(g,'a');char next = nextAdj(g,'a','c');char * isAdj = grphIsAdj(g,'c','d')? "相邻" : "不相邻";int degree = graphDegree(g,'d');printf("a的第一个邻接点是%c,a的c邻接点的下一个邻接点是:%c\n",first,next);printf("c 和 d %s,d的度为:%d\n",isAdj,degree);insertVex(&g,'e');printf("插入e顶点之后图结构如下:\n");printGrahp(g);insertArc(&g,'a','e');printf("插入(a,e)边(弧)之后图结构如下:\n");printGrahp(g);deleteArc(&g,'d','c');printf("删除(d,c)边(弧)之后图结构如下:\n");printGrahp(g);deleteVex(&g,'a');printf("删除顶点a之后图结构如下:\n");printGrahp(g);printf("图的顶点数:%d,边(弧)树为:%d\n",g.vexNum,g.arcNum);//及时销毁内存是个好习惯graphDestory(&g);return 0;}
运行截图:

最后 图的 顶点树为 4, 边(弧) 数 为 1

0 0
原创粉丝点击