zoukankan      html  css  js  c++  java
  • 图的基本概念,图的遍历、拯救007

    图(graph):
    表示“多对多”的关系
    六度空间理论(Six Degrees Separation)
    包含:
    1.一组顶点:通常用V(Vertex)表示顶点集合
    2.一组边:通常用E(edge)表示边的集合
    边是顶点对:(v, w) 属于E, v , w 属于V
    有向边<v, w>表示v 指向w的边(单行线)
    不考虑重边和自回路

    抽象数据类型定义:
    1.类型名称:图
    2.数据对象集:G(V, E)由一个非空的有限顶点集合v 和一个有限边集合Ezucheng
    2.操作集:

    常见术语:
    有向图:边是有方向的,可能是单向或双向
    无向图:边没有方向
    带权重的图叫“网络”

    怎么在程序中表示一个图:
    1.邻接矩阵G[N][N] --- N个顶点从0到N-1编号
    1 若<Vi, Vj>是G中的边
    G[i][j] = 0 否则

    对角元都是0 因为不允许自回路
    所有点关于对角线对称(实际上我们把一条边存了两次)
    问题:对于无向图的存储,怎样可以省一半空间?
    用一个长度N(N+1)/2的一维数组A来存储这些元素Gij在A中的下标是:
    (i*(i + 1) / 2 + j)
    对于网络,只要把G[i][j]的值定义为边<Vi, Vj>的权重即可
    若Vi和Vj之间没有边,则暂用0表示

    用邻接矩阵表示一个图的好处:
    1.直观、简单、好理解
    2.方便检查任意一对顶点间是否存在边
    3.方便找任一顶点的“邻接点”(有边直接相连的顶点)
    4.方便计算任一顶点的度:(从该顶点发出的边的边数为“出度”, 指向该点的边的边数为“入度”
    无向图:对应行(或列)非0元素的个数(也就是所有边的条数)
    有向图:对应行非零元素的个数就是“出度”,对应列非零元素的个数就是“入度”

    缺点:
    1.浪费空间:存稀疏图的时候,点很多,但是边很少,有大量无效元素
    对稠密图(特别是完全图)还是很合算的
    2.浪费时间: 统计稀疏图中一共有多少条边

    用邻接表示一个图:
    G[n]为指针数组,对应矩阵每行一个链表,只存非零元素
    一定要够稀疏才划算
    好处:
    1.方便找任一顶点的所有“邻接点”
    2.节约稀疏图的空间(需要N个头指针, + 2E个结点(每个结点至少2个域)
    3.方便计算任一顶点的度?
    对于无向图:是的
    对于有向图:只能计算“出度”, 需要构造“逆邻接表”(存指向自己的边,邻接矩阵的一列)
    方便计算“入度”
    不方便检查任意一对顶点间是否存在边

    5.2 图的遍历
    1.深度优先搜索(Depth Firsh Search, DFS)
    伪代码:(走一步,看一步,走不通后返回到上一个能走通的结点)

    类似于树的先序遍历:

    void DFS(Vertex V)
    {
        visited[V] = true;
        for(V  的每个邻接点 w)
            if(!visited[w])
                DFS(w);
    }

    若有N个顶点,E条边,时间复杂度是
    用邻接表存储图:有O(N+E)
    用邻接矩阵存储图:有O(N^2)


    2.广度优先搜索(Breadth First Search, BFs)(感觉上应该和邻接表存储搭配更好,但是感觉邻接矩阵也应该合格搭配更好)
    (个人感觉用这种遍历方式更好一些)
    相当于树的层序遍历(计划性非常强,出队一个,访问一圈,访问的同时入队)

     1 void BFS(Vertex V)
     2 {
     3     visited[V] = true;
     4     EnQueue(V, Q);
     5     while(!IsEmpty(Q))
     6     {
     7         V = DeQueue(Q);
     8         for(V 的每个邻接点 w)
     9             if(!visited[w])
    10             {
    11                 vitsit[w] = true;
    12                 EnQueue(w, Q);
    13             }
    14     }
    15 }

    若有N个顶点,E条边,时间复杂度是
    用邻接表存储图:有O(N + E)
    用邻接矩阵存储图: 有O(N^2)

    每调用一次DFS(V)或BFS(V),就把V所在的强连通分量遍历了一遍。

    图不连通怎么办(可能有一些孤立的点,他们和其他的结点都不连通)
    连通:如果从v 到w存在一条(无向)路径,则称v和w是连通的
    路径:v到w的路径是一系列顶点的集合,其中任意一对相邻的顶点间都有图中的边。
    路径的长度:是路径中的边数(如果带权,则是所有边的权重和)。如果v和w之间的所有顶点都不同,则称简单路径
    回路:起点等于终点的路径
    连通图:图中任意两顶点都连通

    对于不连通图:
    连通分量:无向图的极大连通子图
    极大顶点数:再加一个顶点就不连通了
    极大边数:包含子图中所有顶点相连的所有边

    强连通:有向图中顶点v和w之间存在双向路劲,则称v和w是强连通的
    强连通图:有向图中任意两顶点均强连通
    弱连通图:不符合强连通图的条件,但是若是将边的方向都去掉,如果是连通的,则称为弱连通图
    强连通分量:有向图的极大强连通子图

    图不连通时的遍历方法:

    1 伪代码:
    2 void ListComponents(Graph G)
    3 {
    4     for(each V in G)
    5         if(!visited[V])
    6             DFS(V);         //or BFS(V)
    7 }

    拯救007

    void ListComponents(Graph G)
    {
        for(each V in G)
            if(!visited[v])
                DFS(V);
    }
     1 void Save007 (Graph G)
     2 {
     3     for(each V in G)
     4         if(!visited[V] && FirstJump(V)
     5         {
     6             answer = DFS(V);
     7             if(answer == Yes)
     8                 break;
     9         }
    10     if(answer == Yes) output("Yes");
    11     else output("No"):
    12 }
     1 DFS 算法

    2 int DFS(Vertex V) 3 { 4 visited[V] = true; 5 if(IsSave(v)) answer = Yes; 6 else { 7 for(each w in G) 8 if(!visited[w] && Jump(v, w) 9 { 10 answer = DFS[w]; 11 if(answer == yes) 12 break; 13 } 14 } 15 return answer; 16 }
  • 相关阅读:
    2017.5.8下午
    2017.5.8上午
    2017.5.5下午
    2017.5.5上午
    2017.5.4下午
    WPF DataGrid LoadingRow style 滚动失效
    centos nginx 环境变量
    Kettle-03-定时转换
    Kettle-02-转换
    Kettle-01-安装(CentOS 7 离线)
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/9535276.html
Copyright © 2011-2022 走看看