Skip to content
This repository was archived by the owner on Dec 3, 2023. It is now read-only.

Commit c6df686

Browse files
committed
adding Kahn's Topological sorting
1 parent a8f4f4c commit c6df686

File tree

7 files changed

+189
-9
lines changed

7 files changed

+189
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Common algorithms implemented in JavaScript with [Mocha](https://mochajs.org/)/[
3333

3434
* [Breadth First Search](https://github.com/sumtype/common-algorithms-js/blob/master/algorithms/es/breadthFirstSearch.js)
3535
* [Depth First Search](https://github.com/sumtype/common-algorithms-js/blob/master/algorithms/es/depthFirstSearch.js)
36+
* [Kahn's Topological sorting](https://github.com/sumtype/common-algorithms-js/blob/master/algorithms/es/kahnTopologicalSort.js)
3637

3738
### Math
3839

algorithms/es/kahnTopologicalSort.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict'
2+
3+
const kahnTopologicalSort = edges => {
4+
if (!Array.isArray(edges) || edges.length === 0) return null
5+
let nodes = {}
6+
let sorted = []
7+
let visited = {}
8+
9+
let Node = function (id) {
10+
this.id = id
11+
this.afters = []
12+
}
13+
14+
edges.forEach(v => {
15+
let from = v[0]
16+
let to = v[1]
17+
if (!nodes[from]) nodes[from] = new Node(from)
18+
if (!nodes[to]) nodes[to] = new Node(to)
19+
nodes[from].afters.push(to)
20+
})
21+
22+
const visit = (idstr, ancestors) => {
23+
let node = nodes[idstr]
24+
let id = node.id
25+
if (visited[idstr]) return
26+
if (!Array.isArray(ancestors)) ancestors = []
27+
ancestors.push(id)
28+
visited[idstr] = true
29+
node.afters.forEach(afterID => {
30+
if (ancestors.indexOf(afterID) >= 0) {
31+
throw new Error('closed chain : ' + afterID + ' is in ' + id)
32+
}
33+
visit(
34+
afterID.toString(),
35+
ancestors.map(v => {
36+
return v
37+
})
38+
)
39+
})
40+
sorted.unshift(id)
41+
}
42+
43+
Object.keys(nodes).forEach(visit)
44+
45+
return sorted
46+
}
47+
export default kahnTopologicalSort

algorithms/es5/kahnTopologicalSort.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
(function (global, factory) {
2+
if (typeof define === 'function' && define.amd) {
3+
define(['exports'], factory)
4+
} else if (typeof exports !== 'undefined') {
5+
factory(exports)
6+
} else {
7+
var mod = {
8+
exports: {}
9+
}
10+
factory(mod.exports)
11+
global.kahnTopologicalSort = mod.exports
12+
}
13+
})(this, function (exports) {
14+
'use strict'
15+
16+
Object.defineProperty(exports, '__esModule', {
17+
value: true
18+
})
19+
var kahnTopologicalSort = function kahnTopologicalSort (edges) {
20+
if (!Array.isArray(edges) || edges.length === 0) return null
21+
var nodes = {}
22+
var sorted = []
23+
var visited = {}
24+
25+
var Node = function Node (id) {
26+
this.id = id
27+
this.afters = []
28+
}
29+
30+
edges.forEach(function (v) {
31+
var from = v[0]
32+
var to = v[1]
33+
if (!nodes[from]) nodes[from] = new Node(from)
34+
if (!nodes[to]) nodes[to] = new Node(to)
35+
nodes[from].afters.push(to)
36+
})
37+
38+
var visit = function visit (idstr, ancestors) {
39+
var node = nodes[idstr]
40+
var id = node.id
41+
if (visited[idstr]) return
42+
if (!Array.isArray(ancestors)) ancestors = []
43+
ancestors.push(id)
44+
visited[idstr] = true
45+
node.afters.forEach(function (afterID) {
46+
if (ancestors.indexOf(afterID) >= 0) {
47+
throw new Error('closed chain : ' + afterID + ' is in ' + id)
48+
}
49+
visit(afterID.toString(), ancestors.map(function (v) {
50+
return v
51+
}))
52+
})
53+
sorted.unshift(id)
54+
}
55+
56+
Object.keys(nodes).forEach(visit)
57+
58+
return sorted
59+
}
60+
exports.default = kahnTopologicalSort
61+
})

es.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import rayCasting from './algorithms/es/rayCasting'
3030
// Graph Algorithms
3131
import breadthFirstSearch from './algorithms/es/breadthFirstSearch'
3232
import depthFirstSearch from './algorithms/es/depthFirstSearch'
33-
33+
import kahnTopologicalSort from './algorithms/es/kahnTopologicalSort'
3434
// Math Algorithms
3535
import fibonacciNumber from './algorithms/es/fibonacciNumber'
3636
import isPrime from './algorithms/es/isPrime'
@@ -59,7 +59,7 @@ import sorensenDiceCoefficient from './algorithms/es/sorensenDiceCoefficient'
5959
// Algorithm Categories
6060
const array = { binarySearch, bubbleSort, bucketSort, cocktailSort, countingSort, durstenfeldShuffle, gnomeSort, insertionSort, linearSearch, mergeSort, quickSort, radixSort, reservoirSampling, sattoloCycle, selectionSort, shellSort, sleepSort }
6161
const geometry = { bezierCurve, rayCasting }
62-
const graph = { breadthFirstSearch, depthFirstSearch }
62+
const graph = { breadthFirstSearch, depthFirstSearch, kahnTopologicalSort }
6363
const math = { fibonacciNumber, isPrime, powerSet, primeFactors, sieveOfAtkin, sieveOfEratosthenes }
6464
const string = { areAnagrams, arePalindromes, boyerMooreStringMatch, boyerMooreHorspoolStringMatch, bruteForceStringMatch, damerauLevenshteinDistance, hammingDistance, hasDuplicateCharacters, knuthMorrisPrattStringMatch, levenshteinDistance, longestCommonSubsequence, longestCommonSubstring, matchingDelimiters, rabinKarpStringMatch, sorensenDiceCoefficient }
6565

@@ -68,7 +68,7 @@ export default { array, geometry, graph, math, string }
6868
export {
6969
array, binarySearch, bubbleSort, bucketSort, cocktailSort, countingSort, durstenfeldShuffle, gnomeSort, insertionSort, linearSearch, mergeSort, quickSort, radixSort, reservoirSampling, sattoloCycle, selectionSort, shellSort, sleepSort,
7070
geometry, bezierCurve, rayCasting,
71-
graph, breadthFirstSearch, depthFirstSearch,
71+
graph, breadthFirstSearch, depthFirstSearch, kahnTopologicalSort,
7272
math, fibonacciNumber, isPrime, powerSet, primeFactors, sieveOfAtkin, sieveOfEratosthenes,
7373
string, areAnagrams, arePalindromes, boyerMooreStringMatch, boyerMooreHorspoolStringMatch, bruteForceStringMatch, damerauLevenshteinDistance, hammingDistance, hasDuplicateCharacters, knuthMorrisPrattStringMatch, levenshteinDistance, longestCommonSubsequence, longestCommonSubstring, matchingDelimiters, rabinKarpStringMatch, sorensenDiceCoefficient
7474
}

0 commit comments

Comments
 (0)