图的表示--邻接表
来源:互联网 发布:mac 终端更改时间date 编辑:程序博客网 时间:2024/06/05 04:49
图的表示:
测试代码
主要有两种,邻接矩阵和邻接表,前者空间复杂度,O(V2),后者为O(V+E)。因此,除非非常稠密的图(边非常多),一般后者优越于前者。
上篇讨论了邻接矩阵的实现,本篇讨论邻接表的实现
GraphLink.h
- #include "Graph.h"
- #include <iostream>
- #include <queue>
- using std::cout;
- using std::cin;
- using std::endl;
- using std::queue;
- #define N 5 // 定义图的顶点数
- template <typename T> class LList;
- template <typename T> class GraphLink;
- struct ListUnit//邻接表表目中数据部分的结构定义
- {
- int weight; //边的权
- int vertex;//边的终点
- };
- template <typename T>
- class Link //链表元素
- {
- friend class GraphLink<T>;
- friend class LList<T>;
- T element;//表目的数据
- Link<T> *next; //表目指针,指向下一个表目
- Link(const T &e,Link<T> *n = nullptr)//构造函数
- {
- element = e;
- next = n;
- }
- Link(Link<T> *n = nullptr)//构造函数
- {
- next = n;
- }
- };
- template <typename T>
- class LList
- {
- private:
- void removeAll() //释放边表所有表目占据的空间
- {
- Link<T> *p = head->next;
- Link<T> *temp = nullptr;
- while(p != nullptr)
- {
- temp = p;
- p = p->next;
- delete temp;
- }
- }
- public:
- Link<T> *head;//head指针并不储存任何实际元素,其存在只是为了操作方便
- LList()//构造函数
- {
- head = new Link<T>();
- }
- ~LList()
- {
- removeAll();
- }
- };
- template <typename T>
- class GraphLink : public Graph
- {
- private:
- LList<ListUnit> *grapList; //graList是保存所有边表的数组
- public:
- GraphLink(int numVert) : Graph(numVert)
- {
- /*为graList数组申请空间,图有numVertex个顶点,则有numVertex个边表*/
- grapList = new LList<ListUnit>[numVert];
- }
- ~GraphLink()
- {
- delete []grapList;
- }
- virtual Edge firstEdge(int oneVertex)// 返回与顶点oneVertex相关联的第一条边
- {
- Edge edge;
- edge.from = oneVertex;//将顶点oneVertex作为边edge的始点
- edge.to = -1;
- /*graList[oneVertex].head保存的是顶点oneVertex的边表,
- head->next指向顶点oneVertex的第一条边(如果head->next
- 不为null)*/
- Link<ListUnit> *p = grapList[oneVertex].head->next;
- if(p != nullptr)
- {
- edge.to = p->element.vertex;
- edge.weight = p->element.weight;
- }
- return edge;
- }
- virtual Edge nextEdge(Edge preEdge)// 返回与边PreEdge有相同关联顶点的下一条边
- {
- Edge edge;
- edge.from = preEdge.from;
- edge.to = -1;
- Link<ListUnit> *p = grapList[preEdge.from].head->next;
- while(p != nullptr && p->element.vertex <= preEdge.to)// 确定边preEdge的位置
- {
- p = p->next;
- }
- if(p)// 边preEdge的下一条边存在
- {
- edge.to = p->element.vertex;
- edge.weight = p->element.weight;
- }
- return edge;
- }
- void setEdge(int from, int to, int weight)
- {
- Link<ListUnit> *p = grapList[from].head->next;
- Link<ListUnit> *pre = grapList[from].head;
- /*确定边(from,to)或<from,to>在边表中的位置,如果不存在,
- 则边(from,to)或<from,to>为新加的一条边*/
- while(p != nullptr && p->element.vertex < to)
- {
- pre = p;//记录下前一节点
- p = p->next;
- }
- if(p == nullptr)
- {
- Link<ListUnit> *temp = new Link<ListUnit>();
- temp->element.vertex = to;
- temp->element.weight = weight;
- pre->next = temp;
- numEdge++;
- indegree[to]++;
- return;
- }
- /*边(from,to)或<from,to>在边表中已存在,故只需要改变边的权值*/
- if(p->element.vertex == to)
- {
- p->element.weight = weight;
- return;
- }
- /*边(from,to)或<from,to>在边表中不存在,但在边表中其后存在其它边,则在边表中插入这条边*/
- if(p->element.vertex > to)
- {
- Link<ListUnit> *temp = new Link<ListUnit>();
- temp->element.vertex = to;
- temp->element.weight = weight;
- pre->next = temp;
- temp->next = p;
- numEdge++;
- indegree[to]++;
- return;
- }
- }
- void delEdge(int from, int to)
- {
- Link<ListUnit> *p = grapList[from].head->next;
- Link<ListUnit> *pre = grapList[from].head;
- /*确定边(from,to)或<from,to>在边表中的位置*/
- while(p != nullptr && p->element.vertex < to)
- {
- pre = p;//记录下前一节点
- p = p->next;
- }
- if(p == nullptr)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
- {
- return;
- }
- if(p->element.vertex > to)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
- {
- return;
- }
- if(p->element.vertex == to)
- {
- pre->next = p->next;
- delete p;
- numEdge--;
- indegree[to]--;
- return;
- }
- }
- // 函数功能:初始化图
- void initGraph(GraphLink &graphM,int (*A)[N],int n)
- {
- for (int i = 0; i < n; i ++)
- {
- for (int j = 0; j < N; j ++)
- {
- if (A[i][j] > 0)
- graphM.setEdge(i, j, A[i][j]);
- }
- }
- }
- void DFS( GraphLink &graph,int vertex)
- {
- graph.mark[vertex] = VISITED;
- visit(graph,vertex);
- for(Edge edge = graph.firstEdge(vertex); graph.isEdge(edge); edge = graph.nextEdge(edge))
- {
- if(graph.mark[graph.toVertex(edge)] == UNVISITED)
- {
- DFS(graph,graph.toVertex(edge));
- }
- }
- }
- void BFS( GraphLink &graph,int vertex)
- {
- queue<int> q; // 初始化广度优先周游要用到的队列
- q.push(vertex);
- while(!q.empty())
- {
- int v = q.front();
- q.pop();
- if(graph.mark[v] == UNVISITED )
- {
- visit(graph,v);
- graph.mark[v] = VISITED;//标记该顶点已访问
- // 该顶点邻接到的每一个未访问顶点都入队
- for(Edge edge = graph.firstEdge(v); graph.isEdge(edge); edge = graph.nextEdge(edge))
- {
- if(graph.mark[graph.toVertex(edge)] == UNVISITED)
- {
- q.push(graph.toVertex(edge));
- }
- }
- }
- }
- }
- void visit(const GraphLink &graph,int vertex)
- {
- cout << "V:" << vertex << "\t";
- }
- };
测试代码
- #include "GraphLink.h"
- #include <iostream>
- int A[N][N] = {
- // V0 V1 V2 V3 V4
- /*V0*/ 0, 0, 1, 1, 0,
- /*V1*/ 0, 0, 0, 1, 1,
- /*V2*/ 1, 0, 0, 1, 1,
- /*V3*/ 1, 1, 1, 0, 0,
- /*V4*/ 0, 1, 1, 0, 0,}; //图7.2中G1表示的无向图
- int main()
- {
- GraphLink<ListUnit> graphLink(N); // 建立图
- graphLink.initGraph(graphLink, A,N); // 初始化图
- cout << "DFS: ";
- graphLink.DFS(graphLink, 0);
- cout << endl;
- for (int i = 0; i < graphLink.verticesNum(); i++) //把Mark改回UNVISITED
- graphLink.mark[i] = UNVISITED;
- cout << "BFS: ";
- graphLink.BFS(graphLink, 0);
- cout << endl;
- system("pause");
- return 0;
- }
0 0
- 图的表示--邻接表
- 图的表示--邻接表
- 图的邻接表的表示方法
- 图的表示方式----邻接矩阵、邻接表
- 20.图的存储表示-----------------邻接表
- 数据结构:图的邻接表存储表示
- 图的存储表示--邻接表实现
- 图的基本概念;图的存储表示:邻接矩阵、邻接表
- ACM中关于图的邻接表的表示方法
- 图基本算法 ,图的表示方法 邻接矩阵 邻接表
- 图的邻接表存储结构表示法
- 21.图的存储表示 ------------------------邻接多重表
- 第七章(2).图的邻接表存储表示
- 无向图的表示:邻接矩阵和邻接表
- 图的邻接表 表示 DFS 和BFS C++实现
- 图的邻接表和邻接矩阵表示以及相关算法
- 图的表示(邻接矩阵和邻接表)
- C语言:实现图的邻接表存储表示
- SRM 551
- Tesseract学习(五)
- 使用 Spring Batch 和 SFTP 安全的发送数据
- 动态库和静态库
- lua 5.2 GC 源码分析 一
- 图的表示--邻接表
- windows系统下javac使用utf8编码
- Delphi中如何让编辑框只能输入数字或者只能输入一个浮点数值呢?
- 处理芯片cel格式数据的全自动R代码
- my_print_defaults: command not found
- Qt实现屏保功能,鼠标一定时间无响应程序进入待机状态
- Python自动化测试 (二) ConfigParser模块读写配置文件
- 黑马程序员------------------继承
- 图的表示--邻接矩阵