186 lines
5.4 KiB
Markdown
186 lines
5.4 KiB
Markdown
![]() |
---
|
||
|
id: 594fa2746886f41f7d8bf225
|
||
|
title: トポロジカルソート
|
||
|
challengeType: 5
|
||
|
forumTopicId: 302340
|
||
|
dashedName: topological-sort
|
||
|
---
|
||
|
|
||
|
# --description--
|
||
|
|
||
|
項目間のマッピングが与えられ、項目間に依存関係があるとき、トポロジカルソートは、項目がその依存している項目に先行しないように項目を並べます。 トポロジカルソートには、カーン (1962年) のトポロジカルソートと、深さ優先探索という、2つの一般的なアルゴリズムがあります。
|
||
|
|
||
|
# --instructions--
|
||
|
|
||
|
依存関係からのライブラリの有効なコンパイル順でリストを返す関数を記述してください。
|
||
|
|
||
|
- ライブラリ名は 1 つの単語とします。
|
||
|
- 依存する側としてのみ記載されている項目には、自身に依存している項目はありませんが、そのコンパイル順は規定される必要があります。
|
||
|
- 自己依存関係はすべて無視する必要があります。
|
||
|
- 順序付けできない依存関係はすべて無視する必要があります。
|
||
|
|
||
|
次のデータを例として使用します。
|
||
|
|
||
|
<pre>
|
||
|
LIBRARY LIBRARY DEPENDENCIES
|
||
|
======= ====================
|
||
|
des_system_lib std synopsys std_cell_lib des_system_lib dw02 dw01 ramlib ieee
|
||
|
dw01 ieee dw01 dware gtech
|
||
|
dw02 ieee dw02 dware
|
||
|
dw03 std synopsys dware dw03 dw02 dw01 ieee gtech
|
||
|
dw04 dw04 ieee dw01 dware gtech
|
||
|
dw05 dw05 ieee dware
|
||
|
dw06 dw06 ieee dware
|
||
|
dw07 ieee dware
|
||
|
dware ieee dware
|
||
|
gtech ieee gtech
|
||
|
ramlib std ieee
|
||
|
std_cell_lib ieee std_cell_lib
|
||
|
synopsys
|
||
|
</pre>
|
||
|
|
||
|
VHDL言語のライブラリのコンパイルには、ライブラリが依存するライブラリの後にコンパイルされなければならないという制約があります。 例えば、 `dw04` が `dw01`の依存関係のリストに追加された場合、上記のデータは順序不能になります。
|
||
|
|
||
|
関数の入力は複数行の文字列になります。それぞれの行はライブラリの名前で構成され、それに依存しているもの (存在する場合) が続きます。
|
||
|
|
||
|
例えば:
|
||
|
|
||
|
```js
|
||
|
const libsSimple =
|
||
|
`aaa bbb
|
||
|
bbb`;
|
||
|
```
|
||
|
|
||
|
# --hints--
|
||
|
|
||
|
`topologicalSort` は関数とします。
|
||
|
|
||
|
```js
|
||
|
assert(typeof topologicalSort === 'function');
|
||
|
```
|
||
|
|
||
|
`topologicalSort(libsSimple)` は配列を返す必要があります。
|
||
|
|
||
|
```js
|
||
|
assert(Array.isArray(topologicalSort(libsSimple)));
|
||
|
```
|
||
|
|
||
|
`topologicalSort(libsSimple)` は `['bbb', 'aaa']` を返す必要があります。
|
||
|
|
||
|
```js
|
||
|
assert.deepEqual(topologicalSort(libsSimple), ['bbb', 'aaa']);
|
||
|
```
|
||
|
|
||
|
`topologicalSort(libsVHDL)` は `['ieee', 'std_cell_lib', 'gtech', 'dware', 'dw07', 'dw06', 'dw05', 'dw02', 'dw01', 'dw04', 'std', 'ramlib', 'synopsys', 'dw03', 'des_system_lib']` を返す必要があります。
|
||
|
|
||
|
```js
|
||
|
assert.deepEqual(topologicalSort(libsVHDL), ['ieee', 'std_cell_lib', 'gtech', 'dware', 'dw07', 'dw06', 'dw05', 'dw02', 'dw01', 'dw04', 'std', 'ramlib', 'synopsys', 'dw03', 'des_system_lib']);
|
||
|
```
|
||
|
|
||
|
`topologicalSort(libsCustom)` は `['base', 'c', 'd', 'b', 'a']` を返す必要があります。
|
||
|
|
||
|
```js
|
||
|
assert.deepEqual(topologicalSort(libsCustom), ['base', 'c', 'd', 'b', 'a']);
|
||
|
```
|
||
|
|
||
|
`topologicalSort` は順序付けできない依存関係を無視しなければなりません。
|
||
|
|
||
|
```js
|
||
|
assert.deepEqual(topologicalSort(libsUnorderable), ['Base']);
|
||
|
```
|
||
|
|
||
|
# --seed--
|
||
|
|
||
|
## --after-user-code--
|
||
|
|
||
|
```js
|
||
|
const libsSimple =
|
||
|
`aaa bbb
|
||
|
bbb`;
|
||
|
|
||
|
const libsVHDL =
|
||
|
`des_system_lib std synopsys std_cell_lib des_system_lib dw02 dw01 ramlib ieee
|
||
|
dw01 ieee dw01 dware gtech
|
||
|
dw02 ieee dw02 dware
|
||
|
dw03 std synopsys dware dw03 dw02 dw01 ieee gtech
|
||
|
dw04 dw04 ieee dw01 dware gtech
|
||
|
dw05 dw05 ieee dware
|
||
|
dw06 dw06 ieee dware
|
||
|
dw07 ieee dware
|
||
|
dware ieee dware
|
||
|
gtech ieee gtech
|
||
|
ramlib std ieee
|
||
|
std_cell_lib ieee std_cell_lib
|
||
|
synopsys`;
|
||
|
|
||
|
const libsCustom =
|
||
|
`a b c d
|
||
|
b c d
|
||
|
d c
|
||
|
c base
|
||
|
base`;
|
||
|
|
||
|
const libsUnorderable =
|
||
|
`TestLib Base MainLib
|
||
|
MainLib TestLib
|
||
|
Base`;
|
||
|
```
|
||
|
|
||
|
## --seed-contents--
|
||
|
|
||
|
```js
|
||
|
function topologicalSort(libs) {
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
# --solutions--
|
||
|
|
||
|
```js
|
||
|
function topologicalSort(libs) {
|
||
|
// A map of the input data, with the keys as the packages, and the values as
|
||
|
// and array of packages on which it depends.
|
||
|
const D = libs
|
||
|
.split('\n')
|
||
|
.map(e => e.split(' ').filter(ep => ep !== ''))
|
||
|
.reduce((p, c) =>
|
||
|
p.set(c[0], c.filter((e, i) => (i > 0 && e !== c[0] ? e : null))), new Map());
|
||
|
[].concat(...D.values()).forEach(e => {
|
||
|
D.set(e, D.get(e) || []);
|
||
|
});
|
||
|
|
||
|
// The above map rotated so that it represents a DAG of the form
|
||
|
// Map {
|
||
|
// A => [ A, B, C],
|
||
|
// B => [C],
|
||
|
// C => []
|
||
|
// }
|
||
|
// where each key represents a node, and the array contains the edges.
|
||
|
const G = [...D.keys()].reduce((p, c) =>
|
||
|
p.set(
|
||
|
c,
|
||
|
[...D.keys()].filter(e => D.get(e).includes(c))),
|
||
|
new Map()
|
||
|
);
|
||
|
|
||
|
// An array of leaf nodes; nodes with 0 in degrees.
|
||
|
const Q = [...D.keys()].filter(e => D.get(e).length === 0);
|
||
|
|
||
|
// The result array.
|
||
|
const S = [];
|
||
|
while (Q.length) {
|
||
|
const u = Q.pop();
|
||
|
S.push(u);
|
||
|
G.get(u).forEach(v => {
|
||
|
D.set(v, D.get(v).filter(e => e !== u));
|
||
|
if (D.get(v).length === 0) {
|
||
|
Q.push(v);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return S;
|
||
|
}
|
||
|
```
|