深度优先搜索与广度优先搜索(含算法例题讲解)

搜索算法

搜索算法有很多种类型,一般来说就是深度优先搜索广度优先搜索A*搜索IDA*搜索这四种类型的搜索,而本篇讲述的就是其中最核心,最简单的搜索深度优先搜索和广度优先搜索。

DFS算法简述

深度优先搜索是一种适用于树形结构的搜索,它和数据结构栈紧密相连。对于这种算法而言,它的主要步骤大致如下:

  1. 找到当前可以拓展的点,那么立即走入这个分支点。
  2. 如果当前搜索分支,无效或者已经找到目标,那么退回到上一步,即回溯。
  3. 每一个点最多会被访问两次。访问含义是入栈一次,出栈一次。

DFS性质

DFS序列就是深度优先搜索最为重要的性质,它可以将一个子树变成一个区间。

代码实现(递归)

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

#define MAX_N 10000

typedef struct Node {
    int vertex;
    struct Node *next;
} Node, *LinkedList;

LinkedList insert_node(LinkedList head, int index) {
    Node *node = (Node *)malloc(sizeof(Node));
    node->vertex = index;
    node->next = head;
    head = node;
    return head;
}

typedef struct Graph {
    LinkedList edges[MAX_N];
    int n;
    int visited[MAX_N];
} Graph;

void init(Graph * g, int n) {
    g->n = n;
    for (int i = 0; i < g->n; ++i) {
        g->edges[i] = NULL;
    }
    
}

void insert(Graph *g, int x, int y) {
    if (x < 0 || x >= g->n || y < 0 || y >= g->n) {
        return ;
    }
    g->edges[x] = insert_node(g->edges[x], y);
    g->edges[y] = insert_node(g->edges[y], x);
}

void clear(Graph *g) {
    for (int i = 0; i < g->n; ++i) {
        Node *head = g->edges[i];
        while (head != NULL) {
            Node *delete_node = head;
            head = head->next;
            free(delete_node);
        }
    }
    free(g);
}

void dfs(Graph *g, int index) {
    printf("%d
", index);
    g->visited[index] = 1;
    for (Node *tmp = g->edges[index]; tmp != NULL; tmp = tmp->next) {
        if (!g->visited[tmp->vertex]) {
            dfs(g, tmp->vertex);
        }
    }
    return;
}

int main() {
    int n, m, k;
    scanf("%d %d", &n, &m);
    Graph *graph = (Graph *)malloc(sizeof(Graph));
    init(graph, n);
    for (int i = 0; i < m; ++i) {
        int x, y;
        scanf("%d %d", &x, &y);
        insert(graph, x, y);
    }
    scanf("%d", &k);
    dfs(graph, k);
    clear(graph);
    return 0;
}

算法例题

BFS算法简述

广度优先搜索和深度优先搜索恰恰相反,它是一种适用于图型结构的搜索,它和数据结构队列紧密向量。对于这种算法而言,它主要的步骤大致如下所示:

  1. 找到当前可以拓展的点,将它放入候选队列之中。
  2. 每次选取候选队列的队头,作为当前状态。

BFS性质

对于广度优先搜索而言,它是一种逐层遍历的算法,所有状态按照入队的先后顺序具有层次单调性,也就是所谓的步数单调性质,如果每一次拓展恰好对应一部,那么当第一个状态第一次被访问(入队),就会得到从起始状态到达该状态的最少步数。

代码实现(队列)

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

#define MAX_N 10000

typedef struct Queue {
    int *data;
    int head, tail, length;
} Queue;

void init_queue(Queue *q, int length_input) {
    q->data = (int *)malloc(sizeof(int) * length_input);
    q->length = length_input;
    q->head = 0;
    q->tail = -1;
}

void push(Queue *q, int element) {
    if (q->tail + 1 < q->length) {
        q->tail++;
        q->data[q->tail] = element;
    }
}

int front(Queue *q) {
        return q->data[q->head];
}

void pop(Queue *q) {
        q->head++;
}

int empty(Queue *q) {
    if (q->head > q->tail) {
        return 1;
    } else {
        return 0;
    }
}

void clear_queue(Queue *q) {
    free(q->data);
    free(q);
}

typedef struct Node {
    int vertex;
    struct Node *next;
}Node, *LinkedList;

LinkedList insert_node(LinkedList head, int index) {
    Node *node = (Node *)malloc(sizeof(Node));
    node->vertex = index;
    node->next = head;
    head = node;
    return head;
}

typedef struct Graph {
    LinkedList edges[MAX_N];
    int visited[MAX_N];
    int n;
}Graph;

void init_graph(Graph *g, int n) {
    g->n = n;
    memset(g->visited, 0, sizeof(g->visited));
    for (int i = 0; i < g->n; ++i) {
        g->edges[i] = NULL;
    }
}

void insert(Graph *g, int x, int y) {
    if (x < 0 || x >= g->n || y < 0 || y >= g->n) {
        return ;
    }
    g->edges[x] = insert_node(g->edges[x], y);
    g->edges[y] = insert_node(g->edges[y], x);
}

void clear_graph(Graph *g) {
    for (int i = 0; i < g->n; ++i) {
        Node *head = g->edges[i];
        while (head != NULL) {
            Node *delete_node = head;
            head = head->next;
            free(delete_node);
        }
    }
    free(g);
}

void bfs(Graph *g, int id) {
    Queue *queue = (Queue *)malloc(sizeof(Queue));
    init_queue(queue, g->n);
    printf("%d
", id);
    g->visited[id] = 1;
    push(queue, id);
    while (!empty(queue)) {
        int tmp = front(queue);
        pop(queue);
        for (Node *adj = g->edges[tmp]; adj != NULL; adj = adj->next) {
            if (!g->visited[adj->vertex]) {
                printf("%d
", adj->vertex);
                push(queue, adj->vertex);
                g->visited[adj->vertex] = 1;
            }
        }
    }
    clear_queue(queue);
}

int main() {
    int n, m, k;
    scanf("%d %d", &n, &m);
    Graph *graph = (Graph *)malloc(sizeof(Graph));
    init_graph(graph, n);
    for (int i = 0; i < m; ++i) {
        int x, y;
        scanf("%d %d", &x, &y);
        insert(graph, x, y);
    }
    scanf("%d", &k);
    bfs(graph, k);
    clear_graph(graph);
    return 0;
}

算法例题

更多算法例题(迷宫问题与棋盘马走日问题)

参考资料:

https://www.acwing.com/blog/content/173/

https://www.acwing.com/blog/content/173/

Min是清明的茗
原文地址:https://www.cnblogs.com/MinPage/p/13783477.html