[数据结构】图的深度优先遍历和广度优先遍历

一、前言

图的深度优先遍历和广度优先遍历与二叉树的遍历类似,都是采用递归算法,对每一个点进行访问。

二、深度优先遍历(DFS)

1.算法实现

采用邻接矩阵表示图的深度优先搜索遍历

typedef int Boolean;              //Boolean是布尔类型,其值是TRUE或FALSE
Boolean visited[MAX];             //访问标志的数组
//邻接矩阵的深度优先递归算法
void DFS(AMGraph G,int v){        //图G为邻接矩阵类型
    cout<<v;visited[v] = true;    //访问第V个顶点
    for(w = 0; w < G.vexnum; w++)}//依次检查邻接矩阵v所在的行
        if((G.arcs[v][w]!=0)&&(!visited[w]))
            DFS(G,w);
        }
        //w是v的邻接点,如果w未访问,则递归调用DFS
}
//邻接矩阵的深度遍历操作
void DFSTraverse(MGraph G)
{
    int i;
    for(i = 0; i<G.vexnum;i++)
        visited[i] = FALSE;       //初始所有顶点状态都是未访问
    for(i= 0;i<G.vexnum;i++)      
        if(!visited[i])           //对未访问过的顶点调用DFS,若是连通图,只会执行一次
            DFS(G,i);
}

采用邻接表表示图的深度优先搜索遍历

//邻接表的深度优先递归算法
void DFS(ALGraph G,int v){
    ArcNode *p;
    cout<<v;visited[v] = true;    //访问第v个顶点
    p = G.adjlist[v].firstarc;    //p指向v的第一个邻接点
    while(p!=NULL){
        w = p->adjvex;            //邻接点序号为w
        if(!visited[w])
            DFS(G,w);             //若w为未访问过的顶点,则递归调用DFS
        p = p->nextarc;           //p指向v的下一个邻接点
    }
}
//邻接表的深度遍历操作
void DFSTraverse(ALGraph G)
{
    int i;
    for(i = 0;i<G.vexnum;i++)
        visited[i] = FALSE;       //初始所有顶点状态都是未访问
    for(i= 0;i<G.vexnum;i++)
        if(!visited[i])           //对未访问过的顶点调用DFS,若是连通图,只会执行一次
            DFS(G,i);
}

2.算法效率分析

  • 邻接矩阵来表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度为O(n^2)
  • 邻接表来表示图,虽然有2e个边结点,但只需要扫描e个结点即可完成遍历,加上访问n个头结点的时间,时间复杂度为O(n+e)。

结论

  • 稠密图适于在邻接矩阵上进行深度遍历
  • 稀疏图适于在邻接表上进行深度遍历

三、广度优先遍历(BFS)

1.算法实现

采用邻接矩阵表示图的广度优先搜索遍历

//邻接矩阵的广度遍历算法
void BFS(Graph G,int v)
{
    int i,j;
    Queue Q;
    // 初始化访问标记数组
    for(i=0;i<G.vexnum;i++)
        visited[i]=FALSE;
    // 初始化队列
    InitQueue(Q);
    // 遍历所有顶点
    for(i=0;i<G.vexnum;i++)
    {
        // 如果顶点未被访问
        if(!visited[i])
        {
            // 标记顶点为已访问
            visited[i]=TRUE;
            // 打印顶点
            printf("%c",G.vexs[i]);
            // 将顶点入队
            EnQueue(Q,i);
            // 当队列不为空时
            while(!QueueEmpty(Q))
            {
                // 出队一个顶点
                DeQueue(Q,i);
                // 遍历该顶点的所有邻接顶点
                for(j=0;j<G.vexnum;j++)
                {
                    // 如果邻接顶点未被访问且存在边
                    if(G.arc[i][j]==1&&!visited[j])
                    {
                        // 标记邻接顶点为已访问
                        visited[j]=TRUE;
                        // 打印邻接顶点
                        printf("%c",G.vexs[j]);
                        // 将邻接顶点入队
                        EnQueue(Q,j);
                    }
                }
            }
        }
    }
}

采用邻接表表示图的深度优先搜索遍历

//采用邻接表表示图的广度遍历算法
void BFS(Graph G)
{
    int i;
    ArcNode *p;
    Queue Q;
    // 初始化访问标记数组
    for(i=0;i<G.vexnum;i++)
        visited[i]=FALSE;
    // 初始化队列
    InitQueue(Q);
    // 遍历所有顶点
    for(i=0;i<G.vexnum;i++)
    {
        // 如果顶点未被访问
        if(!visited[i])
        {
            // 标记顶点为已访问
            visited[i]=TRUE;
            // 打印顶点
            printf("%c",G.vexs[i]);
            // 将顶点入队
            EnQueue(Q,i);
            // 当队列不为空时
            while(!QueueEmpty(Q))
            {
                // 出队一个顶点
                DeQueue(Q,i);
                // 遍历该顶点的所有邻接顶点
                p=G.adjlist[i].firstarc;
                while(p!=NULL)
                {
                    // 如果邻接顶点未被访问且存在边
                    if(!visited[p->adjvex])
                    {
                        // 标记邻接顶点为已访问
                        visited[p->adjvex]=TRUE;
                        // 打印邻接顶点
                        printf("%c",G.vexs[p->adjvex]);
                        // 将邻接顶点入队
                        EnQueue(Q,p->adjvex);
                    }
                    p=p->nextarc;
                }
            }
        }
    }
}

2.算法效率分析

  • 邻接矩阵来表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度为O(n^2)
  • 邻接表来表示图,虽然有2e个边结点,但只需要扫描e个结点即可完成遍历,加上访问n个头结点的时间,时间复杂度为O(n+e)。

四、DFS和BFS算法效率比较

  • 空间复杂度相同,都是O(n)(借用了堆栈或队列);
  • 时间复杂度只与存储结构(邻接矩阵或邻接表)有关,而与搜索路径无关。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值