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