数据结构&图论:图

在这里对图的存储和遍历进行一个规范,为以后更复杂的数据结构学习打下基础

首先是邻接矩阵的形式,适合于存稠密图,如果是全连接图就再合适不过了

int a[maxn][maxn];

一个二维数组就可以搞定了,如果是bool值那么就是不带权值的

a[i][j]=w表示i->j这条边的权值为w,反之亦然

建图操作是很显然的

    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
        cin>>a[i][j];

接下来是一个DFS:

int vis[maxn];
void dfs(int dp,int x)
{
    cout<<x<<" ";
    for(int i=1;i<=n;i++)
    if(a[x][i]&&!vis[i])
    {
        vis[i]=1;
        dfs(dp+1,i);
    }
}

特别强调一下,我是先输出的结果,再进行的遍历,如果给定的图不是连通的,给了一片森林的话,一定要注意相应的细节

在这里的细节处理是给刚开始进入dfs的点打上标记,不要漏掉这里

然后是BFS,处理方法类似

int q[maxn];
void bfs(int x)
{
    int h=0,t=1;
    q[t]=x;
    while(h!=t)
    {
        h=h%maxn+1;
        cout<<q[h]<<" ";
        for(int i=1;i<=n;i++)
        if(a[q[h]][i]&&!vis[i])
        {
            vis[i]=1;
            t=t%maxn+1;
            q[t]=i;
        }
    }
}

接下来给出一个完整的例子:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 const int maxn=1005;
 5 int n;
 6 int a[maxn][maxn];
 7 int vis[maxn];
 8 void dfs(int dp,int x)
 9 {
10     cout<<x<<" ";
11     for(int i=1;i<=n;i++)
12     if(a[x][i]&&!vis[i])
13     {
14         vis[i]=1;
15         dfs(dp+1,i);
16     }
17 }
18 int q[maxn];
19 void bfs(int x)
20 {
21     int h=0,t=1;
22     q[t]=x;
23     while(h!=t)
24     {
25         h=h%maxn+1;
26         cout<<q[h]<<" ";
27         for(int i=1;i<=n;i++)
28         if(a[q[h]][i]&&!vis[i])
29         {
30             vis[i]=1;
31             t=t%maxn+1;
32             q[t]=i;
33         }
34     }
35 }
36 int main()
37 {
38     cin>>n;
39     for(int i=1;i<=n;i++)
40     for(int j=1;j<=n;j++)
41         cin>>a[i][j];
42     vis[1]=1;
43     dfs(1,1);
44     memset(vis,0,sizeof(vis));
45     cout<<endl;
46     vis[1]=1;
47     bfs(1);
48     return 0;
49 }
50 /*
51 0 1 1 0 0
52 1 0 0 1 1
53 1 0 0 0 0
54 0 1 0 0 0
55 0 1 0 0 0
56 */

然后就是邻接链表了,邻接链表的存储形式是用的最多的

struct Edge
{
    int t,w,next;
}e[maxm];
int g[maxn];
int tot=0;

dalao们喜欢用vector改成邻接数组,我不是dalao,所以就先这样了(*^▽

意义还是很明显的,t代表着这条边的to节点,如果需要记录起始节点,就要存一个u了

由于是链表,next是必不可少的,存的是与此边共起点的下一条边的编号

然后就是g数组了,存的是由下标节点所引出的第一条边的编号

建图采用的是链表的头插法

void addedge(int a,int b,int c)
{
    tot++;
    e[tot].t=b;
    e[tot].w=c;
    e[tot].next=g[a];
    g[a]=tot;
}

然后我们给出DFS和BFS的部分,这里原理是一模一样的,唯一需要注意的就是,数据结构变了,循环变量什么的要相应的调整

int vis[maxn];
void dfs(int dp,int x)
{
    cout<<x<<" ";
    for(int tmp=g[x];tmp;tmp=e[tmp].next)
    if(!vis[e[tmp].t])
    {
        vis[e[tmp].t]=1;
        dfs(dp+1,e[tmp].t);
    }
}
int q[maxn];
void bfs(int x)
{
    int h=0,t=1;
    q[t]=x;
    while(h!=t)
    {
        h=h%maxn+1;
        cout<<q[h]<<" ";
        for(int tmp=g[q[h]];tmp;tmp=e[tmp].next)
        if(!vis[e[tmp].t])
        {
            vis[e[tmp].t]=1;
            t=t%maxn+1;
            q[t]=e[tmp].t;
        }
    }
}

这里再补充一下刚才提到的森林的问题,由于我们是进入的时候就直接输出,所以第一个点一定要提前做好标记

由于是森林,每个点都要跑一边BFS或者DFS,那么在其他点的时候,进入之前判断vis,如果可行,打上vis之后再去跑,这样就没有任何问题了

最后给出邻接链表的完整实现:

 1 #include<iostream>
 2 #include<cstring> 
 3 using namespace std;
 4 const int maxn=1005;
 5 const int maxm=1005;
 6 int n,m;
 7 struct Edge
 8 {
 9     int t,w,next;
10 }e[maxm];
11 int g[maxn];
12 int tot=0;
13 void addedge(int a,int b,int c)
14 {
15     tot++;
16     e[tot].t=b;
17     e[tot].w=c;
18     e[tot].next=g[a];
19     g[a]=tot;
20 }
21 int vis[maxn];
22 void dfs(int dp,int x)
23 {
24     cout<<x<<" ";
25     for(int tmp=g[x];tmp;tmp=e[tmp].next)
26     if(!vis[e[tmp].t])
27     {
28         vis[e[tmp].t]=1;
29         dfs(dp+1,e[tmp].t);
30     }
31 }
32 int q[maxn];
33 void bfs(int x)
34 {
35     int h=0,t=1;
36     q[t]=x;
37     while(h!=t)
38     {
39         h=h%maxn+1;
40         cout<<q[h]<<" ";
41         for(int tmp=g[q[h]];tmp;tmp=e[tmp].next)
42         if(!vis[e[tmp].t])
43         {
44             vis[e[tmp].t]=1;
45             t=t%maxn+1;
46             q[t]=e[tmp].t;
47         }
48     }
49 }
50 int main()
51 {
52     cin>>n>>m;
53     for(int i=1;i<=m;i++)
54     {
55         int x,y,z;
56         cin>>x>>y>>z;
57         addedge(x,y,z);
58         addedge(y,x,z);
59     }
60     vis[1]=1;
61     dfs(1,1);
62     memset(vis,0,sizeof(vis));
63     cout<<endl;
64     vis[1]=1;
65     bfs(1);
66     return 0;
67 } 

邻接链表是我最喜欢的一种存图的形式了

最后就是我觉得比较奇葩的邻接数组,是为了三级项目刻意实现的,当然如果把数组换成vector会更自然一些

这里直接给出完整实现,和邻接链表大同小异,唯一的区别就是不用存next,直接枚举数组下标就可以了

 1 #include<iostream>
 2 #include<cstring> 
 3 using namespace std;
 4 const int maxn=1005;
 5 const int maxm=1005;
 6 int n,m;
 7 struct Edge
 8 {
 9     int t,w;
10 };
11 struct Graph
12 {
13     int cur;
14     Edge e[maxm];
15 }g[maxn];
16 int tot=0;
17 void addedge(int a,int b,int c)
18 {
19     tot++;
20     Edge tmp;
21     tmp.t=b;
22     tmp.w=c;
23     g[a].cur++;
24     int t=g[a].cur;
25     g[a].e[t]=tmp;
26 }
27 int vis[maxn];
28 void dfs(int dp,int x)
29 {
30     cout<<x<<" ";
31     for(int tmp=1;tmp<=g[x].cur;tmp++)
32     if(!vis[g[x].e[tmp].t])
33     {
34         vis[g[x].e[tmp].t]=1;
35         dfs(dp+1,g[x].e[tmp].t);
36     }
37 }
38 int q[maxn];
39 void bfs(int x)
40 {
41     int h=0,t=1;
42     q[t]=x;
43     while(h!=t)
44     {
45         h=h%maxn+1;
46         cout<<q[h]<<" ";
47         for(int tmp=1;tmp<=g[q[h]].cur;tmp++)
48         if(!vis[g[q[h]].e[tmp].t])
49         {
50             vis[g[q[h]].e[tmp].t]=1;
51             t=t%maxn+1;
52             q[t]=g[q[h]].e[tmp].t;
53         }
54     }
55 }
56 int main()
57 {
58     cin>>n>>m;
59     for(int i=1;i<=m;i++)
60     {
61         int x,y,z;
62         cin>>x>>y>>z;
63         addedge(x,y,z);
64         addedge(y,x,z);
65     }
66     vis[1]=1;
67     dfs(1,1);
68     memset(vis,0,sizeof(vis));
69     cout<<endl;
70     vis[1]=1;
71     bfs(1);
72     return 0;
73 } 

在每一种形式中,DFS和BFS先入栈和先入队的点是可能不一样的,但是结果都是正确的,在用之前一定要现在纸上画一画,避免输出顺序错误

转载于:https://www.cnblogs.com/aininot260/p/9323914.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值