图的算法汇总

以下是一些常见的图的算法:

一、深度优先搜索(Depth-First Search,DFS)

  1. 基本思想:

    • 从图中的某个顶点出发,沿着一条路径尽可能深地探索,直到无法继续前进时,回溯到上一个顶点,继续探索另一条未访问过的路径。
  2. 应用场景:

    • 寻找图中的连通分量。
    • 检测图中是否存在环。
    • 求解迷宫问题等。
  3. 实现步骤:

    • 初始化一个标记数组,用于记录每个顶点是否被访问过。
    • 从某个顶点开始,递归地访问其未被访问过的邻接顶点。
    • 当没有未被访问过的邻接顶点时,回溯到上一个顶点。

以下是深度优先搜索(DFS)、广度优先搜索(BFS)和迪杰斯特拉算法(Dijkstra's algorithm)分别用 C++、Java 和 Go 语言实现的示例代码。

一、深度优先搜索(DFS)

C++ 代码

#include <iostream>
#include <vector>

using namespace std;

void dfs(vector<vector<int>>& graph, vector<bool>& visited, int vertex) {
    visited[vertex] = true;
    cout << vertex << " ";
    for (int i = 0; i < graph[vertex].size(); i++) {
        if (!visited[graph[vertex][i]]) {
            dfs(graph, visited, graph[vertex][i]);
        }
    }
}

Java 代码

import java.util.ArrayList;
import java.util.List;

public class DFS {
    public static void dfs(List<List<Integer>> graph, boolean[] visited, int vertex) {
        visited[vertex] = true;
        System.out.print(vertex + " ");
        for (int neighbor : graph.get(vertex)) {
            if (!visited[neighbor]) {
                dfs(graph, visited, neighbor);
            }
        }
    }
}

Go 代码

package main

import "fmt"

func dfs(graph [][]int, visited []bool, vertex int) {
    visited[vertex] = true
    fmt.Print(vertex, " ")
    for _, neighbor := range graph[vertex] {
        if!visited[neighbor] {
            dfs(graph, visited, neighbor)
        }
    }
}

二、广度优先搜索(Breadth-First Search,BFS)

  1. 基本思想:

    • 从图中的某个顶点出发,依次访问其所有的邻接顶点,然后再访问这些邻接顶点的邻接顶点,如此逐层向外扩展,直到访问完所有顶点。
  2. 应用场景:

    • 计算图中两个顶点之间的最短路径。
    • 构建图的广度优先树。
  3. 实现步骤:

    • 初始化一个队列和一个标记数组。
    • 将起始顶点加入队列,并标记为已访问。
    • 从队列中取出一个顶点,访问其所有未被访问过的邻接顶点,并将这些邻接顶点加入队列,标记为已访问。
    • 重复上述步骤,直到队列为空。

二、广度优先搜索(BFS)

C++ 代码

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

using namespace std;

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

Java 代码

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class BFS {
    public static void bfs(List<List<Integer>> graph, int start) {
        boolean[] visited = new boolean[graph.size()];
        Queue<Integer> q = new LinkedList<>();
        q.add(start);
        visited[start] = true;
        while (!q.isEmpty()) {
            int vertex = q.poll();
            System.out.print(vertex + " ");
            for (int neighbor : graph.get(vertex)) {
                if (!visited[neighbor]) {
                    visited[neighbor] = true;
                    q.add(neighbor);
                }
            }
        }
    }
}

Go 代码

package main

import "fmt"

func bfs(graph [][]int, start int) {
    visited := make([]bool, len(graph))
    q := []int{start}
    visited[start] = true
    for len(q) > 0 {
        vertex := q[0]
        q = q[1:]
        fmt.Print(vertex, " ")
        for _, neighbor := range graph[vertex] {
            if!visited[neighbor] {
                visited[neighbor] = true
                q = append(q, neighbor)
            }
        }
    }
}

三、迪杰斯特拉算法(Dijkstra's algorithm)

  1. 基本思想:

    • 用于求解图中某一特定顶点到其他各顶点的最短路径。
    • 算法维护一个距离源点距离最短的顶点集合,每次从集合外选择距离源点最近的顶点加入集合,并更新其他顶点到源点的距离。
  2. 应用场景:

    • 网络路由中寻找最短路径。
    • 地理信息系统中计算两点之间的最短距离。
  3. 实现步骤:

    • 初始化一个距离数组,记录源点到每个顶点的距离,初始值为无穷大(除源点外)。
    • 初始化一个标记数组,记录每个顶点是否已加入最短路径集合。
    • 从距离源点最近的未标记顶点开始,更新其邻接顶点到源点的距离。
    • 重复上述步骤,直到所有顶点都被加入最短路径集合。

C++ 代码

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

using namespace std;

typedef pair<int, int> pii;

vector<int> dijkstra(vector<vector<pii>>& graph, int start) {
    int n = graph.size();
    vector<int> dist(n, INT_MAX);
    dist[start] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push({0, start});
    while (!pq.empty()) {
        int u = pq.top().second;
        int d = pq.top().first;
        pq.pop();
        if (d > dist[u]) continue;
        for (auto& edge : graph[u]) {
            int v = edge.first;
            int w = edge.second;
            if (dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                pq.push({dist[v], v});
            }
        }
    }
    return dist;
}

Java 代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;

class Pair implements Comparable<Pair> {
    int vertex;
    int distance;

    public Pair(int vertex, int distance) {
        this.vertex = vertex;
        this.distance = distance;
    }

    @Override
    public int compareTo(Pair other) {
        return Integer.compare(this.distance, other.distance);
    }
}

public class Dijkstra {
    public static int[] dijkstra(List<List<Pair>> graph, int start) {
        int n = graph.size();
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[start] = 0;
        PriorityQueue<Pair> pq = new PriorityQueue<>();
        pq.add(new Pair(start, 0));
        while (!pq.isEmpty()) {
            Pair pair = pq.poll();
            int u = pair.vertex;
            int d = pair.distance;
            if (d > dist[u]) continue;
            for (Pair edge : graph.get(u)) {
                int v = edge.vertex;
                int w = edge.distance;
                if (dist[u] + w < dist[v]) {
                    dist[v] = dist[u] + w;
                    pq.add(new Pair(v, dist[v]));
                }
            }
        }
        return dist;
    }
}

Go 代码

package main

import (
    "container/heap"
    "fmt"
)

type Pair struct {
    vertex   int
    distance int
}

type PQ []Pair

func (pq PQ) Len() int { return len(pq) }

func (pq PQ) Less(i, j int) bool {
    return pq[i].distance < pq[j].distance
}

func (pq PQ) Swap(i, j int) {
    pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PQ) Push(x interface{}) {
    *pq = append(*pq, x.(Pair))
}

func (pq *PQ) Pop() interface{} {
    old := *pq
    n := len(old)
    item := old[n-1]
    *pq = old[0 : n-1]
    return item
}

func dijkstra(graph [][]Pair, start int) []int {
    n := len(graph)
    dist := make([]int, n)
    for i := range dist {
        dist[i] = 1<<63 - 1
    }
    dist[start] = 0
    pq := &PQ{{start, 0}}
    heap.Init(pq)
    for pq.Len() > 0 {
        pair := heap.Pop(pq).(Pair)
        u := pair.vertex
        d := pair.distance
        if d > dist[u] {
            continue
        }
        for _, edge := range graph[u] {
            v := edge.vertex
            w := edge.distance
            if dist[u]+w < dist[v] {
                dist[v] = dist[u] + w
                heap.Push(pq, Pair{v, dist[v]})
            }
        }
    }
    return dist

四、弗洛伊德算法(Floyd-Warshall algorithm)

  1. 基本思想:

    • 用于求解图中任意两个顶点之间的最短路径。
    • 算法通过动态规划的思想,逐步更新任意两个顶点之间经过中间顶点的最短距离。
  2. 应用场景:

    • 交通网络中计算任意两点之间的最短路径。
    • 多源最短路径问题。
  3. 实现步骤:

    • 初始化一个二维距离矩阵,记录图中任意两个顶点之间的直接距离。
    • 依次以每个顶点作为中间顶点,更新任意两个顶点之间的距离。
    • 重复上述步骤,直到所有顶点都作为过中间顶点。

 二、弗洛伊德算法(Floyd-Warshall algorithm)

C++ 代码

#include <iostream>
#include <vector>
#include <climits>

using namespace std;

void floydWarshall(vector<vector<int>>& graph) {
    int n = graph.size();
    for (int k = 0; k < n; k++) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (graph[i][k]!= INT_MAX && graph[k][j]!= INT_MAX && graph[i][k] + graph[k][j] < graph[i][j]) {
                    graph[i][j] = graph[i][k] + graph[k][j];
                }
            }
        }
    }
}

Java 代码

import java.util.Arrays;

public class FloydWarshall {
    public static void floydWarshall(int[][] graph) {
        int n = graph.length;
        for (int k = 0; k < n; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (graph[i][k]!= Integer.MAX_VALUE && graph[k][j]!= Integer.MAX_VALUE && graph[i][k] + graph[k][j] < graph[i][j]) {
                        graph[i][j] = graph[i][k] + graph[k][j];
                    }
                }
            }
        }
    }
}

Go 代码

package main

import "fmt"

func floydWarshall(graph [][]int) {
    n := len(graph)
    for k := 0; k < n; k++ {
        for i := 0; i < n; i++ {
            for j := 0; j < n; j++ {
                if graph[i][k]!= 1<<31-1 && graph[k][j]!= 1<<31-1 && graph[i][k]+graph[k][j] < graph[i][j] {
                    graph[i][j] = graph[i][k] + graph[k][j]
                }
            }
        }
    }
}

五、拓扑排序(Topological Sort)

  1. 基本思想:

    • 对于一个有向无环图(DAG),将图中的顶点按照一定的顺序排列,使得对于任意一条有向边 (u, v),顶点 u 在排序中都位于顶点 v 之前。
  2. 应用场景:

    • 任务调度问题,确保任务按照依赖关系执行。
    • 课程安排问题,确定课程的学习顺序。
  3. 实现步骤:

    • 统计图中每个顶点的入度。
    • 将入度为 0 的顶点加入一个队列。
    • 从队列中取出一个顶点,将其输出,并将其邻接顶点的入度减 1。如果某个邻接顶点的入度变为 0,则将其加入队列。
    • 重复上述步骤,直到队列为空。如果此时图中还有未输出的顶点,则说明图中存在环,无法进行拓扑排序。

C++ 代码

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

using namespace std;

vector<int> topologicalSort(vector<vector<int>>& graph) {
    int n = graph.size();
    vector<int> inDegree(n, 0);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < graph[i].size(); j++) {
            inDegree[graph[i][j]]++;
        }
    }
    queue<int> q;
    for (int i = 0; i < n; i++) {
        if (inDegree[i] == 0) {
            q.push(i);
        }
    }
    vector<int> result;
    while (!q.empty()) {
        int vertex = q.front();
        q.pop();
        result.push_back(vertex);
        for (int i = 0; i < graph[vertex].size(); i++) {
            inDegree[graph[vertex][i]]--;
            if (inDegree[graph[vertex][i]] == 0) {
                q.push(graph[vertex][i]);
            }
        }
    }
    return result;
}

Java 代码

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class TopologicalSort {
    public static List<Integer> topologicalSort(List<List<Integer>> graph) {
        int n = graph.size();
        int[] inDegree = new int[n];
        for (int i = 0; i < n; i++) {
            for (int neighbor : graph.get(i)) {
                inDegree[neighbor]++;
            }
        }
        Queue<Integer> q = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (inDegree[i] == 0) {
                q.add(i);
            }
        }
        List<Integer> result = new ArrayList<>();
        while (!q.isEmpty()) {
            int vertex = q.poll();
            result.add(vertex);
            for (int neighbor : graph.get(vertex)) {
                inDegree[neighbor]--;
                if (inDegree[neighbor] == 0) {
                    q.add(neighbor);
                }
            }
        }
        return result;
    }
}

Go 代码

package main

import "fmt"

func topologicalSort(graph [][]int) []int {
    n := len(graph)
    inDegree := make([]int, n)
    for i := range graph {
        for _, v := range graph[i] {
            inDegree[v]++
        }
    }
    q := []int{}
    for i := range inDegree {
        if inDegree[i] == 0 {
            q = append(q, i)
        }
    }
    result := []int{}
    for len(q) > 0 {
        vertex := q[0]
        q = q[1:]
        result = append(result, vertex)
        for _, neighbor := range graph[vertex] {
            inDegree[neighbor]--
            if inDegree[neighbor] == 0 {
                q = append(q, neighbor)
            }
        }
    }
    return result
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值