• 图算法系列-图的简单实现


    最近看了很多介绍图算法的文章,发现网上可以搜到的资料比较少,所以打算在这写一个介绍图算法的系列文章,一方面是帮助自己整理,另一方面也给大家分享下这方面的知识。

    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

  • 相关阅读:
    java 实现Queue
    java 实现stack
    为什么现货白银/现货原油的报价每个交易所都不一样?
    现货交易入门之常用术语
    现货操盘手精髓语录
    现货电子交易中实物交割的概念和作用?
    关于ios对rtsp格式的流媒体支持的一些官方说明
    ProgressBar的Indeterminate属性
    安卓适配问题
    推送原理
  • 原文地址:https://www.cnblogs.com/lippi/p/3770668.html
Copyright © 2020-2023  润新知