数据结构与算法Javascript描述-图(网络)

296 阅读1分钟

图(网路)

图由边的集合及顶点的集合组成。利用图可以对现实中很多系统建模,如交通系统,飞行系统,计算机网络。

图的表示

我们可以使用顶点及到顶点的关系来表示图

0 -> 1
0 -> 2
1 -> 3
2 -> 4

构建图类

class Graph {
    constructor(v) {
        this.vertices = v;
        // 边数组
        this.adj = [];
        this.edges = 0;

        for (let i = 0; i < this.vertices; i++) {
            this.adj[i] = [];
            this.adj[i].push();
        }
    }

    // 添加边
    addEdge(v, w) {
        this.adj[v].push(w);
        this.adj[w].push(v);
        this.edges++;
    }

    // 显示图
    showGraph() {
        for (let i = 0; i < this.vertices; i++) {
            const pre = i + ' > '

            let tail = '';
            for (let j = 0; j < this.vertices; j++) {
                if (this.adj[i].indexOf(j) > -1) {
                    tail += j + ' '
                }
            }

            console.log(pre + tail);
        }
    }
}

搜索图

搜索分为深度优先搜索和广度优先搜索

深度优先搜索


// 数组保存已搜索节点
this.visited = [];

// ···
dfs(v) {
    const adjv = this.adj[v];

    this.visited[v] = true;

    console.log(v);

    if (adjv) {
        for (let i = 0, len = adjv.length; i < len; i++) {
            const w = adjv[i];

            if (!this.visited[w]) {
                this.dfs(w);
            }
        }
    }
}

广度优先搜索

// ···
bfs(v) {
    const queue = [v];

    this.visited[v] = true;
    
    // 利用队列来实现遍历,非递归
    while(queue.length) {
        const v = queue.shift();
        const adjv = this.adj[v];

        console.log(v);

        if (adjv) {
            for (let i = 0, len = adjv.length; i < len; i++) {
                const w = adjv[i];

                if (!this.visited[w]) {
                    queue.push(w)
                    this.visited[w] = true;
                }
            }
        }
    }
}

确定最短路径(无权重)

现实生活中,我们求 A->B 的最短路径(站点最少)时,我们一般会先找 A->B 单边路径,再找双边路径,三边路径等。其实这就是我们图的广度优先搜索,得到B所在层数,再串联路径则是 A->B 的最短路径。

// 广度优先遍历时记录上层节点
this.edgeTo = [];

// ···
bfs(v) {
    const queue = [v];

    this.visited[v] = true;
    
    // 利用队列来实现遍历,非递归
    while(queue.length) {
        const v = queue.shift();
        const adjv = this.adj[v];

        console.log(v);

        if (adjv) {
            for (let i = 0, len = adjv.length; i < len; i++) {
                const w = adjv[i];

                if (!this.visited[w]) {
                    this.edgeTo[w] = v;
                    queue.push(w)
                    this.visited[w] = true;
                }
            }
        }
    }
}

pathTo(source, destination) {
    this.visited = [];
    g.bfs(source);

    if (!this.hasPathTo(destination)) {
        return null;
    }

    const path = [destination];

    while(this.edgeTo[destination] !== source) {
        path.push(this.edgeTo[destination]);
        destination = this.edgeTo[destination];
    }

    path.push(source);

    path.reverse()

    console.log(path.toString());

    return path;
}

hasPathTo(v) {
    return this.visited[v];
}

完整代码

class Graph {
    constructor(v) {
        this.vertices = v;
        this.edges = 0;
        this.visited = [];
        this.adj = [];
        this.edgeTo = [];

        for (let i = 0; i < this.vertices; i++) {
            this.adj[i] = [];
            this.adj[i].push();
        }
    }

    addEdge(v, w) {
        this.adj[v].push(w);
        this.adj[w].push(v);
        this.edges++;
    }

    showGraph() {
        for (let i = 0; i < this.vertices; i++) {
            const pre = i + ' > '

            let tail = '';
            for (let j = 0; j < this.vertices; j++) {
                if (this.adj[i].indexOf(j) > -1) {
                    tail += j + ' '
                }
            }

            console.log(pre + tail);
        }
    }

    dfs(v) {
        this.visited[v] = true;

        console.log(v);

        if (this.adj[v]) {
            for (let i = 0, len = this.adj[v].length; i < len; i++) {
                const w = this.adj[v][i];

                if (!this.visited[w]) {
                    this.dfs(w);
                }
            }
        }
    }

    bfs(v) {
        const queue = [v];

        this.visited[v] = true;

        while(queue.length) {
            const v = queue.shift();

            console.log(v);

            for (let i = 0, len = this.adj[v].length; i < len; i++) {
                const w = this.adj[v][i];

                if (!this.visited[w]) {
                    this.edgeTo[w] = v;
                    queue.push(w)
                    this.visited[w] = true;
                }
            }
        }
    }

    pathTo(source, destination) {
        this.visited = [];
        g.bfs(source);

        if (!this.hasPathTo(destination)) {
            return null;
        }

        const path = [destination];

        while(this.edgeTo[destination] !== source) {
            path.push(this.edgeTo[destination]);
            destination = this.edgeTo[destination];
        }

        path.push(source);

        path.reverse()

        console.log(path.toString());

        return path;
    }

    hasPathTo(v) {
        return this.visited[v];
    }
}

欢迎到前端学习打卡群一起学习~516913974