数据结构与算法之广度优先遍历

广度优先遍历(Breadth-First Search,BFS)是一种遍历或搜索数据结构(如树或图)的算法。它从根节点开始,依次遍历同一级别的所有节点,然后再逐级遍历下一级别的节点,直到遍历完整个结构。

BFS使用队列(queue)来实现遍历过程。从根节点开始,将根节点入队,然后进入循环。循环中取出队列首部节点,访问它的所有邻居节点并将其入队,然后重复上述步骤,直到队列为空。

BFS的时间复杂度为O(N),其中N代表节点个数。因为它需要遍历整个结构中的每个节点一次。BFS的空间复杂度也为O(N),因为需要使用队列来存储节点。

BFS的应用非常广泛。例如,可以用它来解决最短路径问题、迷宫问题等。由于BFS能够找到最短路径,因此它也被广泛用于人工智能、游戏设计、网络路由等领域。

在这里插入图片描述

一、C 实现 广度优先遍历 及代码详解

广度优先遍历是一种图遍历算法,也称为“宽度优先搜索”或“横向优先搜索”。该算法从图的某个起始节点开始遍历,先访问该节点,然后访问该节点的所有相邻节点,再访问相邻节点的相邻节点,以此类推,直到遍历完所有可达节点。广度优先遍历一般使用队列来实现。

以下是C语言实现广度优先遍历的代码及详解:

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

#define MAX_VERTEX_NUM 100 // 图中顶点的最大数量

typedef struct node{// 邻接表中的链表节点
    int adjvex; // 邻接点在数组中的下标
    struct node *next; // 指向下一个邻接点
} EdgeNode;

typedef struct VertexNode{// 邻接表中的顶点节点
    int data;// 顶点的数据
    EdgeNode *firstEdge;// 指向第一条邻接边
} VertexNode;

typedef struct Graph{// 定义图结构
    VertexNode adjList[MAX_VERTEX_NUM];// 邻接表
    int visited[MAX_VERTEX_NUM];// 标记数组,用于记录每个顶点是否被访问过
    int vertexNum;// 顶点数目
    int edgeNum;// 边数目
} Graph;

typedef struct Queue{// 定义队列结构
    int *data;// 队列中的数据
    int front, rear;// 队头和队尾指针
} Queue;

void initQueue(Queue *queue, int size){// 初始化队列
    queue->data = (int*)malloc(size * sizeof(int));
    queue->front = queue->rear = 0;
}

void enQueue(Queue *queue, int element){// 入队
    queue->data[queue->rear++] = element;
}

int deQueue(Queue *queue){// 出队
    return queue->data[queue->front++];
}

int isQueueEmpty(Queue *queue){// 判断队列是否为空
    return queue->front == queue->rear;
}

void createGraph(Graph *g){// 创建图
    printf("请输入顶点数目和边数目:");
    scanf("%d%d", &g->vertexNum, &g->edgeNum);
    printf("请输入每个顶点的数据:");
    for (int i = 0; i < g->vertexNum; i++){
        scanf("%d", &g->adjList[i].data);
        g->adjList[i].firstEdge = NULL;// 初始化邻接表
    }

    printf("请输入每条边连接的两个顶点在数组中的下标:\n");
    for (int i = 0; i < g->edgeNum; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        // 添加边
        EdgeNode *newEdge = (EdgeNode*)malloc(sizeof(EdgeNode));
        newEdge->adjvex = v;
        newEdge->next = g->adjList[u].firstEdge;
        g->adjList[u].firstEdge = newEdge;

        newEdge = (EdgeNode*)malloc(sizeof(EdgeNode));
        newEdge->adjvex = u;
        newEdge->next = g->adjList[v].firstEdge;
        g->adjList[v].firstEdge = newEdge;
    }
}

void BFS(Graph *g, int start){// 广度优先遍历
    Queue queue;
    initQueue(&queue, g->vertexNum);
    g->visited[start] = 1;// 标记起始点为已经访问
    printf("%d ", g->adjList[start].data);
    enQueue(&queue, start);

    while (!isQueueEmpty(&queue)){
        int u = deQueue(&queue);
        for (EdgeNode *e = g->adjList[u].firstEdge; e != NULL; e = e->next){
            int v = e->adjvex;
            if (!g->visited[v]){
                g->visited[v] = 1;
                printf("%d ", g->adjList[v].data);
                enQueue(&queue, v);
            }
        }
    }
}

int main(){
    Graph g;
    createGraph(&g);
    printf("广度优先遍历结果为:");
    for (int i = 0; i < g.vertexNum; i++){
        g.visited[i] = 0;// 初始化标记数组
    }
    BFS(&g, 0);// 从第0个顶点开始遍历
    printf("\n");
    return 0;
}

代码详解:

  1. 定义邻接表中的链表节点和顶点节点

    typedef struct node{// 邻接表中的链表节点
        int adjvex; // 邻接点在数组中的下标
        struct node *next; // 指向下一个邻接点
    } EdgeNode;
    
    typedef struct VertexNode{// 邻接表中的顶点节点
        int data;// 顶点的数据
        EdgeNode *firstEdge;// 指向第一条邻接边
    } VertexNode;
    
  2. 定义图结构

    typedef struct Graph{// 定义图结构
        VertexNode adjList[MAX_VERTEX_NUM];// 邻接表
        int visited[MAX_VERTEX_NUM];// 标记数组,用于记录每个顶点是否被访问过
        int vertexNum;// 顶点数目
        int edgeNum;// 边数目
    } Graph;
    
  3. 创建图

    void createGraph(Graph *g){// 创建图
        printf("请输入顶点数目和边数目:");
        scanf("%d%d", &g->vertexNum, &g->edgeNum);
        printf("请输入每个顶点的数据:");
        for (int i = 0; i < g->vertexNum; i++){
            scanf("%d", &g->adjList[i].data);
            g->adjList[i].firstEdge = NULL;// 初始化邻接表
        }
    
        printf("请输入每条边连接的两个顶点在数组中的下标:\n");
        for (int i = 0; i < g->edgeNum; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            // 添加边
            EdgeNode *newEdge = (EdgeNode*)malloc(sizeof(EdgeNode));
            newEdge->adjvex = v;
            newEdge->next = g->adjList[u].firstEdge;
            g->adjList[u].firstEdge = newEdge;
    
            newEdge = (EdgeNode*)malloc(sizeof(EdgeNode));
            newEdge->adjvex = u;
            newEdge->next = g->adjList[v].firstEdge;
            g->adjList[v].firstEdge = newEdge;
        }
    }
    

    先输入顶点数目和边数目,然后输入每个顶点的数据。初始化邻接表,每个顶点的第一条邻接边指向NULL。接着输入每条边连接的两个顶点在数组中的下标,将这两个顶点之间添加边。

  4. 初始化队列

    void initQueue(Queue *queue, int size){// 初始化队列
        queue->data = (int*)malloc(size * sizeof(int));
        queue->front = queue->rear = 0;
    }
    

    根据队列大小动态分配内存,并将队头和队尾指针都初始化为0。

  5. 入队

    void enQueue(Queue *queue, int element){// 入队
        queue->data[queue->rear++] = element;
    }
    

    将元素加入队尾。

  6. 出队

    int deQueue(Queue *queue){// 出队
        return queue->data[queue->front++];
    }
    

    返回队头元素并将队头指针向后移一位。

  7. 判断队列是否为空

    int isQueueEmpty(Queue *queue){// 判断队列是否为空
        return queue->front == queue->rear;
    }
    

    如果队头和队尾指针相等,说明队列为空。

  8. 广度优先遍历

   void BFS(Graph *g, int start){// 广度优先遍历
       Queue queue;
       initQueue(&queue, g->vertexNum);
       g->visited[start] = 1;// 标记起始点为已经访问
       printf("%d ", g->adjList[start].data);
       enQueue(&queue,

在这里插入图片描述

二、C++ 实现 广度优先遍历 及代码详解

广度优先遍历(BFS)是一种图遍历算法,从图的某个顶点开始遍历,先遍历它的所有相邻节点,然后依次遍历它们的相邻节点,直到遍历完整个图。BFS 通常用队列来实现。

以下是一个 C++ 实现 BFS 的代码示例:

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

void bfs(vector<vector<int>>& graph, int start) {
    vector<bool> visited(graph.size(), false);
    queue<int> q;
    visited[start] = true;
    q.push(start);
    while (!q.empty()) {
        int curr = q.front();
        q.pop();
        cout << curr << " ";
        for (int i = 0; i < graph[curr].size(); i++) {
            int next = graph[curr][i];
            if (!visited[next]) {
                visited[next] = true;
                q.push(next);
            }
        }
    }
    cout << endl;
}

int main() {
    vector<vector<int>> graph = {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {5}};
    bfs(graph, 0);
    return 0;
}

这段代码使用了一个二维向量 graph 来表示图的邻接表,其中 graph[i] 表示节点 i 的相邻节点列表。 bfs 函数以一个起始节点 start 作为参数,使用一个队列来遍历整个图。每次从队列头取出一个节点 curr,遍历它的相邻节点,并将未访问过的相邻节点加入队列中。为了避免重复访问节点,使用一个布尔型数组 visited 来记录每个节点是否已经被访问过。

main 函数中,定义了一个以 0 作为起始节点的图,并调用 bfs 函数来遍历整个图。

注意:这只是一个简单的示例,实际应用中需要根据实际情况进行修改和优化。
在这里插入图片描述

三、Java 实现 广度优先遍历 及代码详解

广度优先遍历(BFS)是一种图遍历算法,它从图的起始点开始,依次访问所有可以到达的节点。BFS 通常用队列来实现。

下面是 Java 实现广度优先遍历的代码,具体解释可以看代码注释:

import java.util.LinkedList;
import java.util.Queue;

public class BFS {
    public static void bfs(int[][] graph, int start) {
        // 定义一个队列来存储待访问的节点
        Queue<Integer> queue = new LinkedList<>();
        // 定义一个数组来记录节点是否已被访问过
        boolean[] visited = new boolean[graph.length];

        // 将起点加入队列,标记已访问
        queue.offer(start);
        visited[start] = true;

        while (!queue.isEmpty()) {
            // 取出队头节点
            int curr = queue.poll();
            System.out.print(curr + " ");

            // 遍历与当前节点相邻的所有节点
            for (int i = 0; i < graph[curr].length; i++) {
                int neighbor = graph[curr][i];
                // 如果该节点未被访问过,则加入队列并标记已访问
                if (!visited[neighbor]) {
                    queue.offer(neighbor);
                    visited[neighbor] = true;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[][] graph = {
                // 0  1  2  3  4  5
                {0, 1, 1, 0, 0, 0}, // 0
                {1, 0, 0, 1, 1, 0}, // 1
                {1, 0, 0, 0, 1, 1}, // 2
                {0, 1, 0, 0, 1, 0}, // 3
                {0, 1, 1, 1, 0, 1}, // 4
                {0, 0, 1, 0, 1, 0}  // 5
        };

        bfs(graph, 0);
    }
}

上面代码中,graph 数组表示一个无向图的邻接矩阵,bfs 方法用来实现 BFS 遍历。在 bfs 方法中,我们先定义一个队列 queue 来存储待访问的节点,一个 boolean 数组 visited 用来记录节点是否已被访问过。然后将起点加入队列,并标记已访问。接下来,用一个 while 循环不断从队列中取出队头节点 curr,输出其值,然后遍历与其相邻的所有节点,如果该节点未被访问过,则加入队列并标记已访问。循环直到队列为空。

在主函数中,我们创建一个表示无向图的邻接矩阵 graph,然后调用 bfs 方法进行遍历,起点是节点 0。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值