构建图:

1、添加顶点:用数组存储图中所有顶点的名字

this.addVertex = function(v) {
        vertices.push(v);
        adjList[v] = [];
    }

2、添加边 :用对象的形式存储每个顶点包含的边

this.addEdge = function(a,b) {
        adjList[a].push(b);
        adjList[b].push(a);
    }

功能:

1、打印

this.print= function() {
        let s = '\n';
        for(let i=0; i<vertices.length; i++) {
            let dingdian = vertices[i];
            s += dingdian + '=>';
            let bian = adjList[dingdian];
            for(let j=0; j<bian.length; j++) {
                s += bian[j];
            }
            s += '\n';
        }
        console.log(s);
    }  

2、广度优先遍历(采用队列数据结构)

let initColor = function() {
       let color = [];
       for(let i=1; i<vertices.length; i++) {
           color[vertices[i]] = 'white';
       }
       return color;
    };
    //广度优先遍历(采用队列数据结构)
    this.bfs = function(v,callback) {
        let color = initColor();
        let queue = new Queue;
        queue.enqueue(v);

        while(!queue.isEmpty()) {
            let now = queue.dequeue();
            let bian = adjList[now];
            for(let i=0; i<bian.length; i++) {
                let w = bian[i];
                if(color[w] === 'white') {
                    //未发现的全部入列,并且标识为已发现
                    color[w] = 'grey';
                    queue.enqueue(w);
                }
            }
            color[now] = 'black';
            if(callback) {
                callback(now);
            }
        }  
    };

3、深度优先遍历

 this.dfs = function(v,callback) {
        let color = initColor();   //初始化颜色
        dfsVisite(v,color,callback);
    }

    let dfsVisite = function(u,color,callback) {
        color[u] = 'grey';
        let n = adjList[u];
        for(let i=0; i<n.length; i++) {
            let w = n[i];
            if(color[w] == 'white') {
                dfsVisite(w,color,callback);
            }
        }
        color[u] = 'black'; 

        if(callback) {
            callback(u);
        }
    };

构建函数:

1、基于广度优先的最短路径生成算法

let  zuiduan = function(from,to){
    let v  = to; //设置当前点
    let s = g.BFS(from);
    let path = new Stack();
    while(v !== from) {
        path.push(v);
        v = s.pred[v];
    }
    path.push(v);
    let str = '';
    while(!path.isEmpty()) {
        str += path.pop() + '-';
    }
    str = str.slice(0,str.length-1);
    console.log(str);
}

全部整体代码

//栈
let Stack = function() {
    let items = [];
    //添加元素
    this.push = function(element) {
        items.push(element);
    };
    //删除元素
    this.pop = function() {
        return items.pop();
    };
    //查看栈顶元素
    this.peek = function() {
        return items[items.lenght -1];
    };
    //检查栈是否为空
    this.isEmpty = function() {
        return  items.length == 0;
    } 
    //栈的长度
    this.size = function() {
        return items.length;
    }
    //清空栈
    this.clear = function() {
        items = [];
    }
    //打印栈元素
    this.print = function() {
        console.log(items.toString());
    }
};

//队列
let Queue= function() {
    let items = [];
    //入队
    this.enqueue = function(element) {
        items.push(element);
    };
    //出队
    this.dequeue = function() {
        return items.shift();
    };
    //查看队列头
    this.front = function() {
        return items[0];
    };
    //检查队列是否为空
    this.isEmpty = function() {
        return items.length === 0;
    };
    //队列大小
    this.size = function() {
        return items.length;
    };
};

//图
let Graph = function() {
    //顶点(用数组存储图中所有顶点的名字)
    let vertices = [];
    //边(用对象的形式存储每个顶点包含的边)
    let adjList = {};

    //1、添加顶点
    this.addVertex = function(v) {
        vertices.push(v);
        adjList[v] = [];
    }

    //2、添加边
    this.addEdge = function(a,b) {
        adjList[a].push(b);
        adjList[b].push(a);
    }

    //打印
    this.print= function() {
        let s = '\n';
        for(let i=0; i<vertices.length; i++) {
            let dingdian = vertices[i];
            s += dingdian + '=>';
            let bian = adjList[dingdian];
            for(let j=0; j<bian.length; j++) {
                s += bian[j];
            }
            s += '\n';
        }
        console.log(s);
    }  
    
    /*
    广度优先遍历:
    white 未发现
    grey  已发现未探索
    black 已探索
    */
    //初始化颜色
    let initColor = function() {
       let color = [];
       for(let i=1; i<vertices.length; i++) {
           color[vertices[i]] = 'white';
       }
       return color;
    };
    //广度优先遍历(采用队列数据结构)
    this.bfs = function(v,callback) {
        let color = initColor();
        let queue = new Queue;
        queue.enqueue(v);

        while(!queue.isEmpty()) {
            let now = queue.dequeue();
            let bian = adjList[now];
            for(let i=0; i<bian.length; i++) {
                let w = bian[i];
                if(color[w] === 'white') {
                    //未发现的全部入列,并且标识为已发现
                    color[w] = 'grey';
                    queue.enqueue(w);
                }
            }
            color[now] = 'black';
            if(callback) {
                callback(now);
            }
        }  
    };
    
    //广度优先算法(d:距离    prev:回溯点)
    this.BFS = function(v) {
        let color = initColor();
        let queue = new Queue;
        queue.enqueue(v);
        //初始化
        let d = {};
        let pred = {};
        for(let i=0; i<vertices.length; i++) {
            d[vertices[i]] = 0;
            pred[vertices[i]] = null;
        }

        while(!queue.isEmpty()) {
            let now = queue.dequeue();
            let bian = adjList[now];
            for(let i=0; i<bian.length; i++) {
                let w = bian[i];
                if(color[w] === 'white') {
                    color[w] = 'grey';//未发现的全部入列,并且标识为已发现

                    //设置回溯点
                    pred[w] = now;
                    d[w] = d[now] + 1;

                    queue.enqueue(w);
                }
            }
            color[now] = 'black';
        }  
        return {
            pred : pred,
            d : d
        };
    };
    
    //深度优先算法
    this.dfs = function(v,callback) {
        let color = initColor();   //初始化颜色
        dfsVisite(v,color,callback);
    }

    let dfsVisite = function(u,color,callback) {
        color[u] = 'grey';
        let n = adjList[u];
        for(let i=0; i<n.length; i++) {
            let w = n[i];
            if(color[w] == 'white') {
                dfsVisite(w,color,callback);
            }
        }
        color[u] = 'black'; 

        if(callback) {
            callback(u);
        }
    };
};

//广度优先算法解决最短路径问题 (保证每个点的回溯点是最短的)
let  zuiduan = function(from,to){
    let v  = to; //设置当前点
    let s = g.BFS(from);
    let path = new Stack();
    while(v !== from) {
        path.push(v);
        v = s.pred[v];
    }
    path.push(v);
    let str = '';
    while(!path.isEmpty()) {
        str += path.pop() + '-';
    }
    str = str.slice(0,str.length-1);
    console.log(str);
}

结果测试

let g =new Graph;
g.addVertex('A');
g.addVertex('B');
g.addVertex('C');
g.addVertex('D');
g.addVertex('E');
g.addVertex('F');

g.addEdge('A','B');
g.addEdge('A','C');
g.addEdge('A','D');
g.addEdge('C','D');
g.addEdge('B','E');
g.addEdge('F','B');

g.print();  //A=>BCD  B=>AEF  C=>AD  D=>AC  E=>B  F=>B
g.bfs('A', function(e) {console.log(e)}); //A B C D E F
g.BFS('A');   //d:{A:0, B:1, C:1, D:1, E:2} pred:{A:null, B:"A", C:"A", D:"A", E:"B"}
g.dfs('A',function(e){console.log(e);}); //E F B D C A
zuiduan('A','E')   //A-B-F

皮卡丘丘丘
50 声望12 粉丝

不忘初心方得始终,念念不忘必有回响