最近看了很多介绍图算法的文章,发现网上可以搜到的资料比较少,所以打算在这写一个介绍图算法的系列文章,一方面是帮助自己整理,另一方面也给大家分享下这方面的知识。
1.1图的定义:
图(graph)由顶点(vertex)和边(edge)的集合组成,每一条边就是一个点对(v,w)。
图的种类:地图,电路图,调度图,事物,网络,程序结构
图的属性:有V个顶点的图最多有V*(V-1)/2条边
1.2图的ADT:
1 struct Edge{ 2 int v,w; 3 Edge(int a=-1,int b=-1):v(a),w(b){} 4 }; 5 6 class Graph 7 { 8 private: 9 // 10 public: 11 Graph(int,bool); 12 ~Graph(); 13 int V() const;//顶点 14 int E() const;//边 15 bool directed() const;//是否有方向 16 int insert(Edge); 17 int remove(Edge); 18 bool edge(int,int); 19 //迭代器 20 class adjIterator 21 { 22 public: 23 adjIterator(const Graph&,int); 24 int begin(); 25 int next(); 26 bool end(); 27 }; 28 };
图的构造函数将图中可能的最大顶点数作为一个参数。
1.3邻接矩阵:
邻接矩阵是一个元素为bool值的V*V矩阵,若图中存在一条连接顶点V和W的边,折矩阵adj[v][w]=1,否则为0。占用的空间为V*V,当图是稠密时,邻接矩阵是比较合适的表达方法。
//graph ADT实现(邻接矩阵)
1 class DenseGraph 2 { 3 public: 4 DenseGraph(int v,bool digraph=false):adj(v),Vcnt(v),Ecnt(0),diGraph(digraph){ 5 for(int i=0;i<v;++i) 6 adj[i].assign(v,false);//将邻接矩阵初始化为false 7 } 8 int V() const{ 9 return Vcnt; 10 } 11 int E() const{ 12 return Ecnt; 13 } 14 bool directed() const{ 15 return diGraph; 16 } 17 void insert(Edge e) 18 { 19 int v=e.v,w=e.w; 20 if(adj[v][w]==false) Ecnt++; 21 adj[v][w]=true; 22 if(!digraph) adj[w][v]=true; 23 } 24 void remove(Edge e) 25 { 26 27 int v=e.v,w=e.w; 28 if(adj[v][w]==true) Ecnt--; 29 adj[v][w]=false; 30 if(!digraph) adj[w][v]=false; 31 } 32 bool edge(int v,int w) const 33 { 34 return adj[v][w]; 35 } 36 class adjIterator; 37 friend class adjIterator; 38 39 private: 40 int Vcnt;//顶点数 41 int Ecnt;//边数 42 bool diGraph;//是否有向图 43 vector< vector<bool> > adj;//邻接矩阵 44 }; 45 46 //邻接矩阵的迭代器,返回顶点vertex的下一个相邻的顶点 47 class DenseGraph::adjIterator 48 { 49 public: 50 adjIterator(const DenseGraph &g,int vertex): 51 G(g),v(vertex),i(-1){} 52 int begin() 53 { 54 i=-1; 55 return next(); 56 } 57 int next() 58 { 59 for(i++;i<G.V();++i) 60 if(G.adj[v][i]==true) return i; 61 return -1; 62 } 63 bool end() 64 { 65 return i>=G.V(); 66 } 67 private: 68 const DenseGraph &G; 69 int i,v; 70 };
1.4邻接表的表示
对于非稠密的图,使用邻接矩阵有点浪费存储空间,可以使用邻接表,我们维护一个链表向量,给定一个顶点时,可以立即访问其链表,占用的空间为O(V+E)。
//程序:Graph的邻接表实现
1 class SparseGraph() 2 { 3 public: 4 SparseGraph(int v,bool digraph=false): 5 Vcnt(v),Ecnt(0),diGraph(digraph){ 6 adj.assign(v,0); 7 } 8 SparseGraph(const SparseGraph& G); 9 ~SparseGraph(); 10 int V() const{ 11 return Vcnt; 12 } 13 int E() const{ 14 return Ecnt; 15 } 16 bool directed(){ 17 return digraph; 18 } 19 //往图中插入一条边 20 void insert(Edge e){ 21 int v=e.v,w=e.w; 22 adj[v]=new node(w,adj[v]); 23 if(!diGraph) adj[w]=new node(v,adj[w]); 24 Ecnt++; 25 } 26 void remove(Edge e); 27 bool Edge(int v,int w) const; 28 class adjIterator;//邻接表的迭代器 29 friend class adjIterator;//把迭代器类设置为友元类 30 private: 31 int Vcnt,Ecnt; 32 bool diGraph; 33 struct node 34 { 35 int v; 36 node* next; 37 node(int x,node* t):v(x),next(t){} 38 }; 39 typedef node* link; 40 vector<link> adj;//邻接表 41 }; 42 43 //邻接表迭代器的实现 44 class SparseGraph::adjIterator 45 { 46 public: 47 adjIterator(const SparseGraph& g,int v): 48 G(g),v(v),curLink(0){} 49 adjIterator(const adjIterator&); 50 ~adjIterator(); 51 int begin(){ 52 curLink=adj[v]; 53 return curLink?curLink-v:-1; 54 55 } 56 int next(){ 57 if(curLink) curLink=curLink->next; 58 return curLink?curLink->v:-1; 59 } 60 bool end(){ 61 return curLink==0; 62 } 63 private: 64 const SparseGraph& G; 65 int v;//顶点编号 66 link curLink; 67 };
1.5简单路径搜索
给定两个顶点,图中是否存在一条连接起来的简单路径呢?
比如给定顶点V和W,对于和V相邻的每个顶点t,是否存在从t到W的简单路径,然后递归调用,我们使用一个顶点访问向量visited来对顶点标记防止重复访问。
//程序:简单路径搜索
1 template <class Graph> class SearchPath 2 { 3 4 public: 5 SearchPath(const Graph& g,int v,int w): 6 G(g),visited(g.V(),false){ 7 found=search(v,w); 8 } 9 bool existed() const 10 { 11 return found; 12 } 13 private: 14 const Graph& G; 15 vector<bool> visited; 16 bool found; 17 bool search(int v,int w) 18 { 19 if(v=w) return true; 20 visited[v]=true;
21 typename Graph::adjIterator ite(G,v); 22 for(int t=ite.begin();!ite.end();t=ite.next()) 23 if(!visited[t]) 24 if(search(t,w)) return true; 25 return false; 26 } 27 };
参考资料:维基百科http://en.wikipedia.org/wiki/Category:Graph_algorithms
Graph algorithm:http://www-users.cs.umn.edu/~karypis/parbook/Lectures/AG/chap10_slides.pdf
原文地址:http://lippiouyangonline.info/algorithm/2013/12/29/graph.html