Oliver Eyton-Williams ee1e8abd87
feat(curriculum): restore seed + solution to Chinese (#40683)
* feat(tools): add seed/solution restore script

* chore(curriculum): remove empty sections' markers

* chore(curriculum): add seed + solution to Chinese

* chore: remove old formatter

* fix: update getChallenges

parse translated challenges separately, without reference to the source

* chore(curriculum): add dashedName to English

* chore(curriculum): add dashedName to Chinese

* refactor: remove unused challenge property 'name'

* fix: relax dashedName requirement

* fix: stray tag

Remove stray `pre` tag from challenge file.

Signed-off-by: nhcarrigan <nhcarrigan@gmail.com>

Co-authored-by: nhcarrigan <nhcarrigan@gmail.com>
2021-01-12 19:31:00 -07:00

167 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: 587d825c367417b2b2512c90
title: 广度优先搜索
challengeType: 1
videoUrl: ''
dashedName: breadth-first-search
---
# --description--
到目前为止,我们已经学会了创建图表表示的不同方法。现在怎么办?一个自然的问题是图中任何两个节点之间的距离是多少?输入<dfn>图遍历算法</dfn><dfn>遍历算法</dfn>是遍历或访问图中节点的算法。一种遍历算法是广度优先搜索算法。该算法从一个节点开始,首先访问一个边缘的所有邻居,然后继续访问它们的每个邻居。在视觉上,这就是算法正在做的事情。 ![广度优先搜索算法遍历](https://camo.githubusercontent.com/2f57e6239884a1a03402912f13c49555dec76d06/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f342f34362f416e696d617465645f4246532e676966)要实现此算法,您需要输入图形结构和要启动的节点。首先,您需要了解距起始节点的距离。这个你想要开始你所有的距离最初一些大的数字,如`Infinity` 。这为从起始节点无法访问节点的情况提供了参考。接下来,您将要从开始节点转到其邻居。这些邻居是一个边缘,此时你应该添加一个距离单位到你要跟踪的距离。最后,有助于实现广度优先搜索算法的重要数据结构是队列。这是一个数组,您可以在其中添加元素到一端并从另一端删除元素。这也称为<dfn>FIFO</dfn><dfn>先进先出</dfn>数据结构。
# --instructions--
编写一个函数`bfs()` ,它将邻接矩阵图(二维数组)和节点标签根作为参数。节点标签只是`0``n - 1`之间节点的整数值,其中`n`是图中节点的总数。您的函数将输出JavaScript对象键值对与节点及其与根的距离。如果无法到达节点则其距离应为`Infinity`
# --hints--
输入图`[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]` ,起始节点为`1`应该返回`{0: 1, 1: 0, 2: 1, 3: 2}`
```js
assert(
(function () {
var graph = [
[0, 1, 0, 0],
[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0]
];
var results = bfs(graph, 1);
return isEquivalent(results, { 0: 1, 1: 0, 2: 1, 3: 2 });
})()
);
```
输入图`[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]` ,起始节点为`1`应该返回`{0: 1, 1: 0, 2: 1, 3: Infinity}`
```js
assert(
(function () {
var graph = [
[0, 1, 0, 0],
[1, 0, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 0]
];
var results = bfs(graph, 1);
return isEquivalent(results, { 0: 1, 1: 0, 2: 1, 3: Infinity });
})()
);
```
输入图`[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]` ,起始节点为`0`应该返回`{0: 0, 1: 1, 2: 2, 3: 3}`
```js
assert(
(function () {
var graph = [
[0, 1, 0, 0],
[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0]
];
var results = bfs(graph, 0);
return isEquivalent(results, { 0: 0, 1: 1, 2: 2, 3: 3 });
})()
);
```
起始节点为`0`的输入图`[[0, 1], [1, 0]]`应返回`{0: 0, 1: 1}`
```js
assert(
(function () {
var graph = [
[0, 1],
[1, 0]
];
var results = bfs(graph, 0);
return isEquivalent(results, { 0: 0, 1: 1 });
})()
);
```
# --seed--
## --after-user-code--
```js
// Source: http://adripofjavascript.com/blog/drips/object-equality-in-javascript.html
function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
// If values of same property are not equal,
// objects are not equivalent
if (a[propName] !== b[propName]) {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
```
## --seed-contents--
```js
function bfs(graph, root) {
var nodesLen = {};
return nodesLen;
};
var exBFSGraph = [
[0, 1, 0, 0],
[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0]
];
console.log(bfs(exBFSGraph, 3));
```
# --solutions--
```js
function bfs(graph, root) {
var nodesLen = {};
// Set all distances to infinity
for (var i = 0; i < graph.length; i++) {
nodesLen[i] = Infinity;
}
nodesLen[root] = 0; // ...except root node
var queue = [root]; // Keep track of nodes to visit
var current; // Current node traversing
// Keep on going until no more nodes to traverse
while (queue.length !== 0) {
current = queue.shift();
// Get adjacent nodes from current node
var curConnected = graph[current]; // Get layer of edges from current
var neighborIdx = []; // List of nodes with edges
var idx = curConnected.indexOf(1); // Get first edge connection
while (idx !== -1) {
neighborIdx.push(idx); // Add to list of neighbors
idx = curConnected.indexOf(1, idx + 1); // Keep on searching
}
// Loop through neighbors and get lengths
for (var j = 0; j < neighborIdx.length; j++) {
// Increment distance for nodes traversed
if (nodesLen[neighborIdx[j]] === Infinity) {
nodesLen[neighborIdx[j]] = nodesLen[current] + 1;
queue.push(neighborIdx[j]); // Add new neighbors to queue
}
}
}
return nodesLen;
}
```