直接上代码:
kotlin版本
package org
import java.util.*
import kotlin.collections.*
interface DependencyNode<T> {
val value: T
fun dependsOn(node: DependencyNode<T>)
}
interface DependencyManager<T> {
fun createNode(value: T): DependencyNode<T>
fun toposort(): List<T>
}
class DependencyManagerEx<T> : DependencyManager<T> {
private val list = LinkedList<DepsNode<T>>()
override fun createNode(value: T): DependencyNode<T> = DepsNode(value).apply {
list.add(this)
}
override fun toposort(): List<T> {
if (list.isEmpty()) {
return emptyList()
}
val result = ArrayList<T>()
for (depsNode in list) {
if (depsNode.visited) {
continue
}
toposort(depsNode, depsNode, result)
}
return result
}
fun reset() {
for (depsNode in list) {
depsNode.visited = false
}
}
private fun toposort(node: DepsNode<T>, from: DepsNode<T>, result: MutableList<T>) {
for (dependency in node.dependencies) {
if (dependency == from) {
throw IllegalStateException("has cycle")
}
toposort(dependency, from, result)
}
if (!node.visited) {
result.add(node.value)
node.visited = true
}
}
private class DepsNode<T>(
override val value: T,
) : DependencyNode<T> {
val dependencies: MutableList<DepsNode<T>> = ArrayList()
var visited = false
override fun dependsOn(node: DependencyNode<T>) {
dependencies.add(node as DepsNode)
}
override fun toString(): String {
return "DepsNode(value=$value, dependencies=${dependencies.size}, visited=$visited)"
}
}
}
class DependencyManagerImpl<T> : DependencyManager<T> {
private val map = LinkedHashMap<DepsNode<T>, LinkedList<DepsNode<T>>>()
private fun dependsOn(from: DepsNode<T>, to: DepsNode<T>) {
map[from]!!.add(to.apply { inDegree++ })
}
override fun createNode(value: T): DependencyNode<T> = DepsNode(value, this).apply {
map.putIfAbsent(this, LinkedList<DepsNode<T>>())
}
override fun toposort(): List<T> {
if (map.isEmpty()) {
return emptyList()
}
val result = ArrayList<T>()
var size = 0
while (size != map.size && map.isNotEmpty()) {
size = map.size
val iter = map.keys.toMutableSet().iterator()
while (iter.hasNext()) {
val node = iter.next()
if (node.inDegree == 0) {
result.add(node.value)
map[node]!!.forEach {
it.inDegree--
}
map.remove(node)
}
}
}
if (map.isNotEmpty()) {
throw IllegalStateException("has cycle")
}
return result
}
private class DepsNode<T>(
override val value: T,
val manager: DependencyManagerImpl<T>,
) : DependencyNode<T> {
var inDegree = 0
override fun dependsOn(node: DependencyNode<T>) {
manager.dependsOn(node as DepsNode, this)
}
override fun toString(): String {
return "DepsNode(value=$value, inDegree=$inDegree)"
}
}
}
fun main() {
println(makeNodes(DependencyManagerEx())) // [1, 6, 3, 8, 4, 9, 5, 7, 11]
println(makeNodes(DependencyManagerImpl())) // [1, 6, 8, 3, 9, 11, 4, 5, 7]
println(DependencyManagerEx<Int>().toposort()) // []
println(DependencyManagerImpl<Int>().toposort()) // []
try {
println(makeNodes(DependencyManagerEx(), cyclic = true))
} catch (e: IllegalStateException) {
println(e) // java.lang.IllegalStateException: has cycle
}
try {
println(makeNodes(DependencyManagerImpl(), cyclic = true))
} catch (e: IllegalStateException) {
println(e) // java.lang.IllegalStateException: has cycle
}
}
private fun makeNodes(manager: DependencyManager<Int>, cyclic: Boolean = false): List<Int> {
val task1 = manager.createNode(1)
val task6 = manager.createNode(6)
val task7 = manager.createNode(7)
val task4 = manager.createNode(4)
val task8 = manager.createNode(8)
val task5 = manager.createNode(5)
val task3 = manager.createNode(3)
val task9 = manager.createNode(9)
val task11 = manager.createNode(11)
task4.dependsOn(task1)
task4.dependsOn(task3)
task4.dependsOn(task8)
task5.dependsOn(task6)
task5.dependsOn(task9)
task7.dependsOn(task4)
task7.dependsOn(task5)
task11.dependsOn(task9)
if (cyclic) {
task1.dependsOn(task7)
}
return manager.toposort()
}
Typescript
module org.topo {
export interface DependencyNode<T> {
value: T;
dependsOn(node: DependencyNode<T>):void;
}
export interface DependencyManager<T> {
createNode(value: T): DependencyNode<T>;
toposort(): T[];
}
export class DependencyManagerEx<T> implements DependencyManager<T> {
private readonly list:DepsNodeEx<T>[] = [];
createNode(value: T): DependencyNode<T> {
const node = new DepsNodeEx(value);
this.list.push(node);
return node;
}
toposort(): T[] {
if (this.list.length == 0) {
return [];
}
const result: T[] = [];
for (const depsNode of this.list) {
if (depsNode.visited) {
continue;
}
this.toposort0(depsNode, depsNode, result);
}
return result;
}
private toposort0(node: DepsNodeEx<T>, from: DepsNodeEx<T>, result: T[]) {
for (const dependency of node.dependencies) {
if (dependency === from) {
throw "has cycle";
}
this.toposort0(dependency, from, result);
}
if (!node.visited) {
result.push(node.value);
node.visited = true;
}
}
}
class DepsNodeEx<T> implements DependencyNode<T> {
readonly value: T;
readonly dependencies: DepsNodeEx<T>[] = [];
visited = false;
constructor(value: T) {
this.value = value;
}
dependsOn(node: DependencyNode<T>) {
this.dependencies.push(node as DepsNodeEx<T>);
}
}
export class DependencyManagerImpl<T> implements DependencyManager<T> {
private readonly map = new Map<DepsNodeImpl<T>, DepsNodeImpl<T>[]>();
createNode(value: T): DependencyNode<T> {
const node = new DepsNodeImpl(value, this);
const list: DepsNodeImpl<T>[] = [];
this.map.set(node, list);
return node;
}
toposort(): T[] {
if (this.map.size == 0) {
return [];
}
const result: T[] = [];
let size = 0;
while (size != this.map.size && this.map.size != 0) {
size = this.map.size;
for (const keyNode of this.map.keys()) {
if (keyNode.inDegree == 0) {
result.push(keyNode.value);
const list = this.map.get(keyNode);
this.map.delete(keyNode);
if (list != undefined) {
for (const valueNode of list) {
valueNode.inDegree--;
}
}
}
}
}
if (this.map.size != 0) {
throw "has cycle";
}
return result;
}
dependsOn(from: DepsNodeImpl<T>, to: DepsNodeImpl<T>) {
to.inDegree++;
const list = this.map.get(from);
if (list != undefined) {
list.push(to);
}
}
}
class DepsNodeImpl<T> implements DependencyNode<T> {
readonly value: T;
readonly manager: DependencyManagerImpl<T>;
inDegree = 0;
constructor(value: T, manager: DependencyManagerImpl<T>) {
this.value = value;
this.manager = manager;
}
dependsOn(node: DependencyNode<T>) {
this.manager.dependsOn(node as DepsNodeImpl<T>, this);
}
}
}
import DependencyManager = org.topo.DependencyManager;
import DependencyManagerEx = org.topo.DependencyManagerEx;
import DependencyManagerImpl = org.topo.DependencyManagerImpl;
function makeNodes(manager: DependencyManager<number>, cyclic: boolean = false): number[] {
const task1 = manager.createNode(1);
const task6 = manager.createNode(6);
const task7 = manager.createNode(7);
const task4 = manager.createNode(4);
const task8 = manager.createNode(8);
const task5 = manager.createNode(5);
const task3 = manager.createNode(3);
const task9 = manager.createNode(9);
const task11 = manager.createNode(11);
task4.dependsOn(task1);
task4.dependsOn(task3);
task4.dependsOn(task8);
task5.dependsOn(task6);
task5.dependsOn(task9);
task7.dependsOn(task4);
task7.dependsOn(task5);
task11.dependsOn(task9);
if (cyclic) {
task1.dependsOn(task7);
}
return manager.toposort();
}
(function main() {
console.log(makeNodes(new DependencyManagerEx())); // [1, 6, 3, 8, 4, 9, 5, 7, 11]
console.log(makeNodes(new DependencyManagerImpl())); // [1, 6, 8, 3, 9, 11, 4, 5, 7]
console.log(new DependencyManagerEx().toposort()); // []
console.log(new DependencyManagerImpl().toposort()); // []
try {
console.log(makeNodes(new DependencyManagerEx(), true));
} catch (e) {
console.log(e); // has cycle
}
try {
console.log(makeNodes(new DependencyManagerImpl(), true));
} catch (e) {
console.log(e); // has cycle
}
})();