图的存储和遍历

图的存储

图的存储一般有两种方式:邻接矩阵和邻接表

邻接矩阵

设图G(V,E)的顶点标号为0,1,……n-1,则令二维数组G[n][n]的两维分别表示图的顶点标号。
即如果G[i][j]等于1,指顶点i和顶点j之间有边,如果G[i][j]等于0,指顶点i和顶点j之间没有边,
如果为有权图,则令G[i][j]存放边权。
但如果题目中顶点数过大,可能会造成内存超限。

邻接表

图的常用储存结构之一,由表头结点和表结点两部分组成,其中表头结点存储图的各顶点,
表结点用单向链表存储表头结点所对应顶点的相邻顶点(也就是表示了图的边)。
在有向图里表示表头结点指向其它结点(a->b),无向图则表示与表头结点相邻的所有结点(a—b)

//表头结点(表示图的顶点)  
struct vnode{  
       char data;             //顶点数据,这里用字符表示  
       struct arcnode * firstarc;   //指针指向第一条边   
};  
//表结点(表示图的边)  
struct arcnode{  
       int wt;           //权重  
       int adjvex;     //顶点下标  
       struct arcnode *nextarc;   //指针指向下一条边  
};  
typedef struct arcnode * Arc;  
//图  
struct mgraph{  
       struct vnode vexs[100];  
       int vexsnum,arcnum;     //顶点数,边数  
} *g;  
typedef struct mgraph* Graph;  

图的遍历

用DFS遍历图

沿着一条路径直到无法继续前进,才退回到路径上离当前顶点最近的还存在未访问分支顶点的岔道口,并前往访问那些未访问的分支节点,直至遍历完成
* 连通分量:在无向图中,如果两个顶点可以互相到达,则称这两个顶点连通,如果图G(V,E)的任意两个顶点都连通,则称图G为连通图,
否则,称图G为非连通图,且称其中的极大连通子图为连通分量。
* 强连通分量:在有向图中,如果两个顶点可以各自通过一条有向路径到达另一个顶点,则称这两个顶点强联通。如果一个图的任意两个顶点都强联通,
则称这个图为强连通图;否则这个图为非强连通图,且称其中的极大连通子图为强联通分量。

伪代码
DFS(u){
    vis[u]=true;
    for(从u出发能到达的所有顶点v)
        if(vis[v]==false)
        DFS(v);
}
DFSTrave(G){
    for(G的所有顶点u)
        if(vis[u]==false)
        DFS(u);
}
邻接矩阵实现
const int maxv=1000;
const int inf=1000000;
int n,G[maxv][maxv];
bool vis[maxv]={false};
void dfs(int u,int depth){
    vis[u]=true;
    for(int v=0;v<n;v++){
        if(vis[v]==false&&G[u][v]!=inf){
            dfs(v,depth+1);
        }
    }
}
void dfstrave(){
    for(int u=0;u<n;u++){
        if(vis[u]==false){
            dfs(u,1);
        }
    }
}
邻接表实现
vector<int> Adj[maxv];
int n;
bool vis[maxv] = {false};
void dfs(int u,int depth){
    vis[u] =true;
    for(int i=0;i<Adj[u].size();i++){
        int v=Adj[u][i];
        if(vis[v]==false){
            dfs(v,depth+1);
        }
    }
}
void dfstrave(){
    for(int u=0;u<n;u++){
        if(vis[u]==false){
            dfs(u,1);
        }
    }
}

用BFS遍历图

类似树的遍历,遍历图需要使用一个队列,通过反复取出队首顶点,将该顶点可到达的未曾加入过队列的顶点全部入队,直到队列为空时遍历结束。

伪代码
BFS(u){
    queue q;
    inq[u]=true;
    while(q非空){
        取出q的队首元素加以访问;
        for(从u出发能到达的所有顶点v)
        if(inq[v]==false){
            将v入队;
            inq[v]=true;
        }
    }
}
BFSTrave(G){
    for(G的所有顶点u)
        if(inq[u]==false)
    {
        BFS(u);
    }
}
邻接矩阵实现
int n,G[maxv][maxv];
bool inq[maxv]={false};
void BFS(int u){
    queue<int> q;
    q.push(u);
    inq[u]=true;
    while(!q.empty()){
        int u.q.front();
        q.pop();
        for(int v=0;v<n;v++){
            if(inq[v]==false&&G[u][v]!=inf){
                q.push(v);
                inq[v]=true;
            }
        }
    }
}
void BFSTrave(){
    for(int u=0;u<n;u++){
        if(inq[u]==false){
            BFS(q);
        }
    }
}
邻接表实现
vector<int> Adj[maxv];
int n;
bool inq[maxv]={false};
void BFS(int u){
    queue<int> q;
    q.push(u);
    inq[u]=true;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<Adj[u].size();i++){
            int v=Adj[u][i];
            if(inq[v]==false){
                q.push(v);
                inq[v]=true;
            }
        }
    }
}
void BFSTrave(){
    for(int u=0;u<n;u++){
        if(inq[u]==false){
            BFS(q);
        }
    }
}

例子:

#include<bits/stdc++.h>  
using namespace std;  
typedef struct  
{  
    int edges[100][100];///邻接矩阵  
    int n;  
    int e;  
}graph;  
bool vis[100];///访问数组  
void creategraph(graph &G)  
{  
    int i,j;  
    int s,t;  
    int v;  
    for(i=0;i<G.n;i++)  
    {  
        for(j=0;j<G.n;j++)  
        {  
            G.edges[i][j]=0;///邻接表初始化  
        }  
        vis[i]=false;///访问数组初始化  
    }  
    for(i=0;i<G.e;i++)  
    {  
        cin>>s>>t>>v;///读入顶点数边数和权值  
        G.edges[s][t]=v;///赋值  
    }  
}  
void dfs(graph G,int v)  
{  
    int i;  
    printf("%d ",v);  
    vis[v]=true;///访问第v个定点,并将访问数组置为true  
    for(i=0;i<G.n;i++)  
    {  
        if(G.edges[v][i]!=0&&vis[i]==false)  
        {  
            dfs(G,i);///如果i未被访问递归调用dfs  
        }  
    }  
}  
void bfs(graph G,int v)  
{  
    queue<int>Q;  
    printf("%d ",v);  
    vis[v]=true;  
    Q.push(v);  
    while(!Q.empty())  
    {  
        int i,j;  
        i=Q.front();///取队头元素  
        Q.pop();///队头元素出队  
        for(j=0;j<G.n;j++)  
        {///检查所有邻接点  
            if(G.edges[i][j]!=0&&vis[j]==false)  
            {  
                printf("%d ",j);  
                vis[j]=true;  
                Q.push(j);  
            }  
        }  
    }  
}  
int main()  
{  
    int n,e;  
    while(1)  
    {  
        puts("输入图的顶点数和边数:");  
        cin>>n>>e;  
        graph G;  
        G.n=n;  
        G.e=e;  
        creategraph(G);  
        puts("输出深度优先遍历序列:");  
        dfs(G,0);  
        puts("\n");  
        creategraph(G);  
        puts("输出广度优先遍历序列:");  
        bfs(G,0);  
        puts("\n");  
    }  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值