Chapter12 Graphs Definitions Applications Properties

Slides:



Advertisements
Similar presentations
数据结构 杨鹏宇 QQ: 版权所有,转载或翻印必究
Advertisements

動畫與遊戲設計 Data structure and artificial intelligent
Chapter 10 Graphs.
Chapter 12 圖形結構 12.1 圖形的一些專有名詞 12.2 圖形資料結構表示法 12.3 圖形追蹤 12.4 擴展樹
第5章 回溯法 “通用的解题法” 欢迎辞.
第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例.
資料結構與C++程式設計進階 資料結構概論 講師:林業峻 CSIE, NTU 6/ 7, 2010.
第7章 图论基础与应用 PART A 《可视化计算》.
類別與物件 Class & Object.
Minimum Spanning Trees
Chapter 7 Search.
第八章 第一节 日本 邹旭丹 滨河中学初中部 湘教版地理初一年级.
Chap5 Graph.
7.5 擴張樹 (Spanning Tree) 一個無向相連圖 G 的子圖 G’ 如果可用最少的邊來連接G 的
Chapter 4 Spanning Trees
Chap5 Graph.
Chapter8 Binary and Other Trees
第8章 圖形結構(Graphs) 8-1 圖形的基本觀念 8-2 圖形的表示法 8-3 圖形的走訪 8-4 擴張樹
Chapter 6 Graph Chang Chi-Chung
第八章 图 图的基本概念 图的存储结构 图的遍历与连通性 最小生成树 最短路径 活动网络.
The Greedy Method.
演算法方式總覽 The Divide-and-Conquer Strategy (個各擊破)(binary Searching、Quick Sort…. ) The Greedy Method(貪婪演算法) (Prim MST、Kruskal MST、Djikstra's algorithm) Dynamic.
圖論 (Graph Theory) B 電機四 大鳥 B 電機四 酋長 B 電機四 炫大
第七章 搜索结构 静态搜索结构 二叉搜索树 AVL树.
Array & General List.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
哈夫曼编码.
Graph 2 Michael Tsai 2012/5/1 連載: 學生上課睡覺姿勢大全
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
程序设计期末复习 黎金宁
第三章 C++中的C 面向对象程序设计(C++).
Chapter 7 圖形與網路 資料結構導論 - C語言實作.
二叉树和其他树 (Binary and other trees)
Yuzhong Qu Nanjing University
Ch07 圖形與網路 淡江大學 周清江
Chapter4 Arrays and Matrices
第三章 链表 单链表 (Singly Linked List) 循环链表 (Circular List) 多项式及其相加
Chapter6 队列(Queues) The Abstract Data Type
Animation(動畫) 靜宜大學資工系 蔡奇偉 副教授
第9章 基本图算法 本章内容将包含基本的图形表示法,以及先深搜寻,先广搜寻,拓朴排序,Strongly Connected Components。
第三章 链表 单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵.
数据结构概论 第7章 图 董黎刚 浙江工商大学信电学院 2019年4月8日.
第5章 回溯法 欢迎辞.
圖論的介紹 第二組 徐榮德 鄭又齊 陳俊嘉.
第15讲 路与回路, 图的连通性 主要内容: 1.路与回路. 2.图的连通性..
Tournament (graph theory)
生成树.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
第8章 图 8.1 图的基本概念和基本操作 8.2 图的邻接矩阵存储结构 8.3 图的邻接表存储结构 8.4 图的其他存储结构
Course 8 回溯、分枝與限制 Backtracking, Branch-and-Bound
資料結構簡介 綠園.
鄧姚文 資料結構 第八章:圖(Graph) 鄧姚文
1. 志明打算就客戶服務開發一個語音互動(IVR)系統, 顧客可透過電話鍵盤與系統進行互動。
進階資料結構(2) Disjoint Sets
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
生成树 离散数学─树 南京大学计算机科学与技术系.
第2章 Java语言基础.
Advanced Competitive Programming
Advanced Competitive Programming
Advanced Competitive Programming
圖形結構 Graph Structure chapter 9 德明科技大學資訊科技系.
第7章 图.
Maximum Flow.
11506: Angry Programmer ★★★★☆ 題組:Contest Set Archive with Online Judge
Graph 1 Michael Tsai 2012/4/24 連載: 學生上課睡覺姿勢大全
第二章 Java基本语法 讲师:复凡.
JAVA 程式設計與資料結構 第二十一章 Graph.
Presentation transcript:

Chapter12 Graphs Definitions Applications Properties The ADTs Graph and Digraph Representation of Graphs and Digraphs Representation of Networks Class Definitions Graph Iterators Graph Search Methods 2/22/2019

本章重点 图的基本概念 图的搜索 2/22/2019

逻辑结构 线性结构 层次结构 网状结构 2/22/2019

12.1图的基本概念 简单地说,图(graph)是一个用线或边连接在一起的顶点或节点的集合。 图G=(V,E) 是一个V和E的有限集合,元素V称为顶点(vertice, 也叫作节点或点),元素E称为边(edge, 也叫作弧或连线),E中的每一条边连接V中两个不同的顶点。 可以用(i,j)来表示一条边,其中i 和j 是E所连接的两个顶点。 2/22/2019

例 2/22/2019

例 2/22/2019

有向边/无向边 带方向的边叫有向边(directed edge),而不带方向的边叫无向边(undirected edge)。 对无向边来说,(i, j) 和(j, i) 是一样的;而对有向边来说,它们是不同的。前者的方向是从i 到j,后者是从j 到i。 2/22/2019

关联/邻接 当且仅当(i, j) 是图中的边时,顶点i 和j 是邻接的(adjacent)。边(i, j) 关联(incident)于顶点i 和j。 2/22/2019

例-邻接,关联 2/22/2019

关联/邻接 在有向图中,有时候对邻接和关联的概念作更精确的定义非常有用。 有向边(i, j) 是关联至(incident to)顶点j 而关联于(incident from)顶点i。顶点i 邻接至(adjacent to)顶点j,顶点j邻接于(adjacent from)顶点i。 对于无向图来说,“至”和“于”的含义是相同的。 2/22/2019

无向图/有向图 如果图中所有的边都是无向边,那么该图叫作无向图(undirected graph)。 有向边也成为弧。 2/22/2019

观察 由定义知道,一个图中不可能包括同一条边的多个副本,因此,在无向图中的任意两个顶点之间,最多只能有一条边。在有向图中的任意两个顶点之间,最多只能有一条边从顶点i到顶点j或从j到i。 并且一个图中不可能包含自连边(self-edge),即(i,i)类型的边,自连边也叫作环(loop)。 2/22/2019

图的基本概念 通常把无向图简称为图,有向图仍称为有向图(digraph)。 在一些图和有向图的应用中,会为每条边赋予一个权或耗费,这种情况下,用术语加权有向图(weighted graph)和加权无向图(weighted digraph)来描述所得到的数据对象。 2/22/2019

网络 术语网络(network)是指一个加权有向图或加权无向图。 2/22/2019

7 2 5 B 10 9 60 40 1 12 80 8 A C 6 3 7 30 75 6 35 15 6 3 D E 4 7 45 16 2/22/2019

路径 当且仅当对于每一个j(1≤j≤k),边(ij,ij+1)都在E中时,顶点序列P=i1 , i2 ,…, ik 是图或有向图G= (V, E)中一条从i1 到ik 的路径。 2/22/2019

街道例 2/22/2019

例 在图12-2b的有向图中,5,2,1是从5到1的一条路径,在这个有向图中,从5到4之间没有路径。 2/22/2019

简单路径 简单路径是这样一条路径:除第一个和最后一个顶点(起点和终点)以外,路径中其他所有顶点均不同。 例:路径5,2,1是简单路径,而2,5,2,1则不是。 2/22/2019

环路(回路) 环路(cycle)的起始节点与结束节点是同一节点。 简单路径组成的回路称为简单回路。 2/22/2019

路径长度 对于图或有向图的每一条边,均可以给出一个长度。 路径的长度是路径上所有边的长度之和。对不带权的图,路径长度是指路径上边的数目;对带权的图,路径长度是指路径上各条边的权值之和。 从i 到j 的最短路径是相应网络中顶点i 到j 的最短路径。 2/22/2019

连通图 设G= (V,E)是一个无向图,当且仅当G中每一对顶点之间有一条路径时,可认为G是连通的(connected)。 2/22/2019

强连通图 在有向图中,若任意两个顶点间均有路径存在,则称其为强连通图,否则称为非强连通图。 2/22/2019

观察 假设G是连通的,G中的有些边可能不是必需的,因此即使将它从G中去掉,G仍然可以保持连通。 2/22/2019

子图 图H是图G的子图(subgraph)的充要条件是,H的顶点和边的集合是G的顶点和边的集合的子集。 2/22/2019

生成树 没有环路的无向连通图是一棵树。 一棵包含G中所有顶点并且是G的子图的树是G的生成树(spanning tree)。 2/22/2019

生成树 2/22/2019

生成树 一个n节点的连通图必须至少有?条边。 因此当通信网络的每条链路具有相同的建造费用时,在任意一棵生成树上建设所有的链路可以将网络建设费用减至最小,并且能保证每两个城市之间存在一条通信路径。 如果链路具有不同的耗费,那么需要在一棵最小耗费生成树(生成树的耗费是所有边的耗费之和)上建立链路。 2/22/2019

生成树 2/22/2019

例 会议,此次大会上的所有发言人都只会说英语,而参加会议的其他人说的语言是{L1,L2,…,Ln}之一。翻译小组能够将英语与其他语言互译。 2/22/2019

二分图 可以将顶点集合分成两个子集A和B,这样每条边在A中有一个端点,在B中有一个端点,具有这种特征的图叫作二分图(bipartite graph) 2/22/2019

覆盖 当且仅当B中的每个顶点至少与A中一个顶点相连时,A的一个子集A‘ 覆盖集合B(或简单地说,A’ 是一个覆盖)。 在二分图中寻找最小覆盖的问题为二分覆盖(bipartite-cover)问题。 2/22/2019

二分覆盖 二分覆盖问题是N P-复杂问题。 可以利用贪婪算法寻找一种快速启发式方法。 一种可能是分步建立覆盖A' ,每一步选择A中的一个顶点加入覆盖。顶点的选择利用贪婪准则:从A中选取能覆盖B中还未被覆盖的元素数目最多的顶点。 2/22/2019

顶点的度 设G是一个无向图,顶点i 的度(degree)di 是与顶点i 相连的边的个数。 d1,d2,d3,d4? 2/22/2019

12.3性质 特性1 设G= (V, E)是一个无向图,令|V| =n, |E|=e, di为顶点i的度,则 2/22/2019

完全图 一个具有n 个顶点, n(n-1)/2条边的图是一个完全图(complete graph)。 任意两个顶点均邻接。 2/22/2019

完全图 2/22/2019

入度和出度 设G是一个有向图,顶点i 的入度(in-degree)diin 是指关联至顶点i 的边的数量。顶点i 的出度(out-degree)diout 是指关联于该顶点的边的数量。 入度和出度在无向图中可以作为度的同义词。 2/22/2019

顶点的度 与顶点相关联的边的数目。 有向图顶点的度还有入度与出度之分:顶点的入度即以该顶点为终点的边的数目;顶点的出度即以该顶点为始点的边的数目。 2/22/2019

性质 特性2 设G= (V,E)是一个有向图,令|V| =n, |E|=e, 则 2/22/2019

完全有向图 一个n 顶点的完全有向图(complete digraph)包含n (n- 1 )条有向边 2/22/2019

完全有向图 2/22/2019

思考 设G是任意无向图,度数为奇数的顶点。有偶数个还是奇数个? 2/22/2019

强连通有向图 一个有向图是强连通( strongly connected)的充要条件是:对于每一对不同顶点i 和j,从i 到j 和从j 到i 都有一个有向路径。 1) 对于每一个n(n≥2),都存在一个包含n 条边的强连通有向图。 2) 每一个n(n≥2)顶点的强连通有向图至少包含n 条边。 2/22/2019

12.5无向图和有向图的描述 无向图和有向图最常用的描述方法都是基于邻接的方式: 邻接矩阵 邻接压缩表 邻接链表 2/22/2019

邻接矩阵 一个n顶点的图G= (V,E)的邻接矩阵(adjacency matrix)是一个n×n矩阵A,A中的每一个元素是0或1。假设V={1, 2, ..., n}。如果G是一个无向图,那么A中的元素定义如下: 2/22/2019

邻接矩阵 如果G是有向图,那么A中的元素定义如下: 2/22/2019

例 2/22/2019

例-邻接矩阵 2/22/2019

结论 2/22/2019

邻接矩阵->数组 使用映射A(i,j)=a[i][j]可以将n×n的邻接矩阵映射到一个(n+1)×(n+1)的整型数组a中。 如果sizeof(int)等于2个字节,映射的结果需要2(n+1)2字节的存储空间。 另一种方法是,采用n×n数组a[n][n]和映射A(i,j)=a[i-1][j-1]。这种映射需要2n2字节,比前一种减少了4n+2个字 2/22/2019

邻接矩阵->数组 对于无向图,邻接矩阵是对称的,因此只需要存储上三角(或下三角)的元素,所需空间仅为(n2-n)/2位。 2/22/2019

邻接矩阵-时间需求 使用邻接矩阵时,需要用Θ(n)时间来确定邻接至或邻接于一个给定节点的集合,或寻找关联的边数。另外,增加或删除一条边需要Θ(1)时间。 2/22/2019

邻接链表 在邻接链表(linked-edjacency-list)中,邻接表是作为链表保存的,可以用类Chain<int>来实现。 可使用一个Chain<int> 类型的头节点数组h 来跟踪这些邻接表。h[i].first 指向顶点i 的邻接表中的第一个节点。如果x 指向链表h[i] 中的一个节点,那么(i, x→data) 是图中的一条边。 2/22/2019

例 2/22/2019

例 2/22/2019

例 2/22/2019

邻接链表-时间需求 假设每个指针和整数均为2字节长,则一个n顶点图的邻接链表所需要的空间为2(n+m+1),其中对于无向图,m=2e;而对于有向图,m=e。 邻接链表便于进行边的插入和删除操作。确定邻接表中顶点的数目所需要的时间与表中顶点的数目成正比。 2/22/2019

网络描述 将图和有向图的描述进行简单扩充就可得到网络的描述 2/22/2019

网络-邻接矩阵描述 用一个矩阵C来描述耗费邻接矩阵(cost-adjacency-matrix)。 如果A(i,j)是1,那么C(i,j)是相应边的耗费(或权);如果A(i,j)是0,那么相应的边不存在,C(i,j)等于某些预置的值NoEdge。 选择NoEdge是为了便于区分边是否存在。一般来说,NoEdge的值被设为无穷大。 2/22/2019

12.7邻接矩阵类的设计 AdjacencyWDigraph AdjacencyWGraph AdjacencyDigraph AdjacencyGraph 2/22/2019

邻接链表类的设计 LinkedBase LinkedDigraph LinkedWDigraph LinkedGraph LinkedWGraph 2/22/2019

分析 加权有向图和无向图的链表节点中有一个权值域,而无权有向图和无向图中则没有。 2/22/2019

加权有向图的耗费邻接矩阵 template<class T> class AdjacencyWDigraph{ friend AdjacencyWGraph<T>; public: AdjacencyWDigraph(int Vertices=10,T noEdge=0); ~AdjacencyWDigraph(){Delete2DArray(a,n+1);} bool Exist(int i,int j)const; int Edges()const{return e;} int Vertices()const{return n;} AdjacencyWDigraph<T>& Add(int i,int j,constT& w); AdjacencyWDigraph<T>& Delete(int i,int j); int OutDegree(int i)const; int InDegree(int i)const; 2/22/2019

加权有向图的耗费邻接矩阵 private: T NoEdge;//用于没有边存在的情形 int n;//顶点数目 int e;//边数 T **a;//二维数组 }; 2/22/2019

Chain的描述 2/22/2019

增加删除方法 2/22/2019

邻接链表基类描述 2/22/2019

有向图的链表描述 2/22/2019

2/22/2019

12.8图的遍历 不论采用哪一种图类编写应用程序,都需要沿着矩阵的一行或多行向下移动,或者沿着一个或多个链表向下移动,实现这种移动的函数称为遍历器(iterator)。 邻接矩阵的遍历函数。 邻接链表的遍历函数。 2/22/2019

遍历函数 Begin(i) 对于邻接表,返回顶点i 所对应表中的第一个顶点;对于邻接矩阵,返回邻接于顶点i 的最小(即第一个)顶点。在两种情况中,如果没有邻接顶点,都将返回零值。 NextVertex(i) 返回顶点i 对应邻接表中的下一个顶点或返回邻接于顶点i的下一个最小顶点。同样,当没有下一个顶点时函数返回零。 InitializePos( ) 初始化用来跟踪每一个邻接表或(耗费)邻接矩阵每一行中当前位置的存储配置。 DeactivatePos( ) 取消InitializePos( )所产生的存储配置。 2/22/2019

邻接矩阵的遍历函数 作为AdjacencyWDigraph类的一个共享函数来加以实现。 私有成员int *pos 用来记录每一行中的位置。 2/22/2019

邻接矩阵的遍历函数 void InitializePos() {pos = new int [n+1];} void DeactivatePos() {delete [] pos;} template<class T> int AdjacencyWDigraph<T>::Begin(int i) { / /返回第一个与顶点i邻接的顶点 if (i < 1 || i > n) throw OutOfBounds(); // 查找第一个邻接顶点 for (int j = 1; j <= n; j++) if (a[i][j] != NoEdge) {// j 是第一个 pos[i] = j; return j;} pos[i] = n + 1; // 没有邻接顶点 return 0; } 2/22/2019

邻接矩阵的遍历函数 template<class T> int AdjacencyWDigraph<T>::NextVertex(int i) {// 返回下一个与顶点i邻接的顶点 if (i < 1 || i > n) throw OutOfBounds(); // 寻找下一个邻接顶点 for (int j = pos[i] + 1; j <= n; j++) if (a[i][j] != NoEdge) {// j 是下一个顶点 pos[i] = j; return j;} pos[i] = n + 1; // 不存在下一个顶点 return 0; } 2/22/2019

邻接链表的遍历函数 LinkedBase类: ChainIterator<T> *pos; void InitializePos() {pos = new ChainIterator<T> [n+1];} void DeactivatePos() {delete [] pos;} 2/22/2019

邻接链表的遍历函数 int LinkedDigraph::Begin(int i) {// 返回第一个与顶点i邻接的顶点 if (i < 1 || i > n) throw OutOfBounds(); int *x = pos[i].Initialize(h[i]); return (x) *x : 0; } 2/22/2019

邻接链表的遍历函数 int LinkedDigraph::NextVertex(int i) {// 返回下一个与顶点i邻接的顶点 if (i < 1 || i > n) throw OutOfBounds(); int *x = pos[i].Next(); return (x) *x : 0; } 2/22/2019

链接加权有向图的遍历函数 template<class T> int LinkedWDigraph<T>::Begin(int i) {// 返回第一个与顶点i邻接的顶点 if (i < 1 || i > n) throw OutOfBounds(); GraphNode<T> *x = pos[i].Initialize(h[i]); return (x) x->vertex : 0; } int LinkedWDigraph<T>::NextVertex(int i) {// 返回下一个与顶点i邻接的顶点 GraphNode<T> *x = pos[i].Next(); 2/22/2019

12.9抽象类Network class Network { public: virtual int Begin(int i) = 0; virtual int NextVertex(int i) = 0; virtual void InitializePos() = 0; virtual void DeactivatePos() = 0; } ; 2/22/2019

12.10图的操作 寻找路径,寻找生成树,判断无向图是否连通。 许多函数都要求从一个给定的顶点开始,访问能够到达的所有顶点。(当且仅当存在一条从v 到u 的路径时,顶点v 可到达顶点u。) 2/22/2019

图的搜索算法 搜索这些顶点的两种标准方法是 宽度优先搜索 深度优先搜索 2/22/2019

搜索 判断从顶点1出发可到达的所有顶点? 2/22/2019

宽度优先搜索 从一个顶点开始,识别所有可到达顶点的方法叫作宽度优先搜索(Breadth -FirstSearch, BFS)。 这种搜索可使用队列来实现。 2/22/2019

宽度优先搜索 2/22/2019

宽度优先搜索 //从顶点v 开始的宽度优先搜索 把顶点v标记为已到达顶点; 初始化队列Q,其中仅包含一个元素v; while (Q不空) { 令u 为邻接于w 的顶点; while (u) { if ( u 尚未被标记) { 把u 加入队列; 把u 标记为已到达顶点; } u = 邻接于w 的下一个顶点; } 2/22/2019

观察 BFS的执行方式与是否正在处理一个图、有向图、加权图或加权有向图无关,也与所使用的描述方法无关。 为了实现语句:u=邻接于w的下一个顶点; 必须知道当前正在使用的图类。 通过把BFS函数作为Network类的一个成员函数以及利用图遍历器从一个邻接顶点到达下一个顶点,可以避免为每种图类分别编写不同的代码。 2/22/2019

BFS的实现代码 void Network::BFS(int v,int reach[],int label) {//宽度优先搜索 //初始时对于所有顶点有reach[i]=0并且label≠0 LinkedQueue<int> Q; InitializePos();//初始化图遍历器数组 reach[v]=label; Q.Add(v); while(!Q.IsEmpty()){ int w; Q.Delete(w);//获取一个已标记的顶点 2/22/2019

BFS的实现代码 int u=Begin(w); while(u){//访问w的邻接顶点 if(!reach[u]){//一个未曾到达的顶点 Q.Add(u); reach[u]=label;}//标记已到达该顶点 u=NextVertex(w);//下一个与w邻接的顶点 } DeactivatePos();//释放遍历器数组 2/22/2019

深度优先搜索 深度优先搜索(Depth-First Search, DFS):从顶点v 出发,首先将v 标记为已到达顶点,然后选择一个与v 邻接的尚未到达的顶点u,如果这样的u 不存在,搜索中止。假设这样的u 存在,那么从u 又开始一个新的DFS。当从u 开始的搜索结束时,再选择另外一个与v 邻接的尚未到达的顶点,如果这样的顶点不存在,那么搜索终止。而如果存在这样的顶点,又从这个顶点开始DFS,如此循环下去。 2/22/2019

DFS的实现代码 voidNetwork::DFS(int v,int reach[],int label) {//深度优先搜索 InitializePos();//初始化图遍历器数组 dfs(v,reach,label);//执行dfs DeactivatePos();//释放图遍历器数组 } 2/22/2019

dfs的实现代码 voidNetwork::dfs(int v,int reach[],int label) {//实际执行深度优先搜索的代码 reach[v]=label; int u=Begin(v); while(u){//u邻接至v if(!reach[u]) dfs(u,reach,label); u=NextVertex(v);} } 2/22/2019

例 从顶点1开始的深度优先搜索? 2/22/2019

应用 寻找路径(Finding a Path ) 连通图及其构件(Connected Graphs and Components) 生成树(Spanning Trees) 2/22/2019

寻找路径 若从顶点v 开始搜索(宽度或深度优先)且到达顶点w 时终止搜索,则可以找到一条从顶点v 到达顶点w 的路径。 要实际构造这条路径,需要记住从一个顶点到下一个顶点的边。 2/22/2019

在图中寻找一个路径 bool Network::FindPath (int v, int w, int &length, int path[]) {// 寻找一条从v 到w的路径, 返回路径的长度,并将路径存入数组path[ 0 : l e n g t h ] / /如果不存在路径,则返回false / /路径中的第一个顶点总是v path[0] = v; length = 0; // 当前路径的长度 if (v == w) return true; / /为路径的递归搜索进行初始化 int n = Vertices( ) ; InitializePos(); // 遍历器 2/22/2019

在图中寻找一个路径 int *reach = new int [n+1]; for (int i = 1; i <= n; i++) reach[i] = 0; bool x = findPath(v, w, length, path, reach); DeactivatePos( ) ; delete [] reach; return x; } 2/22/2019

在图中寻找一个路径 bool Network::findPath(int v, int w, int &length, int path[], int reach[]) {// 实际搜索v到w的路径,其中v != w. // 按深度优先方式搜索一条到达w的路径 reach[v] = 1; int u = Begin(v); while (u) { if (!reach[u]) { length++; path[length] = u; // 将u 加入p a t h if (u == w) return true; if (findPath(u, w, length, path, reach)) return true; // 不存在从u 到w的路径 length--; //删除u } u = NextVertex(v) ; } return false; } 2/22/2019

连通图及其构件 通过从任意顶点开始执行D F S或B F S,并且检验所有顶点是否被标记为已到达顶点,可以判断一个无向图G是否连通。 2/22/2019

确定无向图是否连通 class Undirected : virtual public Network { public: bool Connected(); } ; 2/22/2019

确定无向图是否连通 bool Undirected::Connected() {// 当且仅当图是连通的,则返回true int n = Ve r t i c e s ( ) ; // 置所有顶点为未到达顶点 int *reach = new int [n+1]; for (int i = 1; i <= n; i++) reach[i] = 0; // 对从顶点1出发可到达的顶点进行标记 DFS(1, reach, 1); // 检查是否所有顶点都已经被标记 if (!reach[i]) return false; return true; } 2/22/2019

构件 从顶点i 可到达的顶点的集合C与连接C中顶点的边称为连通构件(connected component)。 在构件标识问题( component-labeling problem)中,对图中的顶点进行标识,当且仅当2个顶点属于同一构件时,分配给它们相同的标号。 2/22/2019

构件 可以通过反复调用D F S或B F S算法来标识构件。从每一个尚未标识的顶点开始进行搜索,并用新的标号标识新到达的顶点。 2/22/2019

构件标识 2/22/2019

生成树 在一个n 顶点的连通无向图中,如果从任一个顶点开始进行BFS,所有顶点都将被加上标记。 由于所得到的边的集合中包含一条从v 到图中其他每个顶点的路径,因此它构成了一个连通子图,该子图即为G的生成树。 2/22/2019

生成树 宽度优先生成树:按B F S所得到的生成树 深度优先生成树:按D F S所得到的生成树 2/22/2019

宽度优先生成树 2/22/2019

深度优先生成树 {(1,3),(3,5),(5,2),(5,8),(8,7),(7,4),(4,6)} 2/22/2019

第十二章 总结 图的基本概念 图的存储 图的遍历 路径、生成树 2/22/2019