树(父子关系的节点集合)
二叉树(最多只有两个子节点)
数组(随机访问,顺序存储)
字典Map (键值对)
交通网络
通信网络
class Graph {
  constructor(isDirected = false) {
    this.isDirected = isDirected;
    this.vertices = []; //顶点列表
    this.adjList = new Map(); //顶点表示键,邻接顶点列表表示值
  }
}
addVertex(v) {
    if (!this.vertices.includes(v)) {
      this.vertices.push(v);
      //将新加顶点的邻接顶点列表初始为空数组
      this.adjList.set(v, []); 
    }
}
addEdge(a, b) {
    if (!this.adjList.get(a)) {
      this.addVertex(a);
    }
    if (!this.adjList.get(b)) {
      this.addVertex(b);
    }
    this.adjList.get(a).push(b);
    if (this.isDirected !== true) {
      this.adjList.get(b).push(a);
    }
}
getVertices() {
    return this.vertices;
}
getAdjList() {
    return this.adjList;
}
toString() {
    let s = '';
    for (let i = 0; i < this.vertices.length; i++) {
      s += `${this.vertices[i]} -> `;
      const neighbors = this.adjList.get(this.vertices[i]);
      for (let j = 0; j < neighbors.length; j++) {
        s += `${neighbors[j]} `;
      }
      s += '\n';
    }
    return s;
}
const graph = new Graph();
const myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
for (let i = 0; i < myVertices.length; i++) {
   graph.addVertex(myVertices[i]);
}
graph.addEdge('A', 'B');
graph.addEdge('A', 'C'); 
graph.addEdge('A', 'D'); 
graph.addEdge('C', 'D'); 
graph.addEdge('C', 'G'); 
graph.addEdge('D', 'G'); 
graph.addEdge('D', 'H'); 
graph.addEdge('B', 'E'); 
graph.addEdge('B', 'F'); 
graph.addEdge('E', 'I');
console.log(graph.toString());
| 广度优先搜索 | 队列 | 将顶点存入队列,最先入队列的顶点先被探索 | 
| 深度优先搜索 | 栈 | 将顶点存入栈,顶点是沿着路径被探索的,存在新的相邻顶点就去访问 | 
const Colors = {   
    WHITE: 0,   
    GREY: 1,   
    BLACK: 2 
}; 
const initializeColor = vertices => {   
    const color = {};   
    for (let i = 0; i < vertices.length; i++) {     
        color[vertices[i]] = Colors.WHITE;   
    }   
    return color; 
}; 
const breadthFirstSearch = (graph, startVertex, callback) => {  
    const vertices = graph.getVertices();   
    const adjList = graph.getAdjList();   
    const color = initializeColor(vertices);
    const queue = new Queue();
    queue.enqueue(startVertex);
    while (!queue.isEmpty()) {
        const u = queue.dequeue();
        const neighbors = adjList.get(u);
        color[u] = Colors.GREY;
        for (let i = 0; i < neighbors.length; i++){
            const w = neighbors[i];
            if(color[w] === Colors.WHITE) {
                color[w] = Colors.GREY;
                queue.enqueue(w);
            }
        }
        color[u] = Colors.BLACK;
        if (callback) {       
            callback(u);     
        } 
    }
}    
const printVertex = (value) => console.log('Visited vertex: ' + value);
breadthFirstSearch(graph, myVertices[0], printVertex); 
const depthFirstSearch = (graph, callback) => {
    const vertices = graph.getVertices();
    const adjList = graph.getAdjList();
    const color = initializeColor(vertices);
    for (let i = 0; i < vertices.length; i++) { // {2}
        if (color[vertices[i]] === Colors.WHITE) { // {3}
            depthFirstSearchVisit(vertices[i], color, adjList, callback); // {4}
        }
    }
};
const depthFirstSearchVisit = (u, color, adjList, callback) => {
    color[u] = Colors.GREY; // {5}
    if (callback) { // {6}
        callback(u);
    }
    const neighbors = adjList.get(u); // {7}
    for (let i = 0; i < neighbors.length; i++) { // {8}
        const w = neighbors[i]; // {9}
        if (color[w] === Colors.WHITE) { // {10}
            depthFirstSearchVisit(w, color, adjList, callback); // {11}
        }
    }
    color[u] = Colors.BLACK; // {12}
};
depthFirstSearch(graph, printVertex);
用邻接表创建下图,并分别用BFS和DFS两种方法遍历下图。
var graph = [
[0, 2, 4, 0, 0, 0],
[2, 0, 2, 4, 2, 0],
[4, 2, 0, 0, 3, 0],
[0, 4, 0, 0, 3, 2],
[0, 2, 3, 3, 0, 2],
[0, 0, 0, 2, 2, 0]];
const INF = Number.MAX_SAFE_INTEGER;
const kruskal = graph => {
    const { length } = graph; //邻接矩阵
    const parent = [];//生成树,父子结点,边
    let ne = 0;
    let a; let b; let u; let v;
    const cost = initializeCost(graph); //复制邻接矩阵
    while (ne < length - 1) { // 找n-1条边
        //在cost矩阵中找权值最小的边
        for (let i = 0, min = INF; i < length; i++) {
            for (let j = 0; j < length; j++) {
                if (cost[i][j] < min) {
                    min = cost[i][j];
                    a = u = i;
                    b = v = j;
                }
            }
        }
        //判断最小权值边的两个顶点是否属于同一棵树,有相同的根结点
        //找u的根结点
        u = find(u, parent); 
        //找v的根结点
        v = find(v, parent); 
        //如果u,v根结点不相同,则该边加入最小生成树
        if (union(u, v, parent)) {
            ne++;
        }
        cost[a][b] = cost[b][a] = INF; //去除该边
    }
    return parent;
}
//复制矩阵
const initializeCost = (graph) => {
    let ret = [];
    for(let i = 0; i < graph.length; i++){
        ret[i] = [];
        for(let j = 0; j < graph[i].length; j++){
            ret[i][j] = graph[i][j];
        }
    }
    return ret;
}
//找根结点
const find = (i, parent) => {   
    while (parent[i]) {     
        i = parent[i];   
    }   
    return i; 
};
//判断两个顶点是否属于同一棵树
const union = (i, j, parent) => {
    if (i !== j) {
        parent[j] = i; //i作为j的父结点
        return true;
    }
    return false;
};
const INF = Number.MAX_SAFE_INTEGER;
const prim = graph => {
    const parent = []; //每个顶点的父结点
    const key = []; //最短边的权值
    const visited = []; //访问过顶点设置为true
    const { length } = graph; //顶点数
    //初始化
    for (let i = 0; i < length; i++) {
        key[i] = INF;
        visited[i] = false;
    }
    //开始顶点
    key[0] = 0;
    parent[0] = -1;
    //找所有的顶点
    for (let i = 0; i < length; i++) { 
        //找到key最小结点索引
        const u = minKey(key, visited); 
        visited[u] = true; 
        for (let v = 0; v < length; v++) {
            if (graph[u][v] && !visited[v] && graph[u][v] < key[v]) { // {6}
                //设置v的父结点
                parent[v] = u; 
                //更新v的权值
                key[v] = graph[u][v]; 
            }
        }
    }
    return parent; 
};
//找key且对应的visited为flase的最小值索引
const minKey = (key, visited) => {
    let min = INF;
    let minIndex = -1;
    for (let v = 0; v < key.length; v++) {
        if (visited[v] === false && key[v] <= min) {
            min = key[v];
            minIndex = v;
        }   
    }
    return minIndex;
};
var graph = [
[0, 2, 4, 0, 0, 0],
[0, 0, 2, 4, 2, 0],
[0, 0, 0, 0, 3, 0],
[0, 0, 0, 0, 0, 2],
[0, 0, 0, 3, 0, 2],
[0, 0, 0, 0, 0, 0]];
$$ dist[j] = Min\{dist[i]\} $$ dist[j] + arcs[j][k] < disk[k]时 $$ dist[k] = dist[j] + arcs[j][k] $$
const INF = Number.MAX_SAFE_INTEGER;
const dijkstra = (graph, src) => {
    const dist = []; //dist[i]存储src到i的最短路径的长度
    const visited = [];//设置访问过顶点为true
    const { length } = graph;//顶点数
    //初始化
    for (let i = 0; i < length; i++) { 
        dist[i] = INF;
        visited[i] = false;
    }
    //源点
    dist[src] = 0; 
    for (let i = 0; i < length - 1; i++) { 
        const u = minDistance(dist, visited);
        visited[u] = true;
        for (let v = 0; v < length; v++) {
            if (!visited[v] &&
            graph[u][v] !== 0 &&
            dist[u] !== INF &&
            dist[u] + graph[u][v] < dist[v]) { 
                dist[v] = dist[u] + graph[u][v]; 
            }
        }
    }
    return dist;
};
const minDistance = (dist, visited) => {
    let min = INF;
    let minIndex = -1;
    for (let v = 0; v < dist.length; v++) {
        if (visited[v] === false && dist[v] <= min) {
            min = dist[v];
            minIndex = v;
        }
    }
    return minIndex;
};
const floyd = graph => {
    const dist = [];
    const { length } = graph;
    for (let i = 0; i < length; i++) {
        dist[i] = [];
        for (let j = 0; j < length; j++) {
            if (i === j) {
                dist[i][j] = 0; 
            } else if ((graph[i][j] === 0) && (i !== j)) {
                dist[i][j] = Infinity; 
            } else {
                dist[i][j] = graph[i][j]; 
            }   
        }
    }
    for (let k = 0; k < length; k++) { 
        for (let i = 0; i < length; i++) {
            for (let j = 0; j < length; j++) {
                if (dist[i][k] + dist[k][j] < dist[i][j]) { // {6}
                    dist[i][j] = dist[i][k] + dist[k][j]; // {7}
                }
            }
        }
    }
    return dist;
};