1 / 60

第 12 章 图

第 12 章 图. 主要内容. 图的定义 图的遍历 拓扑排序 贪心算法 : 最短路径 最小生成树. 图 : 定义. 图 G 由集合 v 个 V 的中不同顶点对的集合 E 组成 ,V 的成员称为图 G 的顶点 这些顶点对称为 G 的边 . 如果 e=(v,w) 是顶点 v 和 w 组成的边 , 则说 v 和 w 依赖于 e, 而说 e 关联于 v 和 w. 如果顶点对是无序的 , 则称 G 为无向图 . 如果此顶点对是有序的 , 则称 G 为有向图 . 有向图这个术语在英文中表示经常简化为 digraph, 当不带限制条件时 , 图这个术语通常指无向图.

slade-dale
Download Presentation

第 12 章 图

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第12章 图

  2. 主要内容 • 图的定义 • 图的遍历 • 拓扑排序 • 贪心算法:最短路径 • 最小生成树

  3. 图:定义 • 图G由集合v个V的中不同顶点对的集合E组成,V的成员称为图G的顶点 • 这些顶点对称为G的边. • 如果e=(v,w) 是顶点v和w组成的边,则说v和w依赖于e,而说e关联于v和w. • 如果顶点对是无序的,则称G为无向图. • 如果此顶点对是有序的,则称G为有向图.有向图这个术语在英文中表示经常简化为digraph,当不带限制条件时,图这个术语通常指无向图.

  4. 图:定义 • 对无向图中的两个顶点,如果从一个顶点到另一个顶点存在一条边,则称这两个顶点是邻接的. • 路径是由不同顶点构造的一个序列,序列中的每个顶点都与下一个顶点邻接. • 环是一条至少包含3个顶点的路径,路径上最后一个顶点与第一个顶点邻接. • 如果从任一个顶点到任一个其他顶点之间存在一条路径,则称这个图是连通的.

  5. 图:定义 • 自由树定义为没有环的连通无向图. • 在有向图中,要求所有的边或环具有同样的方向,因此沿着一条边或环意味着总是沿着箭头指示的方向移动.这样的路径称为有向路径(环). • 如果从任一个顶点到另一个其他顶点之间存在一条有向路径,则称有向图是强连通的.如果不考虑边的方向且结果得到的无向图是连通的,则称有向图是弱连通的. • 顶点的度是连接到此顶点的边的个数, 也是其邻接顶点的个数.

  6. 图:定义

  7. 图:定义

  8. 图:定义

  9. 图:定义 • 有向图的集合表示 • 定义 :有向图G 由集合 V 和对所有v2V,V的子集A,其中V称为G的顶点集,Av称为与v邻接的顶点集. • 集合作为布尔数组: template <int max_set> struct Set { bool is_element[max_set]; };

  10. 图:定义 • 有向图的集合表示 • 作为数组的集合 template <int max_size> class Digraph { int count; //number of vertices, at most max_size Set<max_size> neighbors[max_size]; }; • 作为邻接表格 template <int max_size> class Digraph { int count; //number of vertices, at most max_size bool adjacency[max_size][max_size]; };

  11. 图:定义 • 基于表的实现 typedef int Vertex; template <int max_size> class Digraph { int count; //number of vertices, at most max_size List<Vertex> neighbors[max_size]; };

  12. 图:定义 • 基于表的实现 class Edge; //forward declaration(向前声明) class Vertex { Edge *first_edge; // start of the adjacency list Vertex *next_vertex; // next vertex on the linked list }; class Edge { Vertex *end_point; // vertex to which the edge points Edge *next_edge; // next edge on the adjacency list }; class Digraph { Vertex *first_vertex; // header for the list of vertices };

  13. 图:定义

  14. 图:定义

  15. 图:定义

  16. 图遍历 • 图的深度有序遍历大致类似于有序树的前序遍历.假设遍历刚刚访问过顶点v,设 w1;w2……wk 是与v邻接的顶点. 我们接下来将访问 w1 并使 w2……wk 等待. 在访问完 w1之后 , 我们在返回去遍历 w2; ……;wk 前,首先遍历所有与w1相邻的顶点. • 图的广度优先遍历大致类似于有序树的层次遍历.如果遍历刚刚访问过顶点v,则它接下来会访问所有与v邻接的顶点,并将与这些顶点邻接的顶点放入等待表中,在访问完所有与v邻接的顶点后再遍历它们.

  17. 图遍历

  18. 图遍历 • 深度优先算法 template <int max_size> void Digraph<max_size> :: depth_first(void (*visit)(Vertex &)) const /* Post: The function *visit has been performed at each vertex of the Digraph in depth-first order. Uses: Method traverse to produce the recursive depth-first order. */ { bool visited[max_size]; Vertex v; for (all v in G) visited[v] = false; for (all v in G) if (!visited[v]) traverse(v, visited, visit); }

  19. 图遍历 • 深度优先算法 • The recursion is performed in an auxiliary function traverse. template <int max_size> void Digraph<max_size> :: traverse(Vertex &v, bool visited[], void (*visit)(Vertex &)) const /* Pre: v is a vertex of the Digraph . Post: The depth-first traversal, using function*visit , has been completed for v and for all vertices that can be reached from v . Uses: traverse recursively. */

  20. 图遍历 • 深度优先算法 { Vertex w; visited[v] = true; (*visit)(v); for (all w adjacent to v) if (!visited[w]) traverse(w, visited, visit); }

  21. 图遍历 • 广度优先算法 template <int max_size> void Digraph<max_size> :: breadth_first(void (*visit)(Vertex &)) const /* Post: The function *visit has been performed at each vertex of the Digraph in breadth-first order. Uses: Methods of class Queue . */ { Queue q; bool visited[max_size]; Vertex v, w, x; for (all v in G) visited[v] = false; for (all v in G) if (!visited[v]) { q.append(v);

  22. 图遍历 • 广度优先算法 while (!q.empty( )){ q.retrieve(w); if (!visited[w]) { visited[w] = true; (*visit)(w); for (all x adjacent to w) q.append(x); } q.serve( ); } } }

  23. 拓扑排序 • 如果G是一个无有向环的有向图,则G的拓扑排序是G中所有顶点的一个顺序排列,使得对所有的顶点v,w 2 G,如果有一条从v到w的边,则v在顺序排列中先于w.

  24. 拓扑排序

  25. 拓扑排序

  26. 拓扑排序 typedef int Vertex; template <int graph_size> class Digraph { public: Digraph( ); void read( ); void write( ); // methods to do a topological sort void depth_sort(List<Vertex> &topological_order); void breadth_sort(List<Vertex> &topological_order); private: int count; List <Vertex> neighbors[graph_size]; void recursive_depth_sort(Vertex v, bool visited[], List<Vertex> &topological_order); };

  27. 拓扑排序 • 深度优先算法 template <int graph_size> void Digraph<graph_size> ::depth_sort(List<Vertex> &topological_order) /* Post: The vertices of the Digraph are placed into List topological_order with adepth-first traversal of those vertices that do not belong to a cycle. Uses: Methods of class List , and function recursive_depth_sort to perform depth-first traversal. */

  28. 拓扑排序 { bool visited[graph_size]; Vertex v; for (v = 0; v < count; v++) visited[v] = false; Topological_order.clear( ); for (v = 0; v < count; v++) if (!visited[v]) // Add v and its successors into topological order. recursive_depth_sort(v, visited, topological_order); }

  29. 拓扑排序 template <int graph_size> void Digraph<graph_size> :: recursive_depth_sort(Vertex v, bool *visited, List<Vertex> &topological_order) /* Pre: Vertex v of the Digraph does not belong to the partially completed List topological_order . Post: All the successors of v and finally v itself are added to topological order with a depth-first search. Uses: Methods of class List and the function recursive_depth_sort . */

  30. 拓扑排序 { visited[v] = true; int degree = neighbors[v].size( ); for (int i = 0; i < degree; i++) { Vertex w; //A (neighboring) successor of v neighbors[v].retrieve(i, w); if (!visited[w]) // Order the successors of w. recursive_depth_sort(w, visited, topological_order); } topological_order.insert(0, v); // Put v into topological_order . }

  31. 拓扑排序 • 广度优先算法 template <int graph_size> void Digraph<graph_size> :: breadth_sort(List<Vertex> &topological_order) /* Post: The vertices of the Digraph are arranged into the List topological_order which is found with a breadth-first traversal of those vertices that do not belong to a cycle. Uses: Methods of classes Queue and List . */

  32. 拓扑排序 { topological_order.clear( ); Vertex v, w; int predecessor_count[graph size]; for (v = 0; v < count; v++) predecessor_count[v] = 0; for (v = 0; v < count; v++) for (int i = 0; i < neighbors[v].size( ); i++) { neighbors[v].retrieve(i, w); // Loop over all edges v-w. predecessor_count[w]++; } Queue ready_to_process; for (v = 0; v < count; v++) if (predecessor_count[v] == 0) ready_to_process.append(v);

  33. 拓扑排序 while (!ready_to_process.empty( )) { ready_to_process.retrieve(v); topological_order.insert(topological_order.size( ), v); for (int j = 0; j < neighbors[v].size( ); j++) { neighbors[v].retrieve(j, w); // Traverse successors of v . predecessor_count[w]--; if (predecessor_count[w] == 0) ready_to_process.append(w); } ready_to_process.serve( ); } }

  34. 贪心算法: 最短路径 • 最短路径的问题 • 给定有向图G,它的每条边附有一个非负的权,找到一个从顶点v到另一个顶点w的路径,使得路径上的权的和尽可能的小.

  35. 贪心算法: 最短路径 • 方法 • 算法运行时将维持从原点出发且最短距离已知的顶点集合S.最初S中仅有一个源点,接下来每一步,都会从剩下的顶点中找到一个顶点,使得从源点出发到该点的路径最短,然后将它加到S中.这个问题要决定的是每一步将哪个顶点加到S中.我们认为S中的顶点都标上某种颜色,且认为组成从源点出发到这些顶点的最短路径上的边也已着色.

  36. 贪心算法: 最短路径 • 寻找最短路径 • 我们选择记录在表格distance中的具有最小距离的顶点v时运用了贪心准则.对这个顶点v,必须证明记录在diatance中的距离确实是从源点到v的最短路径的长度.假设从源点到v有一条更改的路径,这条路径先是从S出发到某个顶点x,然后继续到v.如果这条路径比到v的着色路径更短,则从源点到x的初始路径也更短,于是有 distance[x] < distance[v].也因此贪心策略将选择x而不是v作为下一个加入S的顶点.

  37. 贪心算法: 最短路径 • 当将c加到S时,我们认为v现在已被着色,同时从源点到v的最短路径也已着色.接下来必须对不在S中的每个顶点w检查通过v然后直接到w的一条路径是否比先前记录到w的距离更短,从而更新整个distance.

  38. 贪心算法: 最短路径 • 例子

  39. 贪心算法: 最短路径 • 例子

  40. 贪心算法: 最短路径 template <class Weight, int graph_size> class Digraph { public: // Add a constructor and methods for Digraph input and output. void set_distances(Vertex source, Weight distance[]) const; protected: int count; Weight adjacency[graph_size][graph_size]; };

  41. 贪心算法: 最短路径 template <class Weight, int graph size> void Digraph<Weight, graph_size> :: set_distances(Vertex source, Weight distance[]) const /* Post: The array distance gives the minimal path weight from vertex source to each vertex of the Digraph . */ { Vertex v, w; bool found[graph_size]; // Vertices found in S for (v = 0; v < count; v++) { found[v] = false; distance[v] = adjacency[source][v]; }

  42. 贪心算法: 最短路径 found[source] = true; // Initialize with vertex source alone in the set S. distance[source] = 0; for (int i = 0; i < count; i++) { // Add one vertex v to S on each pass. Weight min = infinity; for (w = 0; w < count; w++) if (!found[w]) if (distance[w] < min) { v = w; min = distance[w]; } found[v] = true; for (w = 0; w < count; w++) if (!found[w]) if (min C adjacency[v][w] < distance[w]) distance[w] = min + adjacency[v][w]; } }

  43. 最小生成树 • 问题 • 最短路径的算法的应用没有改变网络和图

  44. 最小生成树 • 问题 • 如果初始网络基于连通图G,则从特定源点出发的最短路径就将这个源点和图G中所有其他的顶点连接了起来.如果将计算过的最短路径合并到一起,我们得到一棵树,我们得到了一棵树,这棵树连接了G的所有顶点. • 定义:连通网络的最小生成树是其边的权值总和尽可能小的生成树.

  45. 最小生成树

  46. 最小生成树 • Prim 算法 • 我们选择一个称为源点的顶点开始,当我们用这个方法继续找出生成树时,我们保持了一个顶点集X,X中的顶点到源点的路径可以在我们正在建立的最小生成树中找到.我们需要跟踪边集Y,Y中的边连接了正在构造的树中的X的顶点.因此经过一定的时间,可以想象X中的顶点和Y中的边构成了一棵小树,它生长成最终的生成树. • 最初,源点是X中唯一的顶点,边集Y为空.在每一步,我们都将另一个顶点加入X;这个顶点的选择要回答X的一条边有尽可能小的权值,这条回到X的最小边要加入Y.

  47. 最小生成树 • Prim算法 • 当我们开始实现prim算法时,我们将维持一个属于X的顶点表,将它们作为布尔数组component中的元素.我们可以方便的像存储图的边那样去存储y的边,那个图将通过我们的程序生长成一棵输出树.

  48. 例子

  49. 例子

  50. 最小生成树 • Prim算法 的实现 template <class Weight, int graph_size> class Network: public Digraph<Weight, graph_size> { public: Network( ); void read( ); //overridden method to enter a Network void make_empty(int size = 0); void add_edge(Vertex v, Vertex w, Weight x); void minimal_spanning(Vertex source, Network<Weight, graph_size> &tree) const; };

More Related