【2019暑假刷题笔记-图的存储和图的遍历】绪论(代码模板-总结自《算法笔记》)

一、图的存储

  1. 图有两种存储办法,分别是邻接矩阵(顶点数≤1000,0表示不连通,数字表示权重)和邻接表(用vector数组实现),具体实现如下:
    /*
    邻接矩阵,G[][]
    */
    
    G[2][3]=1;    //2和3连接(可以认为权重为1)
    G[4][5]=0;    //4和5不连接
    G[7][8]=6;    //7和8连接且权重为6    
    
    
    /*
    邻接表 vector<int> Adj[N];
    */
    
    Adj[1].push_back(3);    //1和3连接
    
    //邻接表加权重
    struct Node{
        int v;    //边的终点编号
        int w;    //边权
    };
    vector<Node> Adj[N];    //这样vector的邻接表的类型就是Node了
    
    Node temp;
    temp.v=3;
    temp.w=4;
    Adj[1].push_back(temp);
    
    //邻接表的另一种构造
    struct Node{
        int v,w;
        Node(int_v,int_w):v(_v),w(_w){};  //构造函数
    };
    
    Adj[1].push_back(Node(3,4));
  2. 以DFS法遍历图:

    /*
    伪码思想:不管是邻接表还是邻接矩阵都是采用这种办法的(注:连通图一次DFS解决)
    */
    DFS(u){    //访问定点u
        vis[u]=true;    //设置u被访问过了
        for(从u出发能到达的所有顶点v)    //枚举从u出发的所有顶点v
            if vis[v]==false    //如果v没有被访问过
                DFS(v);
    }
    
    DFSTrave(G){    //遍历G
        for(G的所有顶点u)    //对G的所有顶点u
            if vis[u]==false    //如果u未被访问
                DFS(u);    //访问u所在的连通块
    }
    /*
    邻接矩阵版DFS
    */
    
    //首先定义MAXV为最大顶点数、INF为一个很大的数字
    const int MAXV=1000;
    const int INF=1000000000;
    
    int n,G[MAXV][MAXV];    //n为顶点数,MAXV为最大顶点数
    bool vis[MAXV]={false};
    void DFS(int u,int depth){
        vis[u]=true;    //设置u已被访问
        //如果需要对u进行一些操作,可以在这里进行
        //下面对所有从u出发能到达的分支顶点进行枚举
        for(int v=0;v<n;v++){    //对每个顶点v
            if(vis[v]==false&&G[u][v]!=INF){    //如果v没有被访问且u可以达到v
                DFS(v,depth+1);    //访问v,深度加1
            }
        }
    }
    
    void DFSTrave(){    //遍历图G
        for(int u=0;u<n;u++){    //对每个顶点u
            if(vis[u]==false){    //若u没有被访问过
                DFS(n,1);    //访问u和u所在的连通块,1表示初试的第一层
            }
        }
    }
    
    /*
    邻接表版
    */
    const int MAXV=1000;
    vector<int> Adj[MAXV];    //图G的邻接表
    int n;    //n为顶点数,MAXV为最大顶点数
    bool vis[MAXV]={false};    //若顶点i已经被访问过了,则vis[i]==true.初值为false
    
    void DFS(int u,int depth){    //u为当前访问的顶点标号,depth为深度
        vis[u]=true;    //设置u已经被访问
        //如果需要对u进行一些操作,可以在此处进行
        for(int i=0;i<Adj[u].size();i++){    //对从u出发可以到达的所有顶点v
            int v=Adj[u][i];
            if(vis[v]==false){    //若v没有被访问过
                DFS(v,depth+1);    //访问v,深度+1
            }
        }
    }
    
    void DFSTrave(){    //遍历图G
        for(int u=0;u<n;u++){    //对每个顶点u
            if(vis[u]==false){    //若u未被访问
                DFS(u,1);    //访问u和u所在的联通块,1表示初始值为第一层
            }
        }
    }
    

     

  3. 以BFS法遍历图:

    /*
    伪码思想
    */
    BFS(u){    //遍历u所在的连通块
        queue q;
        将u入队;
        inq[u]=true;    //设置u已经被加入过队列
        while(q非空){    //只要队列非空
            取出q的队首元素u进行访问
            for(u出发可达的所有顶点v){    //枚举从u所能直接到达的顶点v
                if(inq[v]==false){    //若v未曾加入过队列
                    将v入队
                    inq[v]=true;    //设置v已被加入过队列
                }
            }
        }
    }
    
    BFSTrave(){    //遍历图G
        for(G的所有顶点u)    //枚举G的所有顶点u
            if(inq[u]==false){    //若u未曾加入过队列
                BFS(G);    //遍历u所在的连通块
            }
    }
    /*
    邻接矩阵版
    */
    int n,G[MAXV][MAXV];    //n为顶点数,MAXV为最大顶点数
    bool inq[MAXV]=false;    //若顶点i曾入过队列,则inq[i]==true。初值为false
    
    void BFS(int u){    //遍历u所在的连通块
        queue<int> q;    //定义队列q
        q.push(u);    //将初始点u入队
        inq[u]=true;    //设置u已经进入过队列
        while(!q.empty()){    //只要队列非空
            int u=q.front();    //取出队首元素
            q.pop();    //将队首元素出队
            for(int v=0;v<n;v++){    
                if(inq[v]==false&&G[u][v]!=INF){    //若u的邻接点v未曾加入过队列
                    q.push(v);    //将v入队
                    inq[v]=true;    //标记v为已经被加入过队列
                }
            }
        }
    }
    
    void BFSTrave(){    //遍历图G
        for(int u=0;u<n;u++){    //枚举所有顶点
            if(inq[u]==false){    //若u未曾加入过队列
                BFS(q);    //遍历u所在连通块
            }
        }
    }
    /*
    邻接表版
    */
    vector<int> Adj[MAXV];    //图G,Adj[u]存放从顶点u出发可以到达的所有顶点
    int n;    //n为顶点数,MAXV为最大顶点数
    bool inq[MAXV]={false};    //若顶点i曾入过队列,则inq[i]==true。初值为false
    
    void BFS(int u){    //遍历u所在的连通块
        queue<int> q;    //定义队列q
        q.push(u);    //将初始点u入队
        inq[u]=true;    //设置u已经进入过队列
        while(!q.empty()){    //只要队列非空
            int u=q.front();    //取出队首元素
            q.pop();    //将队首元素出队
            for(int i=0;i<Adj[u].size();i++){    //枚举从u出发能到达的所有顶点
                int v=Adj[u][i];    
                if(inq[v]==false){    //若u的邻接点v未曾加入过队列
                    q.push(v);    //将v入队
                    inq[v]=true;    //标记v为已经被加入过队列
                }
            }
        }
    }
    
    void BFSTrave(){    //遍历图G
        for(int u=0;u<n;u++){    //枚举所有顶点
            if(inq[u]==false){    //若u未曾加入过队列
                BFS(q);    //遍历u所在连通块
            }
        }
    }

     

    /*
    邻接表版,设置层号和编号
    */
    struct Node{
        int v;
        int layer;
    }
    
    vector<Node> Adj[MAXV];    //图G,Adj[u]存放从顶点u出发可以到达的所有顶点
    int n;    //n为顶点数,MAXV为最大顶点数
    bool inq[MAXV]={false};    //若顶点i曾入过队列,则inq[i]==true。初值为false
    
    void BFS(int s){    //遍历s为起编号
        queue<Node> q;    //定义队列q
        Node start;
        start.v=s;
        start.layer=0;
        q.push(start);    //将初始点start入队
        inq[start.v]=true;    //设置start已经进入过队列
        while(!q.empty()){    //只要队列非空
            Node topNode=q.front();    //取出队首元素
            q.pop();    //将队首元素出队
            int u=topNode.v;    //队首顶点的编号
            for(int i=0;i<Adj[u].size();i++){    //枚举从u出发能到达的所有顶点
                int next=Adj[u][i];    
                next.layer=topNode.layer+1;
                if(inq[next.v]==false){    //若next的邻接点v未曾加入过队列
                    q.push(next);    //将next入队
                    inq[next.v]=true;    //标记next为已经被加入过队列
                }
            }
        }
    }
    
    void BFSTrave(){    //遍历图G
        for(int u=0;u<n;u++){    //枚举所有顶点
            if(inq[u]==false){    //若u未曾加入过队列
                BFS(q);    //遍历u所在连通块
            }
        }
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_之桐_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值