图的遍历(BFS、DFS)

前文使用邻接矩阵法和邻接链表法实现了图结构(MatrixGraph ListGraph ),本节使用两种算法进行图的遍历

目录

1、定义与概括

2、广度优先搜索算法

3、深度优先搜索算法

4、小结 


1、定义与概括

图的遍历:从图中的某一顶点出发,沿着一些边访问图中的其它顶点,使得每个顶点最多被访问一次 

       注意:从某个顶点出发进行遍历,不一定能够访问到图中的所有顶点

图的遍历方式 

      -广度优先搜索(Breadth First Search) 

          ☛ 以二叉树层次遍历的思想对图进行遍历 

      -深度优先搜索(Depth First Search) 

          ☛ 以二叉树先序遍历的思想对图进行遍历 

2、广度优先搜索算法

广度优先(BFS)

      -按层次对图中的顶点进行访问

            

算法思路

            -原料: class LinkQueue<T>; 

             - 步骤 

                    1. 将起始顶点压入队列中 

                    2. 队头顶点v弹出,判断是否已经标记(标记:转2, 未标记:转3) 

                    3. 标记顶点 v ,并将顶点 v 的邻接顶点压入队列中 

                    4 判断队列是否为空(非空:转2, 空:结束)

广度优先算法示例 

                

             

编程实验 

广度优先算法  Graph::BFS

Graph.h

// V:与顶点相关联数据元素类型,E:与边相关联数据元素(权值)类型
template < typename V, typename E >
class Graph : public Object
{
protected:

    /* 将队列转换为数组 */
    template < typename T >
    DynamicArray<T>* toArray(LinkQueue<T>& queue)
    {
        DynamicArray<T>* ret = new DynamicArray<T>(queue.length());

        if( ret )
        {
            for(int i=0; i<ret->length(); i++, queue.remove())
            {
                ret->set(i, queue.front());
            }
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create ret object ...");
        }

        return ret;
    }

public:
    // ...

    SharedPointer< Array<int> > BFS(int i)
    {
        DynamicArray<int>* ret = NULL;

        if((0 <= i) && (i < vCount()))
        {
            LinkQueue<int> q;
            LinkQueue<int> r;
            DynamicArray<bool> visited(vCount());

            for(int k=0; k<visited.length(); k++)
            {
                visited[k] = false;
            }

            q.add(i);   // 往q队列加入初始顶点


            while(q.length() > 0)
            {
                int v = q.front();  // 将队列头部的顶点拿出来

                q.remove();

                if( !visited[v] )   // 没有被访问过
                {
                    SharedPointer< Array<int> > aj = getAdjacent(v);  // 获取v顶点邻接顶点放到数组里

                    for(int j=0; j<aj->length(); j++)
                    {
                        q.add((*aj)[j]); // 将邻接顶点放到q队列
                    }

                    r.add(v);   // 将v放到return队列

                    visited[v] = true; // 标记该顶点已被访问过
                }
            }

            ret = toArray(r);

        }
        else
        {
            THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ...");
        }

        return ret;
    }

};

main.cpp

#include <iostream>
#include "MatrixGraph.h"

using namespace std;
using namespace DTLib;

int main()
{
    MatrixGraph<9, char, int> g;

    const char* VD = "ABEDCGFHI";

    for(int i=0; i<9; i++)
    {
        g.setVertex(i, VD[i]);
    }

    g.setEdge(0, 1, 0);
    g.setEdge(1, 0, 0);   // 有向图表示无向图,权值0代表无权值

    g.setEdge(0, 3, 0);
    g.setEdge(3, 0, 0);

    g.setEdge(0, 4, 0);
    g.setEdge(4, 0, 0);

    g.setEdge(1, 2, 0);
    g.setEdge(2, 1, 0);


    g.setEdge(1, 4, 0);
    g.setEdge(4, 1, 0);

    g.setEdge(2, 5, 0);
    g.setEdge(5, 2, 0);

    g.setEdge(3, 6, 0);
    g.setEdge(6, 3, 0);

    g.setEdge(4, 6, 0);
    g.setEdge(6, 4, 0);

    g.setEdge(6, 7, 0);
    g.setEdge(7, 6, 0);

    g.setEdge(7, 8, 0);
    g.setEdge(8, 7, 0);

    SharedPointer< Array<int> > sa = g.BFS(0);


    for(int i=0; i<sa->length(); i++)
    {
        cout << (*sa)[i] << " "; // 0 1 3 4 2 6 5 7 8
    }

    return 0;
}

 

   

 

3、深度优先搜索算法

深度优先(DFS) 

    

深度优先算法 (方法一)

   -原料: class LinkStack<T>; 

   -步骤 

              1. 将起始顶点压入栈中 

              2. 弹出栈顶顶点 v, 判断是否已经标记(标记:转2, 未标记:转3) 

              3. 标记顶点,并将顶点 v 的邻接顶点压入栈中 

              4. 判断栈是否为空(非空:转2, 空:结束)

深度优先算法示例

            

                

编程实验 

深度优先算法     Graph::DFS 

Graph.h

    SharedPointer< Array<int> > DFS(int i)
    {
        DynamicArray<int>* ret = NULL;

        if((0 <= i) && (i < vCount()))
        {
            LinkStack<int> s;
            LinkQueue<int> r;
            DynamicArray<bool> visited(vCount());

            for(int j=0; j<visited.length(); j++)
            {
                visited[j] = false;
            }

            s.push(i);

            while(s.size() > 0)
            {
                int v = s.top();

                s.pop();

                if( !visited[v] )
                {
                    SharedPointer< Array<int> > aj = getAdjacent(v);

                    for(int j=aj->length()-1; j>=0; j--)
                    {
                        s.push((*aj)[j]);   // 最先获取到的邻接顶点最后入栈,最先出栈
                    }

                    r.add(v);

                    visited[v] = true;
                }
            }

            ret = toArray(r);
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "Index i is invalid ...");
        }

        return ret;
    }

main.cpp

#include <iostream>  
#include "MatrixGraph.h"  
  
using namespace std;  
using namespace DTLib;  
  
int main()  
{  
    MatrixGraph<9, char, int> g;  
  
    const char* VD = "ABEDCGFHI";  
  
    for(int i=0; i<9; i++)  
    {  
        g.setVertex(i, VD[i]);  
    }  
  
    g.setEdge(0, 1, 0);  
    g.setEdge(1, 0, 0);   // 有向图表示无向图,权值0代表无权值  
  
    g.setEdge(0, 3, 0);  
    g.setEdge(3, 0, 0);  
  
    g.setEdge(0, 4, 0);  
    g.setEdge(4, 0, 0);  
  
    g.setEdge(1, 2, 0);  
    g.setEdge(2, 1, 0);  
  
  
    g.setEdge(1, 4, 0);  
    g.setEdge(4, 1, 0);  
  
    g.setEdge(2, 5, 0);  
    g.setEdge(5, 2, 0);  
  
    g.setEdge(3, 6, 0);  
    g.setEdge(6, 3, 0);  
   
    g.setEdge(4, 6, 0);  
    g.setEdge(6, 4, 0);  
  
    g.setEdge(6, 7, 0);  
    g.setEdge(7, 6, 0);  
  
    g.setEdge(7, 8, 0);  
    g.setEdge(8, 7, 0);  
  
    SharedPointer< Array<int> > sa = g.DFS(0);  
  
  
    for(int i=0; i<sa->length(); i++)  
    {  
        cout << (*sa)[i] << " ";  
    }  
  
    return 0;  
}  

  

 

问题 :如何使用二叉树先序遍历的思想遍历图? 

递归版深度优先(方法二)

   -原图 被划分为 起始顶点 {\color{Red} v_{0}} 子图 G',深度优先遍历原图 就是先访问 {\color{Red} v_{0}}  再 深度优先遍历子图

                

定义功能: DFS(graph, vex) 

               功能: 以顶点 vex 为起始顶点深度优先遍历 graph 

        

编程实验 

递归版深度优先算法     DFS(graph, vex)

#include <iostream>  
#include "MatrixGraph.h"  
  
using namespace std;  
using namespace DTLib;  
  
template < typename V, typename E >  
void DFS(Graph<V, E>& g, int v, Array<bool>& visited)  
{  
    if((0 <= v) && (v < g.vCount()))  
    {  
        cout << v << endl;  
  
        visited[v] = true;  
  
        SharedPointer< Array<int> > aj = g.getAdjacent(v);  
  
        for(int i=0; i<aj->length(); i++)   // v 没有邻接顶点就不会递归调用  
        {  
            if( !visited[(*aj)[i]])  
            {  
                DFS(g, (*aj)[i], visited); // 从邻接顶点开始深度优先遍历子图  
            }  
        }  
    }  
    else  
    {  
        THROW_EXCEPTION(InvalidParameterException, "Index v is invalid ...");  
    }  
}  
  
template < typename V, typename E >  
void DFS(Graph<V, E>& g, int v)  
{  
    DynamicArray<bool> visited(g.vCount());  
  
    for(int i=0; i<visited.length(); i++)  
    {  
        visited[i] = false;  
    }  
  
    DFS(g, v, visited);  
}  
  
  
int main()  
{  
    MatrixGraph<9, char, int> g;  
  
    const char* VD = "ABEDCGFHI";  
  
    for(int i=0; i<9; i++)  
    {  
        g.setVertex(i, VD[i]);  
    }  
  
    g.setEdge(0, 1, 0);  
    g.setEdge(1, 0, 0);   // 有向图表示无向图,权值0代表无权值  
  
    g.setEdge(0, 3, 0);  
    g.setEdge(3, 0, 0);  
  
    g.setEdge(0, 4, 0);  
    g.setEdge(4, 0, 0);  
  
    g.setEdge(1, 2, 0);  
    g.setEdge(2, 1, 0);  
  
  
    g.setEdge(1, 4, 0);  
    g.setEdge(4, 1, 0);  
  
    g.setEdge(2, 5, 0);  
    g.setEdge(5, 2, 0);  
  
    g.setEdge(3, 6, 0);  
    g.setEdge(6, 3, 0);  
  
    g.setEdge(4, 6, 0);  
    g.setEdge(6, 4, 0);  
  
    g.setEdge(6, 7, 0);  
    g.setEdge(7, 6, 0);  
  
    g.setEdge(7, 8, 0);  
    g.setEdge(8, 7, 0);  
  
    SharedPointer< Array<int> > sa = g.DFS(0);  
  
  
    for(int i=0; i<sa->length(); i++)  
    {  
        cout << (*sa)[i] << " ";  
    }  
  
    DFS(g, 0);  
  
  
    return 0;  
}  

   

 

4、小结 

            广度优先按照 “层次的方式” 对顶点进行访问 

            广度优先算法的核心是队列的使用 

            深度优先按照“先序遍历的方式”对顶点进行访问 

            深度优先算法的核心是栈的使用 

            深度优先和广度优先的唯一不同在于栈或队列的使用 

            深度优先算法可以使用递归的方式实现 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值