Связанные списки — это важная для понимания структура данных. Хотя они не так популярны, как массивы, в некоторых случаях они более эффективны. В этом блоге я расскажу об основах связанных списков и обсужу, как объединить отсортированный связанный список.
Создание односвязного списка
Логика односвязных списков относительно проста: у вас есть набор узлов, и каждый узел указывает на следующий узел в последовательности. Однако реализация связанного списка в коде может быть немного сложной, в первую очередь из-за синтаксиса и концепций, которые вам необходимо усвоить. Один из часто используемых подходов к созданию связанного списка — определение конструктора.
class ListNode { constructor(val, next = null) { this.val = val this.next = next } }
После создания конструктора мы можем создать связанный список следующим образом.
// create and connect nodes const node1 = new ListNode(1) node1.next = new ListNode(2) node1.next.next = new ListNode(3) console.log(node1) /* output: -> ListNode { val: 1, next: ListNode { val: 2, next: ListNode { val: 3, next: null } } } */
Как только список создан, мы можем перебирать его следующим образом.
let current = node1 while(current) { console.log(current.val) current = current.next } // output: 1 -> 2 -> 3
Объединение двух отсортированных списков
Теперь, когда мы понимаем основы связанного списка, мы можем объединить отсортированный список. Здесь у нас есть два списка: список 1 и список 2:
function ListNode(val, next) { this.val = val this.next = next || null } const list1 = new ListNode(1); list1.next = new ListNode(2); list1.next.next = new ListNode(3); console.log(list1) /* output: -> ListNode { val: 1, next: ListNode { val: 2, next: ListNode { val: 3, next: null } } } */ const list2 = new ListNode(1); list2.next = new ListNode(1); list2.next.next = new ListNode(4); console.log(list2) /* output: -> ListNode { val: 1, next: ListNode { val: 1, next: ListNode { val: 4, next: null } } }*/
Теперь, когда у нас есть оба списка, мы можем создать функцию слияния.
function mergeSortedLists(list1, list2) { // Initialize a dummy node as the head of the merged list const dummyNode = new ListNode(0); // Set a pointer to the current node, initially pointing to the dummy node let current = dummyNode; // Iterate through both lists while both contain elements while (list1 !== null && list2 !== null) { // Compare the values of the current nodes if (list1.val < list2.val) { // Set the current.next to the smaller list1 value current.next = list1; // Move the list1 pointer to the next node list1 = list1.next; } else { // Set the current.next to the smaller list2 value current.next = list2; // Move the list2 pointer to the next node list2 = list2.next; } // Move 'current' to the newly added node current = current.next; } // After the loop, one of the lists might still have remaining elements // Check which list has remaining elements and append them to the merged list if (list1 !== null) { current.next = list1; } else { current.next = list2; } // The merged list starts from the node after the dummy node return dummyNode.next; }
Короче говоря, эта функция создает фиктивный узел в качестве отправной точки объединенного списка. Затем он эффективно объединяет два отсортированных связанных списка, проходя по обоим спискам и добавляя меньшее значение к этому фиктивному узлу. Кроме того, он проверяет, остались ли элементы list1
или list2
после основного цикла слияния, и добавляет все оставшиеся элементы в объединенный список перед возвратом окончательного списка.
В заключение я хочу признать, что недавно углубился в мир связанных списков в JavaScript. Изучение этих концепций было одновременно трудным и полезным. Продолжая исследовать тонкости структур данных и алгоритмов, я надеюсь, что этот пост в блоге послужит полезным ресурсом для тех, кто также находится на пути непрерывного обучения.