世界就像一个巨大的图书馆,我们读着别人,做着自己,等待被读。 :

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 += '\n';
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 += '\n';
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 += '\n';
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 + '\t\t' + 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

 

posted @ 2019-10-29 19:40  Secret_Wu  阅读(528)  评论(1编辑  收藏  举报