【JavaScript数据结构】图之邻接矩阵

218 阅读3分钟

一个二维数组,其中每个元素 i, j 表示顶点 i 和顶点 j 之间是否存在一条边。如果顶点 ij 之间存在一条边,则 matrix[i][j] = 1,否则 matrix[i][j] = 0。对于带权边的图,可以将权重存储在矩阵中,而不是仅使用 1 和 0。

优点:

  • 表示稠密图时很直观。
  • 查询两个顶点之间是否存在边的操作是O(1)。

缺点:

  • 对于稀疏图,邻接矩阵可能会浪费很多空间。
  • 需要O(V^2)的空间,其中V是顶点数。

使用邻接矩阵表示图的基本实现,以及一些常见的操作,如添加顶点、添加边、检查两顶点之间是否存在边、打印矩阵等。

使用邻接矩阵表示图:

class GraphWithAdjMatrix {
    /**
     * 初始化图的邻接矩阵表示。
     * @param {number} vertices - 图中的顶点数量。
     */
    constructor(vertices) {
        this.matrix = [];
        for (let i = 0; i < vertices; i++) {
            // 初始化一个二维数组,并将所有值设置为0
            this.matrix[i] = Array(vertices).fill(0);
        }
    }

    /**
     * 添加无向边。
     * @param {number} vertex1 - 边的起点。
     * @param {number} vertex2 - 边的终点。
     */
    addEdge(vertex1, vertex2) {
        // 在两个顶点之间添加一条边
        this.matrix[vertex1][vertex2] = 1;
        this.matrix[vertex2][vertex1] = 1;  // 因为是无向图
    }

    /**
     * 检查两个顶点之间是否存在边。
     * @param {number} vertex1 - 第一个顶点。
     * @param {number} vertex2 - 第二个顶点。
     * @returns {boolean} - 如果两个顶点之间存在边,返回 true,否则返回 false。
     */
    hasEdge(vertex1, vertex2) {
        return this.matrix[vertex1][vertex2] === 1;
    }

    /**
     * 打印整个邻接矩阵。
     */
    printMatrix() {
        for (let i = 0; i < this.matrix.length; i++) {
            console.log(this.matrix[i].join(' '));
        }
    }

    /**
     * 深度优先搜索 (DFS)
     * @param {number} startVertex - 开始搜索的顶点索引。
     */
    dfs(startVertex) {
        // 初始化一个数组来跟踪每个顶点是否被访问过
        const visited = Array(this.matrix.length).fill(false);
        // 使用一个栈来辅助DFS搜索
        const stack = [];

        // 将开始顶点推入栈
        stack.push(startVertex);
        while (stack.length > 0) { // 当栈不为空时,继续搜索
            const currentVertex = stack.pop(); // 取出栈顶的顶点

            if (!visited[currentVertex]) { // 如果该顶点未被访问
                console.log(currentVertex); // 打印顶点
                visited[currentVertex] = true; // 标记为已访问

                // 检查当前顶点的所有邻接顶点
                for (let i = 0; i < this.matrix.length; i++) {
                    // 如果找到一个邻接点且该邻接点未被访问
                    if (this.matrix[currentVertex][i] === 1 && !visited[i]) {
                        stack.push(i); // 将该邻接点推入栈以便后续访问
                    }
                }
            }
        }
    }

    /**
     * 广度优先搜索 (BFS)
     * @param {number} startVertex - 开始搜索的顶点索引。
     */
    bfs(startVertex) {
        // 初始化一个数组来跟踪每个顶点是否被访问过
        const visited = Array(this.matrix.length).fill(false);
        // 使用一个队列来辅助BFS搜索
        const queue = [];

        // 将开始顶点加入队列并标记为已访问
        queue.push(startVertex);
        visited[startVertex] = true;

        while (queue.length > 0) { // 当队列不为空时,继续搜索
            const currentVertex = queue.shift(); // 取出队列前部的顶点
            console.log(currentVertex); // 打印顶点

            // 检查当前顶点的所有邻接顶点
            for (let i = 0; i < this.matrix.length; i++) {
                // 如果找到一个邻接点且该邻接点未被访问
                if (this.matrix[currentVertex][i] === 1 && !visited[i]) {
                    queue.push(i); // 将该邻接点加入队列以便后续访问
                    visited[i] = true; // 标记为已访问
                }
            }
        }
    }
    
}

示例:

const graphMatrix = new GraphWithAdjMatrix(4);
graphMatrix.addEdge(0, 1);
graphMatrix.addEdge(0, 2);
graphMatrix.addEdge(1, 2);

console.log(graphMatrix.hasEdge(0, 1)); // 输出:true
console.log(graphMatrix.hasEdge(1, 3)); // 输出:false
graphMatrix.printMatrix();