js实现最短路径求解,简单易懂

19 篇文章 1 订阅
4 篇文章 0 订阅

简介

网上看到很多最短路径求解问题的js实现版本,看了老半天,没怎么看懂。
看懂了我也复现不了。+_+!
所以自己写了个简单易懂的,小白容易看懂
至于大佬,,,,觉得写的不好你来打我咯。。。

别看代码长,一大半是测试代码

题目

  1. 已知图如下,所有线段可以来回走,求 A 到 G 最短路线
    在这里插入图片描述
  2. 已知图如下,所有线段可以来回走,求 A 到 K 最短路线在这里插入图片描述

es6实现

  1. 如果有多个长度相同的最短路径,只输出第一个最短路径
class Graph {
  constructor(nodes) {
    this.nodes = nodes;//保存所有节点
    this.line = {};//保存所有节点关系
    this.res = [];//最短路径结果
    this.hasRes = false;//是否 至少有一个可以到达的路径
  }

  addLine(v, w) {
    this._addLine(v, w);
    this._addLine(w, v);
  }

  _addLine(v, w) {
    !this.line[v] && (this.line[v] = []);
    this.line[v].push(w);
  }

  minPath(v, w) {
    this.step(this.line[v], [v], w);
    return this.res;
  }

  step(adjacentNodes, tempRes, w) {
    //当前节点没有相邻节点
    if (!adjacentNodes) {
      return;
    }
    //存在可以到达的路径,并且比正在探测的路径短则直接退出探测
    if (this.hasRes && this.res.length < tempRes.length) {
      return;
    }
    adjacentNodes.forEach(item => {
      //当前探测的点已经走过了,不再重复走
      if (tempRes.indexOf(item) !== -1) {
        return;
      }
      let newTempRes = tempRes.concat(item);
      //到达终点
      if (item === w) {
        if (this.hasRes) {
          if (newTempRes.length < this.res.length) {
            //已有最短路径,且比当前路径更短,替换
            this.res = newTempRes;
          }
        } else {
          //目前没有最短路径,替换
          this.res = newTempRes;
          this.hasRes = true;
        }
      } else {
        this.step(this.line[item], newTempRes, w);
      }
    });
  }

  toString() {
    console.log("数据结构:");
    console.log(this.nodes);
    console.log("===================");
    console.log(this.line);
  }
}
//测试
let graph = new Graph(["A", "B", "C", "D", "E", "F", "G", "H"]);
graph.addLine("A", "C");
graph.addLine("B", "A");
graph.addLine("B", "H");
graph.addLine("B", "C");
graph.addLine("F", "H");
graph.addLine("B", "E");
graph.addLine("E", "H");
graph.addLine("C", "D");
graph.addLine("D", "E");
graph.addLine("G", "E");
graph.addLine("E", "C");
graph.addLine("E", "F");
graph.addLine("G", "F");

graph.toString();

console.log("结果:");
console.log(graph.minPath("A", "G")); //[ 'A', 'C', 'E', 'G' ]


let graph1 = new Graph(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]);
graph1.addLine("A", "B");
graph1.addLine("A", "C");
graph1.addLine("H", "A");
graph1.addLine("D", "A");
graph1.addLine("B", "C");
graph1.addLine("E", "B");
graph1.addLine("B", "F");
graph1.addLine("D", "G");
graph1.addLine("J", "K");
graph1.addLine("F", "L");
graph1.addLine("E", "I");
graph1.addLine("E", "F");
graph1.addLine("C", "D");
graph1.addLine("C", "F");
graph1.addLine("F", "G");
graph1.addLine("K", "L");
graph1.addLine("G", "H");
graph1.addLine("G", "L");
graph1.addLine("I", "J");

graph1.toString();

console.log("结果:");
console.log(graph1.minPath("A", "K")); //[ 'A', 'B', 'F', 'L', 'K' ]
  1. 如果有多个长度相同的最短路径,输出所有最短路径
class Graph {
  constructor(nodes) {
    this.nodes = nodes;//保存所有节点
    this.line = {};//保存所有节点关系
    this.res = [];//最短路径结果
    this.hasRes = false;//是否 至少有一个可以到达的路径
  }
  addLine(v, w) {
    this._addLine(v, w);
    this._addLine(w, v);
  }
  _addLine(v, w) {
    !this.line[v] && (this.line[v] = []);
    this.line[v].push(w);
  }
  minPath(v, w) {
    this.step(this.line[v], [v], w);
    return this.res;
  }
  step(adjacentNodes, tempRes, w) {
    //当前节点没有相邻节点
    if (!adjacentNodes) {
      return;
    }
    //存在可以到达的路径,并且比正在探测的路径短则直接退出探测
    if (this.hasRes && this.res[0].length < tempRes.length) {
      return;
    }
    adjacentNodes.forEach(item => {
      //当前探测的点已经走过了,不再重复走
      if (tempRes.indexOf(item) !== -1) {
        return;
      }
      let newTempRes = tempRes.concat(item);
      //到达终点
      if (item === w) {
        if (this.hasRes) {
          if (newTempRes.length < this.res[0].length) {
            //已有最短路径,且比当前路径更短,替换
            this.res = [newTempRes];
          }else if(newTempRes.length == this.res[0].length){
            //已有最短路径,且长度相同,添加
            this.res.push(newTempRes);
          }
        } else {
          //目前没有最短路径,替换
          this.res = [newTempRes];
          this.hasRes = true;
        }
      } else {
        this.step(this.line[item], newTempRes, w);
      }
    });
  }
  toString() {
    console.log("数据结构:");
    console.log(this.nodes);
    console.log("===================");
    console.log(this.line);
  }
}
//测试
let graph = new Graph(["A", "B", "C", "D", "E", "F", "G", "H"]);
graph.addLine("A", "C");
graph.addLine("B", "A");
graph.addLine("B", "H");
graph.addLine("B", "C");
graph.addLine("F", "H");
graph.addLine("B", "E");
graph.addLine("E", "H");
graph.addLine("C", "D");
graph.addLine("D", "E");
graph.addLine("G", "E");
graph.addLine("E", "C");
graph.addLine("E", "F");
graph.addLine("G", "F");

graph.toString();

console.log("结果:");
console.log(graph.minPath("A", "G"));
// [ [ 'A', 'C', 'E', 'G' ], [ 'A', 'B', 'E', 'G' ] ]


let graph1 = new Graph(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]);
graph1.addLine("A", "B");
graph1.addLine("A", "C");
graph1.addLine("H", "A");
graph1.addLine("D", "A");
graph1.addLine("B", "C");
graph1.addLine("E", "B");
graph1.addLine("B", "F");
graph1.addLine("D", "G");
graph1.addLine("J", "K");
graph1.addLine("F", "L");
graph1.addLine("E", "I");
graph1.addLine("E", "F");
graph1.addLine("C", "D");
graph1.addLine("C", "F");
graph1.addLine("F", "G");
graph1.addLine("K", "L");
graph1.addLine("G", "H");
graph1.addLine("G", "L");
graph1.addLine("I", "J");

graph1.toString();

console.log("结果:");
console.log(graph1.minPath("A", "K"));
// [ [ 'A', 'B', 'F', 'L', 'K' ],
//   [ 'A', 'C', 'F', 'L', 'K' ],
//   [ 'A', 'H', 'G', 'L', 'K' ],
//   [ 'A', 'D', 'G', 'L', 'K' ] ]
  1. 单向图
  addLine(v, w) {
    this._addLine(v, w);
    // this._addLine(w, v);//只需要将这一行注释掉就是单向图的实现。
    // 注:当前测试用例单向图没有合法路径
  }

写完了, 就酱~
点个赞再走咯 +_+

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值