首先是vertex 和edge:

class Vertex {
public:
    int id;
    std::vector<Vertex*> neighbors;
};

储存图

邻接表和邻接矩阵

// 邻接表
// graph[x] 存储 x 的所有邻居节点
vector<vector<int>> graph;

// 邻接矩阵
// matrix[x][y] 记录 x 是否有一条指向 y 的边
vector<vector<bool>> matrix;

注意分析两种存储方式的空间复杂度,对于一幅有 V 个节点,E 条边的图,邻接表的空间复杂度是 O(V+E),而邻接矩阵的空间复杂度是 O(V2)。

DFS遍历图:

// 遍历图的所有节点
void traverse(const Graph& graph, int s, std::vector<bool>& visited) {
    // base case
    if (s < 0 || s >= graph.size()) {
        return;
    }
    if (visited[s]) {
        // 防止死循环
        return;
    }
    // 前序位置
    visited[s] = true;
    std::cout << "visit " << s << std::endl;
    for (const Graph::Edge& e : graph.neighbors(s)) {
        traverse(graph, e.to, visited);
    }
    // 后序位置

}

所以如果一幅图的 E 远小于 V^2(稀疏图),那么邻接表会比邻接矩阵节省空间,反之,如果 E 接近 V^2(稠密图),二者就差不多了

有向加权图

有向加权图怎么实现?很简单呀:

  • 如果是邻接表,我们不仅仅存储某个节点 x 的所有邻居节点,还存储 x 到每个邻居的权重,不就实现加权有向图了吗?

  • 如果是邻接矩阵,matrix[x][y] 不再是布尔值,而是一个 int 值,0 表示没有连接,其他值表示权重。

    // 邻接表
    // graph[x] 存储 x 的所有邻居节点以及对应的权重
    // 具体实现不一定非得这样,可以参考后面的通用实现
    struct Edge {
    int to;
    int weight;
    };

    vector<vector> graph;

    // 邻接矩阵
    // matrix[x][y] 记录 x 指向 y 的边的权重,0 表示不相邻
    vector<vector> matrix;