Вывод односвязного списка
Допустим, у нас есть односвязный список (как описано в главе Рекурсия и стек):
let list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
Напишите функцию printList(list)
, которая выводит элементы списка по одному.
Сделайте два варианта решения: используя цикл и через рекурсию.
Как лучше: с рекурсией или без?
Решение с использованием цикла
Решение с использованием цикла:
let list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
function printList(list) {
let tmp = list;
while (tmp) {
alert(tmp.value);
tmp = tmp.next;
}
}
printList(list);
Обратите внимание, что мы используем временную переменную tmp
для перемещения по списку. Технически, мы могли бы использовать параметр функции list
вместо неё:
function printList(list) {
while(list) {
alert(list.value);
list = list.next;
}
}
…Но это было бы неблагоразумно. В будущем нам может понадобиться расширить функцию, сделать что-нибудь ещё со списком. Если мы меняем list
, то теряем такую возможность.
Говоря о хороших именах для переменных, list
здесь – это сам список, его первый элемент. Так и должно быть, это просто и понятно.
С другой стороны, tmp
используется исключительно для обхода списка, как i
в цикле for
.
Решение через рекурсию
Рекурсивный вариант printList(list)
следует простой логике: для вывода списка мы должны вывести текущий list
, затем сделать то же самое для list.next
:
let list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
function printList(list) {
alert(list.value); // выводим текущий элемент
if (list.next) {
printList(list.next); // делаем то же самое для остальной части списка
}
}
printList(list);
Какой способ лучше?
Технически, способ с циклом более эффективный. В обеих реализациях делается то же самое, но для цикла не тратятся ресурсы для вложенных вызовов.
С другой стороны, рекурсивный вариант более короткий и, возможно, более простой для понимания.