1 / 128

图 图的存储表示 图的遍历 无向图的连通分量和生成树 最短路径 拓扑排序

第八章 图. 图 图的存储表示 图的遍历 无向图的连通分量和生成树 最短路径 拓扑排序. 一、图. 图 应用最广泛的数据结构。 不同于树的另一种 非线性结构 每个顶点可以与 多个 其他顶点相关联,各顶 点之间的关系是 任意 的。 简单图 没有自身环,两点间至多一条边. v 1. v 3. v 2. v 1. v 5. v 3. v 4. v 4. v 2. 无向图. 有向图. 图的基本概念. G=<V, E>

majed
Télécharger la présentation

图 图的存储表示 图的遍历 无向图的连通分量和生成树 最短路径 拓扑排序

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. 第八章 图 • 图 • 图的存储表示 • 图的遍历 • 无向图的连通分量和生成树 • 最短路径 • 拓扑排序

  2. 一、图 图 应用最广泛的数据结构。 不同于树的另一种非线性结构 每个顶点可以与多个其他顶点相关联,各顶 点之间的关系是任意的。 简单图 没有自身环,两点间至多一条边 v1 v3 v2 v1 v5 v3 v4 v4 v2 无向图 有向图

  3. 图的基本概念 G=<V, E> V={v1,v2,······,vn} 顶点集 E={ (vi, vj) | vi,vj∈V, vi≠vj} 边集 无向图 E={<vi, vj>|vi ,vj∈V}有向边集 有向图 有向边 <vi, vj> , vi起点弧尾, vj终点弧头 TD(vi):一个顶点的度,以vi为端点的边的数目。 OD(vi): 出度, 以vi为起点的边的数目。 ID(vi): 入度,以vi为终点的边的数目。 TD(vi)= OD(vi)+ ID(vi) OD=ID, TD=2|E|, |E| =1/2*TD TD OD ID 为整个图的总度,出度,入度数。

  4. 图的基本概念 路径 vi······vj, 以vi为起点vj为终点的顶点序列。 路径的长 路径上边的数目, 简单路径 顶点都不重复的路径, 回路 环 首尾相接的路径, 简单回路 除第一个和最后一个顶点以外都不重 复的路径, vivj连通 有路径 vi······vj, 连通图 任意两点都连通, 有向图 vivj强连通 vivj连通 vjvi也连通, 强连通图 任意两点都强连通。

  5. v2 v2 v1 v1 v4 v4 v3 v3 v5 v5 弱连通 强连通

  6. 强连通分量:彼此强连通的顶点的子集 B A ABC D EFG H I D C F E H G I

  7. 完全图 任意两点间都有边相关联的图。 无向完全图 共有边 1/2(n*(n-1)) 条, 有向完全图 共有边 n(n-1) 条。 稀疏图 |E|<nlog n 稠密图 |E|<nlog n 带权边 具有边长的边 有权图 图的所有边都是带权边。 网络 有权图

  8. 子图 G=(V, E), G’=(V’, E’) 如果 V’ V, E’ E , 就称 G’是G的子图。 ∩ ∩ 连通分量 一个图的极大连通子图。 强连通分量 一个图的极大强连通子图。 连通图的生成树 含有所有顶点的极小 连通图 n个顶点尽可能少边的连通图有n-1条边。 非连通图的生成森林:所有k个连通分支的生成树组成生成森林,共有n-k条边。

  9. 有向树 有向图连通图恰有一个顶点的入度为0, 其余顶点的入度都是1。 有向图的生成森林: 有向图的一个子图,含有所有顶点,构成若干互不相交的有向树,叫做生成森林。

  10. 二、图的存储结构 1.邻接矩阵 用矩阵表示图的顶点之间的相邻关系。 A[i,j]=1 (vi,vj)∈E =0 o.w. 0 1 1 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 0 0 0 1 1 0 0 v1 v2 v5 v3 v4

  11. 无向图的邻接矩阵是对称矩阵 0 1 1 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 0 0 0 1 1 0 0 TD(vi)=ΣA[i,j] i行数字的和等于vi的度 v1 v2 v5 v3 v4 n j=1 n n |E|=1/2 ΣΣA[i,j] 全部数字的和等于边数*2 i=1 j=1

  12. 有向图的邻接矩阵 A[i,j]=1 <vi,vj>∈E =0 o.w. 0 1 1 0 0 0 0 1 1 0 0 0 1 0 0 0 v3 v1 v4 v2 n OD(vi)=ΣA[i,j] i行数字的和等于vi的出度 j=1 n n |E|= ΣΣA[i,j] 全部数字的和等于边数 i=1 j=1

  13. 网的邻接矩阵 A[i,j]=wi (vi,vj)∈E 权为wi =∞ o.w. ∞ 5 ∞ 7 ∞ ∞ ∞ ∞ 4 ∞ ∞ ∞ 8 ∞ ∞ ∞ ∞ 9 ∞ ∞ 5 ∞ ∞ 6 ∞ ∞ ∞ 5 ∞ ∞ 3 ∞ ∞ ∞ 1 ∞ 5 v2 v1 4 8 v3 7 3 9 v6 6 1 5 v5 v4 5

  14. #ifndef GRAPH_CLASS#define GRAPH_CLASS#include <iostream.h>#include <fstream.h>#include "stack.h"#include "pqueue.h"#include "queue.h"#include "seqlist2.h"const intMaxGraphSize= 25;

  15. template <class T>class VertexIterator;template <class T> class Graph{ SeqList<T> vertexList; int edge [MaxGraphSize][MaxGraphSize]; int graphsize; int FindVertex(SeqList<T> &L, const T& vertex); int GetVertexPos(const T& vertex);

  16. public: Graph(void); int GraphEmpty(void) const; int GraphFull(void) const; int NumberOfVertices(void) const;int GetWeight(const T& vertex1, const T& vertex2); SeqList<T>& GetNeighbors(const T& vertex); int GetFirstNeighbor(const int v); int GetNextNeighbor(const int v1, const int v2);

  17. // graph modification methods void InsertVertex(const T& vertex);void InsertEdge(const T& vertex1, const T& vertex2, int weight); void DeleteVertex(const T& vertex);void DeleteEdge(const T& vertex1, const T& vertex2);

  18. // utility methods void ReadGraph(char *filename);SeqList<T>& DFS( ); SeqList<T>& DFS(const int v, int *visited); SeqList<T>& DepthFirstSearch(const T& beginVertex); SeqList<T>& BreadthFirstSearch(const T& beginVertex);int MinimumPath(const T& sVertex, const T& eVertex); // iterator used to scan the vertices friend class VertexIterator<T>;};

  19. 2. 邻接表 A B E C D 有向图可以有正反两种邻接表

  20. 邻接表表示的图的定义 Const int MaxGraphSize=25; template <class T> struct Edge //边的类 第一个顶点是隐式的 { int adjvex; //第二个顶点的编号 int weight; Edge<T> *next; //指向下一条边的指针 Edge( ):adjvex(0),weight(0),next(0){ } Edge(int v,int w):ajvex(v),weight(w),next(0){ } ~Edge( ){delete next;} };

  21. template<class T> struct VNode { Tvertex; Edge<T> *firstedge; } template<class T> class ALGraph { VNode vertexArry[MaxGraphSize] ; int vexNum, edgeNum; int FindVertex(SeqList<T> &L, const T& vertex); int GetVertexPos(const T& vertex);

  22. public: ALGraph(void); int GraphEmpty(void) const; int GraphFull(void) const; int NumberOfVertices(void) const;int GetWeight(const T& vertex1, const T& vertex2); SeqList<T>& GetNeighbors(const T& vertex); int GetFirstNeighbor(const int v); int GetNextNeighbor(const int v1, const int v2);

  23. // graph modification methods void InsertVertex(const T& vertex);void InsertEdge(const T& vertex1, const T& vertex2, int weight); void DeleteVertex(const T& vertex);void DeleteEdge(const T& vertex1, const T& vertex2);

  24. // utility methods void ReadGraph(char *filename);SeqList<T>& DFS( ); SeqList<T>& DFS(const int v, int *visited); SeqList<T>& DepthFirstSearch(const T& beginVertex); SeqList<T>& BreadthFirstSearch(const T& beginVertex);int MinimumPath(const T& sVertex, const T& eVertex);};

  25. //邻接矩阵表示的图的实现// constructor initialize entries in the adjacency matrix// to 0 and sets the graphsize to 0template <class T>Graph<T>::Graph(void){ for (int i = 0; i < MaxGraphSize; i++) for (int j = 0; j < MaxGraphSize; j++)edge[i][j] = 0;graphsize = 0;}

  26. 图的输入格式 0 1 1 0 0 1 0 0 1 1 1 0 0 0 1 0 1 0 0 0 0 1 1 0 0 A B 顶点数 顶点序列 边数 边序列 E C D 5 A B C D E 5 A B 1 A C 1 B D 1 B E 1 C E 1 Graph<char>G; G.ReadGraph(“graph.dat”);

  27. template <class T >void Graph< T >::ReadGraph(char *filename){ int i, nvertices, nedges;T S1, S2; int weight; ifstream f;f.open(filename, ios::in | ios::nocreate); if(!f){ cerr << "Cannot open " << filename << endl; exit(1); }f >> nvertices; for (i = 0; i < nvertices; i++) { f >> S1; InsertVertex(S1); }f >> nedges; for (i = 0; i < nedges; i++) { f >> S1; f >> S2; f >> weight; InsertEdge(S1,S2, weight); }f.close( ); }

  28. template <class T>int Graph<T>::NumberOfVertices(void) const{ return graphsize;} template <class T>int Graph<T>::GraphEmpty(void) const{ return graphsize == 0;}

  29. template <class T>int Graph<T>::GetVertexPos(const T& vertex){ SeqListIterator<T> liter(vertexList); int pos = 0;while(!liter.EndOfList( ) && liter.Data( ) != vertex) { pos++; liter.Next( ); } if (liter.EndOfList( )) { cerr << "GetVertex: the vertex is not in the graph." << endl; pos = -1; } return pos;}

  30. template <class T>int Graph<T>::GetWeight(const T& vertex1, const T& vertex2){ int pos1=GetVertexPos(vertex1), pos2=GetVertexPos(vertex2); if (pos1 == -1 || pos2 == -1) { cerr << "GetWeight: a vertex is not in the graph." << endl; return -1; } return edge[pos1][pos2];}

  31. template <class T>SeqList<T>& Graph<T>::GetNeighbors(const T& vertex){ SeqList<T> *L; SeqListIterator<T> viter(vertexList);L = new SeqList<T>; int pos = GetVertexPos(vertex); if (pos == -1) { cerr << "GetNeighbors: the vertex is not in the graph." << endl; return *L; } for (int i = 0; i < graphsize; i++) { if (edge[pos][i] > 0) L->Insert(viter.Data( ));viter.Next( ); } return *L;}

  32. template <class T>int Graph<T>::GetFirstNeighbor(const int v){if (v <0||v>graphsize) { cerr << “The vertex is not in the graph." << endl; return -1; } for(int i = 0; i < graphsize;i++) if(edge[v][i] >0) return i; return -1;}

  33. template <class T>int Graph<T>::GetNextNeighbor(const int v, const int v1){if (v <0||v>graphsize ||v1 <0||v1>graphsize) { cerr << “The vertex is not in the graph." << endl; return -1; } for(int i = v1+1; i < graphsize;i++)if(edge[v][i] >0) return i; return -1;}

  34. template <class T>void Graph<T>::InsertVertex(const T& vertex){ if (graphsize+1 > MaxGraphSize) { cerr << "Graph is full" << endl; exit (1); }vertexList.Insert(vertex);graphsize++;}

  35. 插入一条边 <vertex1,vertex2> 检查顶点vertex1,vertex2是否在图的 顶点表中,有一个不在图中就给出 错误信息返回。 在图中,则确定位置pos1,pos2, 设置边(pos1,pos2)的权值。

  36. template <class T>void Graph<T>::InsertEdge(const T& vertex1, const T& vertex2, int weight){ int pos1=GetVertexPos(vertex1), pos2=GetVertexPos(vertex2); if (pos1 == -1 || pos2 == -1) { cerr << "InsertEdge: a vertex is not in the graph." << endl; return; } edge[pos1][pos2] = weight;}

  37. 删除一个顶点 如果顶点不在表中给出错误信息返回。 如果在表中,确定位置pos 把邻接矩阵分成四块 pos 第I块中边不动 第II块中边列左移 第III块中边行上移 第IV块中边 列左移行上移 I II pos III IV

  38. template <class T>void Graph<T>::DeleteVertex(const T& vertex){ int pos = GetVertexPos(vertex); int row, col; if (pos == -1) { cerr << "DeleteVertex: a vertex is not in the graph." << endl; return; }vertexList.Delete(vertex); graphsize--; for (row = 0; row < pos; row++) for (col = pos + 1;col < graphsize;col++)edge[row][col-1] = edge[row][col]; for (row = pos + 1;row < graphsize;row++) for (col = pos + 1;col < graphsize;col++)edge[row-1][col-1] = edge[row][col]; for (row = pos + 1;row < graphsize;row++) for (col = 0; col < pos; col++)edge[row-1][col] = edge[row][col]; }

  39. template <class T>void Graph<T>::DeleteEdge(const T& vertex1, const T& vertex2){ int pos1=GetVertexPos(vertex1), pos2=GetVertexPos(vertex2); if (pos1 == -1 || pos2 == -1) { cerr << "DeleteEdge: a vertex is not in the graph." << endl; return; }edge[pos1][pos2] = 0;}

  40. template <class T>int Graph<T>::FindVertex(SeqList<T> &L, const T& vertex){ SeqListIterator<T> iter(L); int ret = 0; while(!iter.EndOfList( )) { if (iter.Data( ) == vertex) { ret = 1; break; }iter.Next( ); } return ret;}

  41. template <class T >class VertexIterator: public SeqListIterator< T >{ public:VertexIterator(Graph< T >& G);}; template <class T >VertexIterator<T>::VertexIterator(Graph<T>& G): SeqListIterator< T > (G.vertexList){}

  42. 深度优先搜索用递归算法 三、图的遍历 输出顶点并标记 循环:{ 递归计算第一个邻接点 (如 未标记) 下一个邻接点 } ABCDEIHF A F B C E H D I

  43. template <class T> SeqList<T>& Graph<T>::DFS( ) { int *visited=new int[graphsize]; for(int i=0;i<graphsize;i++) visited[i]=0; SeqList<T> *L=new SeqList<T>; *L=DFS(0,visited); delete[]visited; return *L; }

  44. template <class T> SeqList<T>& Graph<T>::DFS(const int v, int *visited) { SeqList<T>*L; Tvertex=vertexList.GetData(v); L=new SeqList<T>; visited[v]=1; L->Insert(vertex); int w=GetFirstNeighbor(v) while(w!=-1) {if(!visited[w])DFS(w,visited); w=GetNextNeihbor(v,w); } return *L; }

  45. //深度优先搜索2 不用递归用栈 L F B A S SeqList<T> L; //输出顶点 Stack<T> S; //存储待算顶点 HE B AF IE B A AFH F B D B AFHIE C E H C AFHIEDB D I AFHIEDBC

  46. //深度优先搜索2 不用递归用栈 template <class T>SeqList<T> & Graph<T>::DepthFirstSearch(const T& beginVertex){ Stack<T> S; SeqList<T> *L, adjL; SeqListIterator<T> iteradjL(adjL); Tvertex; L = new SeqList<T>; S.Push(beginVertex);

  47. while (!S.StackEmpty( )) {vertex = S.Pop( ); if (!FindVertex(*L,vertex)) { (*L).Insert(vertex); adjL = GetNeighbors(vertex);iteradjL.SetList(adjL);for(iteradjL.Reset( );!iteradjL.EndOfList( );iteradjL.Next( )) if (!FindVertex(*L,iteradjL.Data( ))) S.Push(iteradjL.Data( )); } } return *L; // return list}

  48. 广度优先搜索 用队列 ABFCHEDI Queue<T> Q; SeqList<T> L,adjL; L Q BF A AB FCH A ABF CHE F B HED ABFC C E H EDI ABFCH D I ABFCHEDI

  49. template <class T>SeqList< T >& Graph< T >::BreadthFirstSearch( const T & beginVertex){ Queue< T > Q; SeqList< T > *L, adjL; SeqListIterator< T > iteradjL(adjL);Tvertex; L = new SeqList< T >; Q.QInsert(beginVertex); // initialize the queue while (!Q.QEmpty( )) { vertex = Q.QDelete( ); if (!FindVertex(*L,vertex)) { (*L).Insert(vertex); adjL = GetNeighbors(vertex);iteradjL.SetList(adjL); for(iteradjL.Reset( );!iteradjL.EndOfList( );iteradjL.Next( )) { if (!FindVertex(*L,iteradjL.Data( )))Q.QInsert(iteradjL.Data( )); } } } return *L; }

  50. 四、无向图的连通分量和生成树 一个图中互相连通的点的极大子集叫连通分量。 从一点出发,深度优先或广度优先搜索到的子图就是连通分量。 从连通图的任意一点出发,深度优先搜索到的子图也就是图的生成树,也叫深度优先生成树;广度优先搜索到的生成树,也叫广度优先生成树; 非连通图遍历得到的是生成森林: 从一点出发深度优先搜索并标记,得到一棵树,再继续得到另一棵树,直到取遍所有顶点。

More Related