en.javascript.info/1-js/4-data-structures/8-array-methods/9-output-single-linked-list/solution.md
2015-01-11 01:54:57 +03:00

142 lines
No EOL
4.3 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.

# Вывод списка в цикле
```js
//+ run
var list = {
value: 1, next: {
value: 2, next: {
value: 3, next: {
value: 4, next: null
}
}
}
};
function printList(list) {
var tmp = list;
while(tmp) {
alert( tmp.value );
tmp = tmp.next;
}
}
printList(list);
```
Обратите внимание, что для прохода по списку используется временная переменная `tmp`, а не `list`. Можно было бы и бегать по списку, используя входной параметр функции:
```js
function printList(list) {
while(*!*list*/!*) {
alert( list.value );
list = list.next;
}
}
```
...Но при этом мы в будущем не сможем расширить функцию и сделать со списком что-то ещё, ведь после окончания цикла начало списка уже нигде не хранится.
Поэтому и используется временная переменная -- чтобы сделать код расширяемым, и, кстати, более понятным, ведь роль `tmp` -- исключительно обход списка, как `i` в цикле `for`.
# Вывод списка с рекурсией
Рекурсивный вариант `printList(list)` следует простой логике: вывести текущее значение `(1)`, а затем пропустить через себя следующее `(2)`:
```js
//+ run
var list = {
value: 1, next: {
value: 2, next: {
value: 3, next: {
value: 4, next: null
}
}
}
};
function printList(list) {
alert(list.value); // (1)
if (list.next) {
printList(list.next); // (2)
}
}
printList(list);
```
# Обратный вывод с рекурсией
Обратный вывод -- почти то же самое, что прямой, просто сначала мы обрабатываем следующее значение, а потом -- текущее:
```js
//+ run
var list = {
value: 1, next: {
value: 2, next: {
value: 3, next: {
value: 4, next: null
}
}
}
};
function printReverseList(list) {
if (list.next) {
printReverseList(list.next);
}
alert(list.value);
}
printReverseList(list);
```
# Обратный вывод без рекурсии
```js
//+ run
var list = {
value: 1, next: {
value: 2, next: {
value: 3, next: {
value: 4, next: null
}
}
}
};
function printReverseList(list) {
var arr = [];
var tmp = list;
while(tmp) {
arr.push(tmp.value);
tmp = tmp.next;
}
for( var i = arr.length-1; i>=0; i-- ) {
alert( arr[i] );
}
}
printReverseList(list);
```
**Обратный вывод без рекурсии быстрее.**
По сути, рекурсивный вариант и нерекурсивный работают одинаково: они проходят список и запоминают его элементы, а потом выводят в обратном порядке.
В случае с массивом это очевидно, а для рекурсии запоминание происходит в стеке (внутренней специальной структуре данных): когда вызывается вложенная функция, то интерпретатор сохраняет в стек текущие параметры. Вложенные вызовы заполняют стек, а потом он выводится в обратном порядке.
При этом, при рекурсии в стеке сохраняется не только элемент списка, а другая вспомогательная информация, необходимая для возвращения из вложенного вызова. Поэтому тратится больше памяти. Все эти расходы отсутствуют во варианте без рекурсии, так как в массиве хранится именно то, что нужно.
Преимущество рекурсии, с другой стороны -- более короткий и, зачастую, более простой код.