图的遍历(BFS,DFS)

本文介绍了在数据结构课程中用C++实现图的两种遍历方法——广度优先搜索(BFS)和深度优先搜索(DFS)。通过邻接矩阵和邻接表两种存储方式,实现了图的遍历。BFS利用队列进行,而DFS则采用递归方法。代码示例展示了如何构造和遍历图。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:在数据结构课程中,用C++封装了一些经典的算法,所以特地开一个个人分类来记录这些算法,以便将来用到的时候能够使我回忆起来,或者当做模板使用(另一方面也将书本上的代码的一些错误改正过来,方便以后的同学参考)。

首先是第三章的图的作业,图有两种存储方法,一种是用邻接矩阵来存图(主要用于稠密图),另一种是用邻接表来存图(主要用于稀疏图)。两种存图的方式不同,但是可以通过重写虚函数,使两种方式对图的操作的函数都一样,这样就便于之后在图上的各种算法的实现(比如最小生成树,最短路,拓补排序)

这次作业是封装图的类型以及用BFS,DFS 来遍历图。BFS用队列来实现,DFS则用递归来实现。

下面是我这段代码的构造的图:




下面是代码


1、邻接矩阵实现:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<stack>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int INF = 0x7fffffff;
//边类型
template <class EdgeType>
class Edge
{
public:
    int start,endd;
    EdgeType weight;
    Edge():start(-1),endd(-1),weight(-1){}
    Edge(int s,int e,int w=-1):start(s),endd(e),weight(w){}
    bool operator < (const Edge<EdgeType> e) const {
        return this->weight > e.weight;
    }
};

//图的抽象数据类型
template <class EdgeType>
class Graph
{
public:
    int numv,nume;
    bool *mark;

    //构造函数
    Graph(int num):numv(num),nume(0) {
        mark = new bool[num+1];
        memset(mark,false,sizeof(mark));
    }

    //析构函数
    ~Graph() {
        delete []mark;
    }
    virtual Edge<EdgeType> FirstEdge(int vertex)=0;
    virtual Edge<EdgeType> NextEdge(Edge<EdgeType> edge)=0;
    virtual void addEdge(int s,int e,EdgeType w)=0;
//    virtual void deleEdge(int s,int e)=0;

    //判断该边是否为该图的边
    bool IsEdge(Edge<EdgeType> edge) {
        if(edge.weight == -1) {
            return false;
        }
        return true;
    }
};



//邻接矩阵类型
template<class EdgeType>
class MatGraph: public Graph<EdgeType>
{
private:
    int **matrix;
public:
    //构造函数
    MatGraph(int num):Graph<EdgeType>(num) {
        matrix = (int**)new int*[num+1];
        for(int i=0;i<=num;i++) {
            matrix[i] = new int [num+1];
        }
        for(int i=0;i<=num;i++)
            memset(matrix[i],0,sizeof(matrix[i]));
//        memset(matrix,0,sizeof(int)*(num+1)*(num+1));
    }

    //析构函数
    ~MatGraph() {
        for(int i=0;i<=this->numv;i++) {
            delete [] matrix[i];
        }
        delete [] matrix;
    }

    //加入一条边
    void addEdge(int s,int e,int w=1) {
        if(matrix[s][e]!=0) {
            cout<<"改边已经存在,不能加入该边"<<endl;
            return ;
        }
        matrix[s][e] = w;
    }

    //返回以v为起点的第一条边
    Edge<EdgeType> FirstEdge(int v) {
        Edge<EdgeType> tempEdge(v,-1);
        for(int i=1;i<=this->numv;i++) {
            if(matrix[v][i]>0) {
                tempEdge.endd = i;
                tempEdge.weight = matrix[v][i];
                return tempEdge;
            }
        }
        return tempEdge;
    }

    //返回与该边有同起点的下一条边
    Edge<EdgeType> NextEdge(Edge<EdgeType> edge) {
        Edge<EdgeType> tempEdge(edge.start,-1);
        for(int i=edge.endd+1;i<=this->numv;i++) {
            if(matrix[edge.start][i]!=0) {
                tempEdge.endd = i;
                tempEdge.weight = matrix[edge.start][i];
                return tempEdge;
            }
        }
        return tempEdge;
    }

    //递归实现以v为起点的深度优先搜索
    void DFS(int v) {
        cout<<"DFS: ";
        memset(this->mark,false,sizeof(bool)*(this->numv+1));//将每个点标记为未访问
        dfs(v);
        cout<<endl;
    }
    void dfs(int v) {
        if(!this->mark[v]) {//递归出口
            cout<<v<<' ';
            this->mark[v] = true;//标记该边已经访问过
            for(Edge<EdgeType> edge=FirstEdge(v);this->IsEdge(edge);edge=NextEdge(edge)) {
                if(!this->mark[edge.endd]) {
                    dfs(edge.endd);
                }
            }
        }
    }

    //队列实现以v为起点的宽度优先搜索
    void BFS(int v) {
        //基类的成员变量和成员函数要用this来调用
        memset(this->mark,false,sizeof(bool)*(this->numv+1));
        queue<int> que;
        que.push(v);
        this->mark[v]=true;
        cout<<"BFS: ";
        while(!que.empty()) {
            int node=que.front();
            que.pop();
            cout<<node<<' ';
            for(Edge<EdgeType> edge=FirstEdge(node);this->IsEdge(edge);edge=NextEdge(edge)) {
//                cout<<node<<"->"<<edge.endd<<endl;
                if(!this->mark[edge.endd]) {
                    que.push(edge.endd);
                    this->mark[edge.endd]=true;
                }
            }
        }
        cout<<endl;
    }
};


//图遍历的建图
template<class T>
void init (MatGraph<T>& graph1) {
    graph1.addEdge(1,2);
    graph1.addEdge(2,1);
    graph1.addEdge(2,4);
    graph1.addEdge(4,2);
    graph1.addEdge(2,5);
    graph1.addEdge(5,2);
    graph1.addEdge(4,8);
    graph1.addEdge(8,4);
    graph1.addEdge(5,8);
    graph1.addEdge(8,5);
    graph1.addEdge(1,3);
    graph1.addEdge(3,1);
    graph1.addEdge(3,6);
    graph1.addEdge(6,3);
    graph1.addEdge(3,7);
    graph1.addEdge(7,3);
    graph1.addEdge(6,7);
    graph1.addEdge(7,6);
}

int main () {
//    作业一:图的遍历(DFS、BFS)
    MatGraph<int> graph1(8);
    init(graph1);
    graph1.DFS(1);
    graph1.BFS(1);

    return 0;
}


2、邻接表实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<stack>
using namespace std;
const int INF = 0x7fffffff;


//边类型
template <class EdgeType>
class Edge
{
public:
    int start,endd;
    EdgeType weight;
    Edge<EdgeType> *next;
    Edge():start(-1),endd(-1),weight(-1),next(0){}
    Edge(int s,int e,EdgeType w=1,Edge<EdgeType> *nex=0):start(s),endd(e),weight(w),next(nex){}
    bool operator < (const Edge<EdgeType> e) const {
        return this->weight > e.weight;
    }
};

//图的抽象数据类型
template <class EdgeType>
class Graph
{
public:
    int numv,nume;
    bool *mark;

    //构造函数
    Graph(int num):numv(num),nume(0) {
        mark = new bool[num+1];
        memset(mark,false,sizeof(mark));
    }

    //析构函数
    ~Graph() {
        delete []mark;
    }
    virtual Edge<EdgeType> FirstEdge(int vertex)=0;
    virtual Edge<EdgeType> NextEdge(Edge<EdgeType> edge)=0;
    virtual void addEdge(int s,int e,EdgeType w)=0;
//    virtual void deleEdge(int s,int e)=0

    //判断该边是否为该图的边
    bool IsEdge(Edge<EdgeType> edge) {
        if(edge.endd == -1) {
            return false;
        }
        return true;
    }
};


//由同一个起点出发的边的链表表类型
template<class EdgeType>
class EdgeList
{
public:
    Edge<EdgeType> *head;
    //构造函数
    EdgeList():head(0){}
};

//图的邻接表示
template<class EdgeType>
class ListGraph: public Graph<EdgeType>
{
private:
    EdgeList< EdgeType > *graList;
public:
    //构造函数
    ListGraph(int num=0):Graph<EdgeType>(num) {
        graList = new EdgeList< EdgeType >[num+1];
    }

    //析构函数
    ~ListGraph() {
        delete []graList;
    }

    //加入一条边
    void addEdge(int s,int e,EdgeType w=1) {
        if(graList[s].head == NULL) {
            graList[s].head = new Edge<EdgeType>(s,e,w,0);
        }
        else {
            Edge<EdgeType> *curEdge = graList[s].head;
            bool flag=false;//已经存在改边flag=true
            if(curEdge->endd == e)
                flag=true;
            while(curEdge->next && !flag) {
                curEdge = curEdge->next;
                if(curEdge->endd == e) {
                    flag=true;
                }
            }
            if(flag) {
                //如果已经存在改边,则不用加边
                cout<<"该边已存在,添加失败"<<endl;
                return;
            }
            curEdge->next = new Edge<EdgeType>(s,e,w,0);
        }
    }

    //返回起点为v的第一条边(邻接表中该函数没用)
    Edge<EdgeType> FirstEdge(int v) {
        if(graList[v].head) {
            return *graList[v].head;
        }
        Edge<EdgeType> temp(-1,-1,-1);
        return temp;
    }

    //返回起点为v的一条边的下一条边(邻接表中该函数没用)
    Edge<EdgeType> NextEdge(Edge<EdgeType> e) {
        if(e.next) {
            return *e.next;
        }
        Edge<EdgeType> temp(-1,-1,-1);
        return temp;
    }

    //递归实现以v为起点的深度优先搜索
    void DFS(int v) {
        cout<<"DFS: ";
        memset(this->mark,false,sizeof(bool)*(this->numv+1));//将每个点标记为未访问
        dfs(v);
        cout<<endl;
    }
    void dfs(int v) {
        if(!this->mark[v]) {//递归出口
            cout<<v<<' ';
            this->mark[v] = true;//标记该边已经访问过
            for(Edge<EdgeType> edge=FirstEdge(v);this->IsEdge(edge);edge=NextEdge(edge)) {
                if(!this->mark[edge.endd]) {
                    dfs(edge.endd);
                }
            }
        }
    }

    //队列实现以v为起点的宽度优先搜索
    void BFS(int v) {
        memset(this->mark,false,sizeof(bool)*(this->numv+1));
        queue<int> que;
        que.push(v);
        this->mark[v]=true;
        cout<<"BFS: ";
        while(!que.empty()) {
            int node=que.front();
            que.pop();
            cout<<node<<' ';
            for(Edge<EdgeType> edge=FirstEdge(node);this->IsEdge(edge);edge=NextEdge(edge)) {
//                cout<<node<<"->"<<edge.endd<<endl;
                if(!this->mark[edge.endd]) {
                    que.push(edge.endd);
                    this->mark[edge.endd]=true;
                }
            }
        }
        cout<<endl;
    }

};

//图遍历的建图
template<class T>
void init (ListGraph<T>& graph1) {
    graph1.addEdge(1,2);
    graph1.addEdge(2,1);
    graph1.addEdge(2,4);
    graph1.addEdge(4,2);
    graph1.addEdge(2,5);
    graph1.addEdge(5,2);
    graph1.addEdge(4,8);
    graph1.addEdge(8,4);
    graph1.addEdge(5,8);
    graph1.addEdge(8,5);
    graph1.addEdge(1,3);
    graph1.addEdge(3,1);
    graph1.addEdge(3,6);
    graph1.addEdge(6,3);
    graph1.addEdge(3,7);
    graph1.addEdge(7,3);
    graph1.addEdge(6,7);
    graph1.addEdge(7,6);
}


int main () {
//    作业一:图的遍历(DFS、BFS)
    ListGraph<int> graph1(8);
    init(graph1);
    graph1.DFS(1);
    graph1.BFS(1);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值