图的创建和遍历(邻接表、邻接矩阵存储实现BFS、DFS)

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。在学习图的过程中,知道图中存储的数据称为顶点,无向图连接顶点之间关系的称为边,有向图连接顶点的称为弧,弧的起点为弧尾,终点为弧头。图可以根据边有无方向,分为无向图和有向图,只要存在有方向的边,则为有向图,全部为无方向边的图,则为无向图。

1.邻接表

接表是图的一种链式存储结构。由两部分组成:表头结点表和边表。邻接表中每个单链表的第一个结点存放有关顶点的信息,把这一结点看成链表的表头,其余结点存放有关边的信息

(1)表头结点表:包括数据域和链域,数据域存储顶点的名称,链域用于指向链表中第一个结点(与顶点邻接的第一个顶点)

(2)边表:包括邻接点域(指示与顶点邻接的点在图中的位置,即数组下标)、数据域(存储和边相关的信息,如权值)、链域(指示与顶点邻接的下一条边的结点)。

代码设计如下:

//
// Created by A on 2023/6/10.
//
#include <iostream>
#include <vector>
#include <cassert>
#include <stack>
#include <queue>
#include <algorithm>

using namespace std;

class SparseGraph {
public:
    int n, m;
    bool directed;
    vector<vector<int> > g;

    SparseGraph(int n, bool directed) {
        this->n = n;
        this->m = m;
        this->directed = directed;
        for (int i = 0; i < n; ++i)
            g.push_back(vector<int>());
    }

    ~SparseGraph() {

    }

    int V() {
        return n;
    }

    int E() {
        return m;
    }

    void addEgde(int v, int w) {
        assert(v >= 0 && v < n);
        assert(w >= 0 && w < n);
        g[v].push_back(w);
        if (!directed)
            g[w].push_back(v);
        ++m;
    }

    bool hasEdge(int v, int w) {
        assert(v >= 0 && v < n);
        assert(w >= 0 && w < n);
        for (int i = 0; i < g[v].size(); ++i) {
            if (g[v][i] == w)
                return true;
        }
        return false;
    }

    void Print() {
        for (int i = 0; i < g.size(); ++i) {
            cout << "边" << i << ":";
            for (int j = 0; j < g[i].size(); ++j) {
                cout << g[i][j] << " ";
            }
            cout << endl;
        }
    }

    void dfs(int v) {
        vector<bool> visited(n, false);
        stack<int> s;
        s.push(v);
        while (!s.empty()) {
            int tmp = s.top();
            if (!visited[tmp])
                cout << tmp << " ";
            visited[tmp] = true;
            s.pop();
            int size = g[tmp].size();
            for (int i = 0; i < size; ++i) {
                int b = g[tmp][i];
                if (!visited[b])
                    s.push(b);
            }
        }
        cout << endl;
    }

    void bfs(int v) {
        vector<bool> visited(n, false);
        queue<int> que;
        que.push(v);
        while (!que.empty()) {
            int tmp = que.front();
            if (!visited[tmp])
                cout << tmp << " ";
            visited[tmp] = true;
            que.pop();
            int size = g[tmp].size();
            for (int i = 0; i < size; ++i) {
                int b = g[tmp][i];
                if (!visited[b])
                    que.push(b);
            }
        }
        cout << endl;
    }
};

int main() {
    int vertex, edge;
    cin >> vertex >> edge;
    SparseGraph myGraph(vertex, false);
    for (int i = 0; i < edge; ++i) {
        int from, to;
        cin >> from >> to;
        assert(from >= 0 && from < vertex);
        assert(from >= 0 && from < vertex);
        myGraph.addEgde(from, to);
    }
    myGraph.Print();
    myGraph.dfs(0);
    myGraph.bfs(0);
    return 0;
}


 

2.邻接矩阵

邻接矩阵是表示顶点之间相邻关系的矩阵。他由V和E集合,其中,V是顶点,E是边。因此,用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,这个二维数组称为邻接矩阵。邻接矩阵又分有向图邻接矩阵和无向图邻接矩阵。

代码设计如下:

//
// Created by A on 2023/6/10.
//
#include <iostream>
#include <vector>
#include <cassert>
#include <stack>
#include <queue>

using namespace std;

class DenseGraph {
public:
    int n, m;
    bool directed;
    vector<vector<int> > g;


    DenseGraph(int n, bool directed) {
        this->n = n;
        this->m = m;
        this->directed = directed;
        for (int i = 0; i < n; ++i)
            g.push_back(vector<int>(n, 0));
    }

    ~DenseGraph() {

    }

    int V() {
        return n;
    }

    int E() {
        return m;
    }

    void addEgde(int v, int w) {
        assert(v >= 0 && v < n);
        assert(w >= 0 && w < n);
        if (hasEdge(v, w))
            return;
        g[v][w] = 1;
        if (!directed)
            g[w][v] = 1;
        ++m;
    }

    bool hasEdge(int v, int w) {
        assert(v >= 0 && v < n);
        assert(w >= 0 && w < n);
        return (g[v][w] == 1);
    }

    void Print() {
        for (int i = 0; i < g.size(); ++i) {
            for (int j = 0; j < g[i].size(); ++j) {
                cout << g[i][j] << " ";
            }
            cout << endl;
        }
    }

    void dfs(int v) {
        assert(v >= 0 && v < n);
        vector<bool> visited(n, false);
        stack<int> s;
        s.push(v);
        while (!s.empty()) {
            int tmp = s.top();
            if (!visited[tmp])
                cout << tmp << " ";
            visited[tmp] = true;
            s.pop();
            int size = g[tmp].size();
            for (int i = 0; i < size; ++i) {
                int b = g[tmp][i];
                if (b == 1 && !visited[i])
                    s.push(i);
            }
        }
        cout << endl;
    }

    void bfs(int v) {
        assert(v >= 0 && v < n);
        vector<bool> visited(n, false);
        queue<int> que;
        que.push(v);
        while (!que.empty()) {
            int tmp = que.front();
            if (!visited[tmp])
                cout << tmp << " ";
            visited[tmp] = true;
            que.pop();
            int size = g[tmp].size();
            for (int i = 0; i < size; ++i) {
                int b = g[tmp][i];
                if (b == 1 && !visited[i])
                    que.push(i);
            }
        }
        cout << endl;
    }

};

int main() {
    int vertex, edge;
    cin >> vertex >> edge;
    DenseGraph myGraph(vertex, false);
    for (int i = 0; i < edge; ++i) {
        int from, to;
        cin >> from >> to;
        assert(from >= 0 && from < vertex);
        assert(from >= 0 && from < vertex);
        myGraph.addEgde(from, to);
    }
    myGraph.Print();
    myGraph.dfs(0);
    myGraph.bfs(0);
    return 0;
}

3.深度优先遍历(DFS) 

图的深度优先遍历(Depth-First Search,DFS)是一种遍历图的方式,它从图的某个顶点开始,沿着一条路径一直走到底,直到不能继续为止,然后返回到上一个节点,继续尝试其他路径,直到所有的节点都被访问过为止。简单来说,就是尽可能深地访问每个节点,如果没有路可走就返回上一个节点。

具体实现时,可以使用递归或栈来实现深度优先遍历。在递归实现中,从起始节点开始,递归地遍历与该节点相邻的节点,直到遇到没有未被访问的相邻节点为止。在栈实现中,从起始节点开始,将其压入栈中,然后弹出栈顶节点,遍历该节点的未被访问的相邻节点,并将其压入栈中,直到栈为空为止。

4.图的广度优先遍历(BFS)

图的广度优先遍历(Breadth-First Search,BFS)是一种遍历图的方式,它从图的某个顶点开始,先访问该节点,然后访问与该节点相邻的所有节点,再依次访问这些相邻节点的相邻节点,直到所有节点都被访问过为止。简单来说,就是逐层访问节点,先访问距离起始节点最近的节点。

具体实现时,可以使用队列来实现广度优先遍历。从起始节点开始,将其加入队列,然后弹出队首节点,依次访问该节点的未被访问的相邻节点,并将其加入队列尾部,直到队列为空为止。需要注意的是,在访问每个节点时,要标记已经访问过的节点,以避免重复访问。

与深度优先遍历相比,广度优先遍历可以找到最短路径,因为它首先访问距离起始节点最近的节点。但是,广度优先遍历需要使用队列,空间复杂度比深度优先遍历高。

运行结果如下:

6 8
0 1
0 2
0 5
1 2
1 3
1 4
3 4
3 5
图的邻接表实现: 
边0:1 2 5 
边1:0 2 3 4 
边2:0 1 
边3:1 4 5 
边4:1 3 
边5:0 3 
深度优先遍历结果: 
0 5 3 4 1 2 
广度优先遍历结果: 
0 1 2 5 3 4 

6 8
0 1
0 2
0 5
1 2
1 3
1 4
3 4
3 5
图的邻接矩阵实现: 
0 1 1 0 0 1 
1 0 1 1 1 0 
1 1 0 0 0 0 
0 1 0 0 1 1 
0 1 0 1 0 0 
1 0 0 1 0 0 
深度优先遍历结果: 
0 5 3 4 1 2 
广度优先遍历结果: 
0 1 2 5 3 4 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值