• ES6的JavaScript数据结构实现之图


    目的:ES6标准下的JS数据结构的一些实现代码。(作为记录和启发)

    内容:图,图的遍历(广度优先搜索BFS,深度优先搜索DFS),最短路径算法,最小生成树算法。(未完成,待继续)

    所有源码在我的Github上(如果觉得不错记得给星鼓励我哦):ES6的JavaScript数据结构实现之图

    一、基础数据结构

    1、图(创建Graph类)

      1 // import dictionary
      2 class ValuePair {
      3   constructor(key, value) {
      4     this.key = key;
      5     this.value = value;
      6   }
      7 
      8   toString() {
      9     return `[#${this.key}: ${this.value}]`;
     10   }
     11 }
     12 
     13 function defaultToString(item) {
     14   if (item === null) {
     15     return 'NULL';
     16   } if (item === undefined) {
     17     return 'UNDEFINED';
     18   } if (typeof item === 'string' || item instanceof String) {
     19     return `${item}`;
     20   }
     21   return item.toString();
     22 }
     23 
     24 class Dictionary {
     25   constructor(toStrFn = defaultToString) {
     26     this.toStrFn = toStrFn;
     27     this.table = {};
     28   }
     29   hasKey(key) {
     30     return this.table[this.toStrFn(key)] != null;
     31   }
     32   set(key, value) {
     33     if (key != null && value != null) {
     34       const tableKey = this.toStrFn(key);
     35       this.table[tableKey] = new ValuePair(key,value);
     36       return true;
     37     }
     38     return false;
     39   }
     40   remove(key) {
     41     if (this.hasKey(key)) {
     42       delete this.table[this.toStrFn(key)];
     43       return true;
     44     }
     45     return false;
     46   }
     47   get(key) {
     48     const valuePair = this.table[this.toStrFn(key)];
     49     return valuePair == null ? undefined : valuePair.value;
     50   }
     51   keyValues() {
     52     return Object.values(this.table);
     53   }
     54   values() {
     55     return this.keyValues().map(valuePair => valuePair.value);
     56   }
     57 
     58   keys() {
     59     return this.keyValues().map(valuePair => valuePair.key);
     60   }
     61   forEach(callbackFn) {
     62     const valuePairs = this.keyValues();
     63     for (let i = 0; i < valuePairs.length; i++) {
     64       const result = callbackFn(valuePairs[i].key, valuePairs[i].value);
     65       if (result === false) {
     66         break;
     67       }
     68     }
     69   }
     70 
     71     isEmpty() {
     72     return this.size() === 0;
     73   }
     74 
     75   size() {
     76     return Object.keys(this.table).length;
     77   }
     78 
     79   clear() {
     80     this.table = {};
     81   }
     82 
     83   toString() {
     84     if (this.isEmpty()) {
     85       return '';
     86     }
     87     const valuePairs = this.keyValues();
     88     let objString = `${valuePairs[0].toString()}`;
     89     for (let i = 1; i < valuePairs.length; i++) {
     90       objString = `${objString},${valuePairs[i].toString()}`;
     91     }
     92     return objString;
     93   }
     94 
     95 
     96 }
     97 
     98 class Graph {
     99   constructor (isDirected = false) {
    100     this.isDirected = isDirected;
    101     this.vertices = [];
    102     this.adjList = new Dictionary();
    103   }
    104   addVertex(v) {
    105     if (!this.vertices.includes(v)) {
    106       this.vertices.push(v);
    107       this.adjList.set(v, []);
    108     }
    109   }
    110   addEdge(a, b ) {
    111     if (!this.adjList.get(a)) {
    112       this.addVertex(a);
    113     }
    114     if (!this.adjList.get(b)) {
    115       this.adjList(b);
    116     }
    117     this.adjList.get(a).push(b);
    118     if (this.isDirected !== true) {
    119       this.adjList.get(b).push(a);
    120     }
    121   }
    122   getVertices() {
    123     return this.vertices;
    124   }
    125   getAdjList() {
    126      return this.adjList;
    127   }
    128   toString() {
    129     let s = '';
    130     for (let i = 0; i < this.vertices.length; i++) {
    131       s += `${this.vertices[i]} -> `;
    132       const neighbors = this.adjList.get(this.vertices[i]);
    133       for (let j = 0; j < neighbors.length; j++) {
    134         s +=`${neighbors[j]} `;
    135       }
    136       s += '
    ';
    137     }
    138     return s;
    139   }
    140 
    141 }
    142 
    143 
    144 const graph = new Graph();
    145 const myVertices = ['A','B','C','D','E','F','G','H','I'];
    146 for (let i = 0; i < myVertices.length; i++) {
    147   graph.addVertex(myVertices[i]);
    148 }
    149 graph.addEdge('A','B');
    150 graph.addEdge('A','C');
    151 graph.addEdge('A', 'D');
    152 graph.addEdge('C', 'D');
    153 graph.addEdge('C', 'G');
    154 graph.addEdge('D', 'G');
    155 graph.addEdge('D', 'H');
    156 graph.addEdge('B', 'E');
    157 graph.addEdge('B', 'F');
    158 graph.addEdge('E', 'I');
    159 console.log(graph.toString());
    Graph

    二、简单应用

     1、图的遍历

     1.1 广度优先搜索(算法工作原理实现;使用BFS寻找最短路径)

    概念:广度优先搜索算法会从指定的第一个顶点开始遍历图,先访问其所有的邻点(相邻顶点),就像一次访问图的一层(先宽后深地访问顶点)。使用BFS寻找最短路径(给定一个图G和源顶点v,找出每个顶点u和v之间最短路径的距离(以边的数量计))。

    注:在上面的最短路径算法中,图不是加权的。如果要计算加权图中的最短路径,广度优先搜索未必合适,要考虑使用Dijkstra算法、Floyd-Warshell算法、Bellman-Ford算法、A*搜索算法(前两者的实现在本博客的最后)。

      1 // import dictionary
      2 class ValuePair {
      3   constructor(key, value) {
      4     this.key = key;
      5     this.value = value;
      6   }
      7 
      8   toString() {
      9     return `[#${this.key}: ${this.value}]`;
     10   }
     11 }
     12 
     13 function defaultToString(item) {
     14   if (item === null) {
     15     return 'NULL';
     16   } if (item === undefined) {
     17     return 'UNDEFINED';
     18   } if (typeof item === 'string' || item instanceof String) {
     19     return `${item}`;
     20   }
     21   return item.toString();
     22 }
     23 
     24 class Dictionary {
     25   constructor(toStrFn = defaultToString) {
     26     this.toStrFn = toStrFn;
     27     this.table = {};
     28   }
     29   hasKey(key) {
     30     return this.table[this.toStrFn(key)] != null;
     31   }
     32   set(key, value) {
     33     if (key != null && value != null) {
     34       const tableKey = this.toStrFn(key);
     35       this.table[tableKey] = new ValuePair(key,value);
     36       return true;
     37     }
     38     return false;
     39   }
     40   remove(key) {
     41     if (this.hasKey(key)) {
     42       delete this.table[this.toStrFn(key)];
     43       return true;
     44     }
     45     return false;
     46   }
     47   get(key) {
     48     const valuePair = this.table[this.toStrFn(key)];
     49     return valuePair == null ? undefined : valuePair.value;
     50   }
     51   keyValues() {
     52     return Object.values(this.table);
     53   }
     54   values() {
     55     return this.keyValues().map(valuePair => valuePair.value);
     56   }
     57 
     58   keys() {
     59     return this.keyValues().map(valuePair => valuePair.key);
     60   }
     61   forEach(callbackFn) {
     62     const valuePairs = this.keyValues();
     63     for (let i = 0; i < valuePairs.length; i++) {
     64       const result = callbackFn(valuePairs[i].key, valuePairs[i].value);
     65       if (result === false) {
     66         break;
     67       }
     68     }
     69   }
     70 
     71     isEmpty() {
     72     return this.size() === 0;
     73   }
     74 
     75   size() {
     76     return Object.keys(this.table).length;
     77   }
     78 
     79   clear() {
     80     this.table = {};
     81   }
     82 
     83   toString() {
     84     if (this.isEmpty()) {
     85       return '';
     86     }
     87     const valuePairs = this.keyValues();
     88     let objString = `${valuePairs[0].toString()}`;
     89     for (let i = 1; i < valuePairs.length; i++) {
     90       objString = `${objString},${valuePairs[i].toString()}`;
     91     }
     92     return objString;
     93   }
     94 
     95 
     96 }
     97 
     98 class Graph {
     99   constructor (isDirected = false) {
    100     this.isDirected = isDirected;
    101     this.vertices = [];
    102     this.adjList = new Dictionary();
    103   }
    104   addVertex(v) {
    105     if (!this.vertices.includes(v)) {
    106       this.vertices.push(v);
    107       this.adjList.set(v, []);
    108     }
    109   }
    110   addEdge(a, b ) {
    111     if (!this.adjList.get(a)) {
    112       this.addVertex(a);
    113     }
    114     if (!this.adjList.get(b)) {
    115       this.adjList(b);
    116     }
    117     this.adjList.get(a).push(b);
    118     if (this.isDirected !== true) {
    119       this.adjList.get(b).push(a);
    120     }
    121   }
    122   getVertices() {
    123     return this.vertices;
    124   }
    125   getAdjList() {
    126      return this.adjList;
    127   }
    128   toString() {
    129     let s = '';
    130     for (let i = 0; i < this.vertices.length; i++) {
    131       s += `${this.vertices[i]} -> `;
    132       const neighbors = this.adjList.get(this.vertices[i]);
    133       for (let j = 0; j < neighbors.length; j++) {
    134         s +=`${neighbors[j]} `;
    135       }
    136       s += '
    ';
    137     }
    138     return s;
    139   }
    140 
    141 }
    142 //import Queue
    143 class Queue{
    144 constructor(){
    145 this.count = 0;
    146 this.lowestCount = 0;
    147 this.items ={};
    148 }
    149 
    150 
    151 enqueue(element) {
    152 this.items[this.count] = element;
    153 this.count++;
    154 }
    155 
    156 dequeue() {
    157 if (this.isEmpty()) {
    158 return undefined;
    159 }
    160 const result = this.items[this.lowestCount];
    161 delete this.items[this.lowestCount];
    162 this.lowestCount++;
    163 return result;
    164 }
    165 
    166 peek() {
    167 if (this.isEmpty()){
    168 return undefined;
    169 }
    170 return this.items[this.lowestCount];
    171 }
    172 
    173 isEmpty() {
    174 return this.size() === 0;
    175 }
    176 size() {
    177 return this.count - this.lowestCount;
    178 }
    179 clear(){
    180 this.items = {};
    181 this.count = 0;
    182 this.lowestCount = 0;
    183 }
    184 toString(){
    185 if (this.isEmpty()){
    186 return '';
    187 }
    188 let objString = `${this.items[this.lowestCount]}`
    189 for (let i= this.lowestCount + 1; i < this.count;i++){
    190 objString = `${objString},${this.items[i]}`;
    191 }
    192 return objString;
    193 }
    194 }
    195 
    196 // stack for shortest path - BFS
    197 class Stack {
    198 constructor() {
    199 this.count = 0;
    200 this.items = {};
    201 }
    202 
    203 push(element) {
    204 this.items[this.count] = element;
    205 this.count++;
    206 }
    207 
    208 pop() {
    209 if (this.isEmpty()) {
    210 return undefined;
    211 }
    212 this.count--;
    213 const result = this.items[this.count];
    214 delete this.items[this.count];
    215 return result;
    216 }
    217 
    218 peek() {
    219 if (this.isEmpty()) {
    220 return undefined;
    221 }
    222 return this.items[this.count - 1];
    223 }
    224 
    225 isEmpty() {
    226 return this.count === 0;
    227 }
    228 
    229 size() {
    230 return this.count;
    231 }
    232 
    233 clear() {
    234 /* while (!this.isEmpty()) {
    235 this.pop();
    236 } */
    237 this.items = {};
    238 this.count = 0;
    239 }
    240 
    241 toString() {
    242 if (this.isEmpty()) {
    243 return '';
    244 }
    245 let objString = `${this.items[0]}`;
    246 for (let i = 1; i < this.count; i++) {
    247 objString = `${objString},${this.items[i]}`;
    248 }
    249 return objString;
    250 }
    251 }
    252 
    253 
    254 const Colors = {
    255   WHITE: 0,
    256   GREY: 1,
    257   BLACK: 2
    258 };
    259 
    260 
    261 const initializeColor = vertices => {
    262   const color = {};
    263   for (let i = 0; i < vertices.length; i++) {
    264     color[vertices[i]] = Colors.WHITE;
    265   }
    266   return color;
    267 };
    268 
    269 const breadthFirstSearch = (graph, startVertex, callback) => {
    270   const vertices = graph.getVertices();
    271   const adjList = graph.getAdjList();
    272   const color = initializeColor(vertices);
    273   const queue = new Queue;
    274 
    275   queue.enqueue(startVertex);
    276   while (!queue.isEmpty()) {
    277     const u = queue.dequeue();
    278     const neighbors = adjList.get(u);
    279     color[u] = Colors.GREY;
    280     for (let i = 0; i < neighbors.length; i++) {
    281       const w = neighbors[i];
    282       if (color[w] === Colors.WHITE) {
    283         color[w] = Colors.GREY;
    284         queue.enqueue(w);
    285       }
    286     }
    287     color[u] = Colors.BLACK;
    288     if (callback) {
    289       callback(u);
    290     }
    291 
    292   }
    293 
    294 };
    295 
    296 const BFS = (graph, startVertex) => {
    297   const vertices = graph.getVertices();
    298   const adjList = graph.getAdjList();
    299   const color = initializeColor(vertices);
    300   const queue = new Queue;
    301   const distances =  {};
    302   const predecessors = {};
    303   queue.enqueue(startVertex);
    304 
    305   for (let i = 0; i < vertices.length; i++) {
    306     distances[vertices[i]] = 0;
    307     predecessors[vertices[i]] = null;
    308   }
    309   while (!queue.isEmpty()) {
    310     const u = queue.dequeue();
    311     const neighbors = adjList.get(u);
    312     color[u] = Colors.GREY;
    313     for (let i = 0; i < neighbors.length; i++) {
    314       const w = neighbors[i];
    315       if (color[w] === Colors.WHITE) {
    316         color[w] = Colors.GREY;
    317         distances[w] = distances[u] + 1;
    318         predecessors[w] = u;
    319         queue.enqueue(w);
    320       }
    321     }
    322     color[u] = Colors.BLACK;
    323   }
    324   return {
    325     distances,
    326     predecessors
    327   };
    328 };
    329 
    330 
    331 const graph = new Graph();
    332 
    333 const myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
    334 
    335 for (let i = 0; i < myVertices.length; i++) {
    336   graph.addVertex(myVertices[i]);
    337 }
    338 graph.addEdge('A', 'B');
    339 graph.addEdge('A', 'C');
    340 graph.addEdge('A', 'D');
    341 graph.addEdge('C', 'D');
    342 graph.addEdge('C', 'G');
    343 graph.addEdge('D', 'G');
    344 graph.addEdge('D', 'H');
    345 graph.addEdge('B', 'E');
    346 graph.addEdge('B', 'F');
    347 graph.addEdge('E', 'I');
    348 
    349 console.log('********* printing graph ***********');
    350 console.log(graph.toString());
    351 console.log('********* bfs with callback ***********');
    352 const printVertex = (value) => {
    353   console.log('Visited vertex: ' + value)
    354 }
    355 breadthFirstSearch(graph, myVertices[0], printVertex);
    356 console.log('********* shortest path - BFS ***********');
    357 const shortestPathA = BFS(graph, myVertices[0]);
    358 console.log(shortestPathA.distances);
    359 console.log(shortestPathA.predecessors);
    360 
    361 const fromVertex = myVertices[0];
    362 for (let i = 1; i < myVertices.length; i++) {
    363   const toVertex = myVertices[i];
    364   const path = new Stack();
    365   for(let v = toVertex; v !== fromVertex; v = shortestPathA.predecessors[v]) {
    366     path.push(v);
    367   }
    368   path.push(fromVertex);
    369   let s = path.pop();
    370   while (!path.isEmpty()) {
    371     s += '-' + path.pop();
    372   }
    373   console.log(s);
    374 }  
    BFS

     1.2 深度优先搜索 (算法工作原理的实现;构建森林;拓扑排序)

     概念:深度优先搜索算法将会从一个指定的顶点开始遍历图,沿着路径直到这条路径最后一个顶点被访问了,接着原路回退并探索下一条路径(先深度后广度地访问顶点)。对于给定的图G,我们希望深度优先搜索算法遍历图G的所有节点,构建“森林”(有根树的一个集合)以及一组源顶点(根),并输出两个数组:发现时间和完成探索时间。而这些信息,我们可以用来做拓扑排序(当我们需要编排一些任务或者步骤的执行顺序时,这称为拓扑排序,其只能应用于有向无环图DAG)。

      1 // import dictionary
      2 class ValuePair {
      3   constructor(key, value) {
      4     this.key = key;
      5     this.value = value;
      6   }
      7 
      8   toString() {
      9     return `[#${this.key}: ${this.value}]`;
     10   }
     11 }
     12 
     13 function defaultToString(item) {
     14   if (item === null) {
     15     return 'NULL';
     16   } if (item === undefined) {
     17     return 'UNDEFINED';
     18   } if (typeof item === 'string' || item instanceof String) {
     19     return `${item}`;
     20   }
     21   return item.toString();
     22 }
     23 
     24 class Dictionary {
     25   constructor(toStrFn = defaultToString) {
     26     this.toStrFn = toStrFn;
     27     this.table = {};
     28   }
     29   hasKey(key) {
     30     return this.table[this.toStrFn(key)] != null;
     31   }
     32   set(key, value) {
     33     if (key != null && value != null) {
     34       const tableKey = this.toStrFn(key);
     35       this.table[tableKey] = new ValuePair(key,value);
     36       return true;
     37     }
     38     return false;
     39   }
     40   remove(key) {
     41     if (this.hasKey(key)) {
     42       delete this.table[this.toStrFn(key)];
     43       return true;
     44     }
     45     return false;
     46   }
     47   get(key) {
     48     const valuePair = this.table[this.toStrFn(key)];
     49     return valuePair == null ? undefined : valuePair.value;
     50   }
     51   keyValues() {
     52     return Object.values(this.table);
     53   }
     54   values() {
     55     return this.keyValues().map(valuePair => valuePair.value);
     56   }
     57 
     58   keys() {
     59     return this.keyValues().map(valuePair => valuePair.key);
     60   }
     61   forEach(callbackFn) {
     62     const valuePairs = this.keyValues();
     63     for (let i = 0; i < valuePairs.length; i++) {
     64       const result = callbackFn(valuePairs[i].key, valuePairs[i].value);
     65       if (result === false) {
     66         break;
     67       }
     68     }
     69   }
     70 
     71     isEmpty() {
     72     return this.size() === 0;
     73   }
     74 
     75   size() {
     76     return Object.keys(this.table).length;
     77   }
     78 
     79   clear() {
     80     this.table = {};
     81   }
     82 
     83   toString() {
     84     if (this.isEmpty()) {
     85       return '';
     86     }
     87     const valuePairs = this.keyValues();
     88     let objString = `${valuePairs[0].toString()}`;
     89     for (let i = 1; i < valuePairs.length; i++) {
     90       objString = `${objString},${valuePairs[i].toString()}`;
     91     }
     92     return objString;
     93   }
     94 
     95 
     96 }
     97 
     98 class Graph {
     99   constructor (isDirected = false) {
    100     this.isDirected = isDirected;
    101     this.vertices = [];
    102     this.adjList = new Dictionary();
    103   }
    104   addVertex(v) {
    105     if (!this.vertices.includes(v)) {
    106       this.vertices.push(v);
    107       this.adjList.set(v, []);
    108     }
    109   }
    110   addEdge(a, b ) {
    111     if (!this.adjList.get(a)) {
    112       this.addVertex(a);
    113     }
    114     if (!this.adjList.get(b)) {
    115       this.adjList(b);
    116     }
    117     this.adjList.get(a).push(b);
    118     if (this.isDirected !== true) {
    119       this.adjList.get(b).push(a);
    120     }
    121   }
    122   getVertices() {
    123     return this.vertices;
    124   }
    125   getAdjList() {
    126      return this.adjList;
    127   }
    128   toString() {
    129     let s = '';
    130     for (let i = 0; i < this.vertices.length; i++) {
    131       s += `${this.vertices[i]} -> `;
    132       const neighbors = this.adjList.get(this.vertices[i]);
    133       for (let j = 0; j < neighbors.length; j++) {
    134         s +=`${neighbors[j]} `;
    135       }
    136       s += '
    ';
    137     }
    138     return s;
    139   }
    140 
    141 }
    142 
    143 
    144 
    145 const Colors = {
    146   WHITE: 0,
    147   GREY: 1,
    148   BLACK: 2
    149 };
    150 
    151 
    152 const initializeColor = vertices => {
    153   const color = {};
    154   for (let i = 0; i < vertices.length; i++) {
    155     color[vertices[i]] = Colors.WHITE;
    156   }
    157   return color;
    158 };
    159 
    160 const depthFirstSearchVisit = (u, color, adjList, callback) =>{
    161   color[u] = Colors.GREY;
    162   if (callback) {
    163     callback(u);
    164   }
    165   const neighbors = adjList.get(u);
    166   for (let i = 0; i < neighbors.length; i++) {
    167     const w = neighbors[i];
    168     if (color[w] === Colors.WHITE) {
    169       depthFirstSearchVisit(w, color, adjList, callback);
    170     }
    171   }
    172   color[u] = Colors.BLACK;
    173 };
    174 
    175 const depthFirstSearch = (graph, callback) =>{
    176   const vertices = graph.getVertices();
    177   const adjList =  graph.getAdjList();
    178   const color = initializeColor(vertices);
    179   for (let i = 0; i < vertices.length; i++) {
    180     if (color[vertices[i]] === Colors.WHITE) {
    181       depthFirstSearchVisit(vertices[i], color, adjList, callback);
    182     }
    183   }
    184 
    185 };
    186 
    187 const DFSVisit = (u, color, d, f, p, time, adjList) => {
    188   color[u] = Colors.GREY;
    189   d[u] = ++time.count;
    190   const neighbors = adjList.get(u);
    191   for (let i =0; i <neighbors.length; i++) {
    192     const w = neighbors[i];
    193     if (color[w] === Colors.WHITE) {
    194       p[w] = u;
    195       DFSVisit(w, color, d, f, p, time, adjList);
    196     }
    197   }
    198   color[u] = Colors.BLACK;
    199   f[u] = ++time.count;
    200 };
    201 
    202 const DFS = graph =>{
    203   const vertices = graph.getVertices();
    204   const adjList = graph.getAdjList();
    205   const color = initializeColor(vertices);
    206   const d = {};
    207   const f = {};
    208   const p = {};
    209   const time = {count: 0};
    210   for (let i = 0; i < vertices.length; i++) {
    211     f[vertices[i]] = 0;
    212     d[vertices[i]] = 0;
    213     p[vertices[i]] = null; 
    214   }
    215   for (let i = 0; i < vertices.length; i++) {
    216     if (color[vertices[i]] === Colors.WHITE) {
    217       DFSVisit(vertices[i], color, d, f, p, time, adjList);
    218     }
    219   }
    220   return {
    221     discovery: d,
    222     finished: f,
    223     predecessors:p
    224   };
    225 
    226 };
    227 
    228 
    229 
    230 let graph = new Graph(true);
    231 
    232 let myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
    233 
    234 for (let i = 0; i < myVertices.length; i++) {
    235   graph.addVertex(myVertices[i]);
    236 }
    237 graph.addEdge('A', 'B');
    238 graph.addEdge('A', 'C');
    239 graph.addEdge('A', 'D');
    240 graph.addEdge('C', 'D');
    241 graph.addEdge('C', 'G');
    242 graph.addEdge('D', 'G');
    243 graph.addEdge('D', 'H');
    244 graph.addEdge('B', 'E');
    245 graph.addEdge('B', 'F');
    246 graph.addEdge('E', 'I');
    247 
    248 console.log('********* printing graph ***********');
    249 
    250 console.log(graph.toString());
    251 
    252 console.log('********* dfs with callback ***********');
    253 
    254 const printVertex = value => console.log('Visited vertex: ' + value);
    255 
    256 depthFirstSearch(graph, printVertex);
    257 console.log('*********  DFS ***********');
    258 
    259 const result = DFS(graph);
    260 console.log('discovery', result.discovery);
    261 console.log('finished', result.finished);
    262 console.log('predecessors', result.predecessors);
    263 
    264 console.log('********* topological sort - DFS ***********');
    265 
    266 graph = new Graph(true);
    267 
    268 myVertices = ['A', 'B', 'C', 'D', 'E', 'F'];
    269 for (i = 0; i < myVertices.length; i++) {
    270   graph.addVertex(myVertices[i]);
    271 }
    272 graph.addEdge('A', 'C');
    273 graph.addEdge('A', 'D');
    274 graph.addEdge('B', 'D');
    275 graph.addEdge('B', 'E');
    276 graph.addEdge('C', 'F');
    277 graph.addEdge('F', 'E');
    278 
    279 const result2 = DFS(graph);
    280 console.log('discovery', result.discovery);
    281 console.log('finished', result.finished);
    282 console.log('predecessors', result.predecessors);
    283 
    284 const fTimes = result2.finished;
    285 s = '';
    286 for (let count = 0; count < myVertices.length; count ++) {
    287   let max = 0;
    288   let maxName = null;
    289   for (i = 0; i < myVertices.length; i++) {
    290     if (fTimes[myVertices[i]] > max ) {
    291       max = fTimes[myVertices[i]];
    292       maxName = myVertices[i];
    293     }
    294   }
    295   s += ' - ' + maxName;
    296   delete fTimes[maxName]; 
    297 }
    298 console.log(s);
    DFS

     1.3 最短路径算法(Dijkstra算法、Floyd-Warshall算法)

     1.3.1 Dijkstra算法

    概念:Dijkstra算法是一种计算从单个源到所有其他源的最短路径的贪心算法,这意味着我们可以用它来计算从图的一个顶点到其余各顶点的最短路径。

     1 const INF = Number.MAX_SAFE_INTEGER;
     2 const minDistance = (dist, visited) => {
     3   let min = INF;
     4   let minIndex = -1;
     5   for (let v = 0; v < dist.length; v++) {
     6     if (visited[v] === false && dist[v] <= min) {
     7       min = dist[v];
     8       minIndex = v;
     9     }
    10   }
    11   return minIndex;
    12 };
    13 
    14 const dijkstra = (graph, src) => {
    15   const dist = [];
    16   const visited = [];
    17   const {length} = graph;
    18   for (let i = 0; i < length; i++ ) {
    19     dist[i] = INF;
    20     visited[i] = false;
    21   }
    22   dist[src] = 0;
    23   for (let i = 0; i < length -1; i++) {
    24     const u = minDistance(dist, visited);
    25     visited[u] = true;
    26     for (let v = 0; v < length; v++) {
    27       if (!visited[v] && graph[u][v] !== 0 && dist[u] !== INF && dist[u] + graph[u][v] < dist[v]) {
    28         dist [v] = dist[u] + graph[u][v];
    29       }
    30     }
    31   }
    32   return dist;
    33 }; 
    34 
    35 
    36 const graph = [
    37   [0, 2, 4, 0, 0, 0],
    38   [0, 0, 2, 4, 2, 0],
    39   [0, 0, 0, 0, 3, 0],
    40   [0, 0, 0, 0, 0, 2],
    41   [0, 0, 0, 3, 0, 2],
    42   [0, 0, 0, 0, 0, 0]
    43 ];
    44 
    45 console.log("********* Dijkstra's Algorithm - Shortest Path ***********");
    46 
    47 const dist = dijkstra(graph, 0);
    48 
    49 for (i = 0; i < dist.length; i++){
    50     console.log(i + '		' + dist[i]);
    51 }
    Dijkstra

     1.3.2 Floyd-Warshall算法

     概念:Floyd-Warshall算法是一种计算图中所有最短路径的动态规划算法。通过该算法,我们可以找出从所有源到所有顶点的最短路径。

     1 const floydWarshall = graph => {
     2   const dist = [];
     3   const {length} = graph;
     4   for (let i = 0; i < length; i++) {
     5     dist[i] = [];
     6     for (let j = 0; j < length; j++) {
     7       if (i === j) {
     8         dist[i][j] = 0;
     9       } else if (!isFinite(graph[i][j])) {
    10         dist[i][j] = Infinity;
    11       } else {
    12         dist[i][j] = graph[i][j];
    13       }
    14     }
    15   }
    16   for (let k = 0; k < length; k++) {
    17     for(let i = 0; i < length; i++) {
    18       for (let j = 0; j < length; j++) {
    19         if (dist[i][k] + dist[k][j] < dist[i][j]) {
    20           dist[i][j] = dist[i][k] + dist[k][j];
    21         }
    22       }
    23     }
    24   }
    25   return dist;
    26 };
    27 
    28 const INF = Infinity;
    29 const graph = [
    30   [INF, 2, 4, INF, INF, INF],
    31   [INF, INF, 2, 4, 2, INF],
    32   [INF, INF, INF, INF, 3, INF],
    33   [INF, INF, INF, INF, INF, 2],
    34   [INF, INF, INF, 3, INF, 2],
    35   [INF, INF, INF, INF, INF, INF]
    36 ];
    37 
    38 dist = floydWarshall(graph);
    39 let s = '';
    40 for (let i = 0; i < dist.length; i++) {
    41   s = '';
    42   for (let j = 0; j < dist.length; j++) {
    43     if (dist[i][j] === INF) {
    44       s += 'INF ';
    45     } else {
    46       s += dist[i][j] + ' ';
    47     }
    48    
    49   }
    50   console.log(s);
    51 }
    floydWarshall

     1.4 最小生成树(Prim算法、Kruskal算法)

     概念:最小生成树(MST,最小权重生成树)是一个有n个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树问题是网络设计中常见的问题,例如办公室电话线路通信问题和岛桥问题。

     1.4.1 Prim算法(“加点法”)

     概念:Prim算法是一种求解加权无向连通图的MST问题的贪心算法。它能找到一个边的子集,使得其构成的树包含图中所有顶点,并且边的权值之和最小。

     1 const INF = Number.MAX_SAFE_INTEGER;
     2 const minKey  = (graph, key, visited) => {
     3   let min = INF;
     4   let minIndex = 0;
     5   for (let v = 0; v < graph.length; v++) {
     6     if (visited[v] === false && key[v] < min) {
     7       min = key[v];
     8       minIndex = v;
     9     }
    10   }
    11   return minIndex;
    12 };
    13 
    14 const prim = graph => {
    15   const parent = [];
    16   const key = [];
    17   const visited = [];
    18   const {length} = graph;
    19   for (let i = 0; i < length; i++) {
    20     key[i] = INF;
    21     visited[i] = false;
    22   }
    23   key[0] = 0;
    24   parent[0] = -1;
    25   for (let i = 0; i < length - 1; i++) {
    26     const u = minKey(graph, key, visited);
    27     visited[u] = true;
    28     for (let v = 0; v < length; v++) {
    29       if (graph[u][v] && !visited[v] && graph[u][v] < key[v]) {
    30         parent[v] = u;
    31         key[v] = graph[u][v];
    32       }
    33     }
    34   }
    35   return parent;
    36 };
    37 
    38 const graph = [
    39   [0, 2, 4, 0, 0, 0],
    40   [2, 0, 2, 4, 2, 0],
    41   [4, 2, 0, 0, 3, 0],
    42   [0, 4, 0, 0, 3, 2],
    43   [0, 2, 3, 3, 0, 2],
    44   [0, 0, 0, 2, 2, 0]
    45 ];
    46 
    47 
    48 
    49 const parent = prim(graph);
    50 
    51 console.log('Edge   Weight');
    52 for (let i = 1; i < graph.length; i++) {
    53   console.log(parent[i] + ' - ' + i + '   ' + graph[i][parent[i]]);
    54 }
    prim

     1.4.2 Kruskal算法(“加边法”)

     概念:Kruskal算法也是一种求加权无向连通图的MST的贪心算法。

     1 const INF = Number.MAX_SAFE_INTEGER;
     2 const find = (i, parent) => {
     3   while (parent[i]) {
     4     i = parent[i];
     5   }
     6   return i;
     7 };
     8 
     9 const union = (i, j, parent) => {
    10   if (i !== j) {
    11     parent[j] = i;
    12     return true;
    13   }
    14   return false;
    15 };
    16 const initializeCost = graph => {
    17   const cost = [];
    18   const {length} = graph;
    19   for (let i = 0; i < length; i++) {
    20     cost[i] =[];
    21     for (let j = 0; j < length; j++) {
    22       if (graph[i][j] === 0) {
    23         cost[i][j] = INF;
    24       } else {
    25         cost[i][j] = graph[i][j];
    26       }
    27     }
    28   }
    29   return cost;
    30 };
    31 
    32 const kruskal = graph => {
    33   const {length} = graph;
    34   const parent = [];
    35   let ne = 0;
    36   let a;
    37   let b;
    38   let u;
    39   let v;
    40   const cost = initializeCost(graph);
    41   while (ne < length - 1) {
    42     for (let i = 0, min = INF; i < length; i++) {
    43       for (let j = 0; j < length; j++) {
    44         if (cost[i][j] < min) {
    45           min = cost[i][j];
    46           a = u = i;
    47           b = v = j;
    48         }
    49       }
    50     }
    51     u = find(u, parent);
    52     v = find(v, parent);
    53     if (union(u, v, parent)) {
    54       ne++;
    55     }
    56     cost[a][b] = cost[b][a] = INF;
    57   }
    58   return parent;
    59 };
    60 
    61 
    62 const graph = [
    63   [0, 2, 4, 0, 0, 0],
    64   [2, 0, 2, 4, 2, 0],
    65   [4, 2, 0, 0, 3, 0],
    66   [0, 4, 0, 0, 3, 2],
    67   [0, 2, 3, 3, 0, 2],
    68   [0, 0, 0, 2, 2, 0]
    69 ];
    70 
    71 
    72 
    73 const parent = kruskal(graph);
    74 
    75 console.log('Edge   Weight');
    76 for (i = 1; i < graph.length; i++) {
    77   console.log(parent[i] + ' - ' + i + '   ' + graph[i][parent[i]]);
    78 }
    kruskal
  • 相关阅读:
    HDU 1816, POJ 2723 Get Luffy Out(2-sat)
    [Transducer] Make an Into Helper to Remove Boilerplate and Simplify our Transduce API
    [ML] Daily Portfolio Statistics
    [Javascript] Transduce over any Iteratable Collection
    [Javascript] Improve Composition with the Compose Combinator
    [Mobx] Using mobx to isolate a React component state
    [Javascript] Simplify Creating Immutable Data Trees With Immer
    [React Native] Dismiss the Keyboard in React Native
    [CSSinJS] Convert Sass (SCSS) Styled Button to CSSinJS with JavaScript Templates and Variables
    [React Native] Use the SafeAreaView Component in React Native for iPhone X Compatibility
  • 原文地址:https://www.cnblogs.com/xinkuiwu/p/11761052.html
Copyright © 2020-2023  润新知