Вивести одинозв’язаний список
Скажімо, у нас є одинозв’язаний список (як описано в розділі Рекурсія та стек):
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
, то ми втрачаємо таку здатність.
Говорячи про хороші імена змінних, 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)
;
Що ж тепер краще?
Технічно цикл є більш ефективним. Ці два варіанти роблять те ж саме, але цикл не витрачає ресурси для вкладених викликів.
З іншого боку, рекурсивний варіант коротший, а іноді його легше зрозуміти.