数据结构(六)——图之DFS和BFS遍历

本文介绍了如何使用邻接表构造无向图,并详细讲解了深度优先搜索(DFS)和广度优先搜索(BFS)遍历无向图的实现方法,包括递归遍历和队列遍历的过程。

代码中所用到的结构体

typedef struct arcnode
{
    int adjvex;//指向的下一个顶点
    struct arcnode *next;//指向这个点的另一条边
}Arcnode,*pArcnode;

typedef struct vnode
{
    pArcnode firstarc;//点所指向的第一条边
}Vnode,AdjList[30];

typedef struct graph
{
    int Vnum,Arcnum;//点的数目,边的数目
    AdjList vertice;
}Graph,*pGraph;

邻接表构造无向图

  • 首先输入图的总边数和总点数,通过输入边的起始点和终点,来确立点和点之间的关系
  • 注意点1:要申请两个新的指针p1,p2。p1从起始点指向终点,p2从终点指向起始点。以此通过两个有向的边构成一个无向的边。
  • 注意点2:注意每个点的头指针为空和不为空的情况是不一样的。
void CreateGraph(pGraph G)//构造无向图
{
    int i;
    int node1,node2;//暂时存储数据
    pArcnode p1,p2;//两个有向边组成一个无向边
    printf("请输入无向图的总点数:\n");
    scanf("%d",&G->Vnum);
    getchar();
    for(i=0;i<G->Vnum;i++)//给每个结点的第一个后继边初始化
    {
        G->vertice[i].firstarc=NULL;
    }
    printf("请输入无向图的总边数:\n");
    scanf("%d",&G->Arcnum);
    getchar();
    printf("请输入点和点之间的连接:(例:1 5)\n");
    for(i=0;i<G->Arcnum;i++)//循环输入边的信息
    {
        scanf("%d %d",&node1,&node2);
        getchar();
        p1=(pArcnode)malloc(sizeof(Arcnode));
        p2=(pArcnode)malloc(sizeof(Arcnode));
        p1->adjvex=node1;//构造连接,即两个有向边组成一个无向边
        p1->next=NULL;
        p2->adjvex=node2;
        p2->next=NULL;
        if(G->vertice[node1].firstarc==NULL&&G->vertice[node1].firstarc==NULL)//还未有邻接点时
        {
            G->vertice[node2].firstarc=p1;
            G->vertice[node1].firstarc=p2;
        }
        else//已有邻接点时
        {
            p1->next=G->vertice[node2].firstarc;
            G->vertice[node2].firstarc=p1;
            p2->next=G->vertice[node1].firstarc;
            G->vertice[node1].firstarc=p2;
        }
    }
}

DFS遍历无向图

  • 这里主要用的的参数有:pos,遍历到的点;G,要遍历的图;visited【】,标记已经遍历的点。
  • DFS是通过递归的方法遍历的
void DFSL(int pos,pGraph G,int visited[30])//从pos点开始,深度遍历无向图
{
    pArcnode p;
    printf("%d ",pos);//打印深度遍历的点
    visited[pos]=1;//标记为以访问过
    p=G->vertice[pos].firstarc;//将当前点的第一个指针赋值给p
    while(p!=NULL)//是否存在邻接点
    {
        if(visited[p->adjvex]==0)//判断该邻接点是否被遍历过
        {
            DFSL(p->adjvex,G,visited);
        }
        p=p->next;//后移一位,为之后是否有邻接点做准备
    }
}

BFS遍历无向图

  • 这里主要用的的参数有:pos,遍历到的点;G,要遍历的图;visited【】,标记已经遍历的点;queue【】,一个数组作为队列来遍历数组。
  • 通过将点pos存入队列,并将其标记,通过一个while循环对一个点的所连接的未被遍历的点进行遍历,遍历一个点所连接的点的方法为遍历该点所有的后继指针。
void BFSL(int pos,pGraph G,int visited[30])//从pos点开始进行广度优先遍历无向图
{
    int queue[G->Vnum];//队列辅助BFS遍历
    int head=0,tail=0;//队头、队尾指针
    Arcnode* p;
    queue[tail]=pos;
    visited[pos]=1;//标记遍历过
    tail++;
    while(head!=tail)
    {
        pos=queue[head];//出队操作
        head++;
        printf("%d ",pos);
        p=G->vertice[pos].firstarc;
        while(p!=NULL)
        {
            if(visited[p->adjvex]==0)//判断是否遍历过
            {
                queue[tail]=p->adjvex;//入队操作
                visited[p->adjvex]=1;//标记遍历过
                tail++;
            }
            p=p->next;
        }
    }
}

源代码

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef struct arcnode
{
    int adjvex;//指向的下一个顶点
    struct arcnode *next;//指向这个点的另一条边
}Arcnode,*pArcnode;

typedef struct vnode
{
    pArcnode firstarc;//点所指向的第一条边
}Vnode,AdjList[30];

typedef struct graph
{
    int Vnum,Arcnum;//点的数目,边的数目
    AdjList vertice;
}Graph,*pGraph;

void CreateGraph(pGraph G)//构造无向图
{
    int i;
    int node1,node2;//暂时存储数据
    pArcnode p1,p2;//两个有向边组成一个无向边
    printf("请输入无向图的总点数:\n");
    scanf("%d",&G->Vnum);
    getchar();
    for(i=0;i<G->Vnum;i++)//给每个结点的第一个后继边初始化
    {
        G->vertice[i].firstarc=NULL;
    }
    printf("请输入无向图的总边数:\n");
    scanf("%d",&G->Arcnum);
    getchar();
    printf("请输入点和点之间的连接:(例:1 5)\n");
    for(i=0;i<G->Arcnum;i++)//循环输入边的信息
    {
        scanf("%d %d",&node1,&node2);
        getchar();
        p1=(pArcnode)malloc(sizeof(Arcnode));
        p2=(pArcnode)malloc(sizeof(Arcnode));
        p1->adjvex=node1;//构造连接,即两个有向边组成一个无向边
        p1->next=NULL;
        p2->adjvex=node2;
        p2->next=NULL;
        if(G->vertice[node1].firstarc==NULL&&G->vertice[node1].firstarc==NULL)//还未有邻接点时
        {
            G->vertice[node2].firstarc=p1;
            G->vertice[node1].firstarc=p2;
        }
        else//已有邻接点时
        {
            p1->next=G->vertice[node2].firstarc;
            G->vertice[node2].firstarc=p1;
            p2->next=G->vertice[node1].firstarc;
            G->vertice[node1].firstarc=p2;
        }
    }
}
void DFSL(int pos,pGraph G,int visited[30])//从pos点开始,深度遍历无向图
{
    pArcnode p;
    printf("%d ",pos);//打印深度遍历的点
    visited[pos]=1;//标记为以访问过
    p=G->vertice[pos].firstarc;//将当前点的第一个指针赋值给p
    while(p!=NULL)//是否存在邻接点
    {
        if(visited[p->adjvex]==0)//判断该邻接点是否被遍历过
        {
            DFSL(p->adjvex,G,visited);
        }
        p=p->next;//后移一位,为之后是否有邻接点做准备
    }
}
void BFSL(int pos,pGraph G,int visited[30])//从pos点开始进行广度优先遍历无向图
{
    int queue[G->Vnum];//队列辅助BFS遍历
    int head=0,tail=0;//队头、队尾指针
    Arcnode* p;
    queue[tail]=pos;
    visited[pos]=1;//标记遍历过
    tail++;
    while(head!=tail)
    {
        pos=queue[head];//出队操作
        head++;
        printf("%d ",pos);
        p=G->vertice[pos].firstarc;
        while(p!=NULL)
        {
            if(visited[p->adjvex]==0)//判断是否遍历过
            {
                queue[tail]=p->adjvex;//入队操作
                visited[p->adjvex]=1;//标记遍历过
                tail++;
            }
            p=p->next;
        }
    }
}
int main()
{
    pGraph G;
    G=(pGraph)malloc(sizeof(Graph));
    int i;
    int visited[30]={0};
    int pos;
    CreateGraph(G);
    printf("请输入DFS和BFS遍历的起始点:\n");
    scanf("%d",&pos);
    getchar();
    if(pos<0||pos>G->Vnum)
    {
        assert(1);
    }
    printf("DFS遍历的结果:\n");
    DFSL(pos,G,visited);
    for(i=0;i<30;i++)
    {
        visited[i]=0;
    }
    printf("\n");
    printf("BFS遍历的结果:\n");
    BFSL(pos,G,visited);
    return 0;
}

测试数据:
9
12
0 1
0 5
1 6
1 2
6 8
6 7
2 7
2 3
7 8
3 7
3 4
4 5
1
结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值