Skip to main content

Связный список

Прямой обход

Описание

Задача состоит в том, чтобы обойти (посетить каждый узел) связный список в прямом порядке (от головы до хвоста).

Например, для такого связного списка:


Порядок обхода будет следующим:

12 → 99 → 37

Сложность

Временная сложность данного алгоритма составляет O(n), поскольку мы должны посетить каждый узел и делаем это один раз.

Реализация

Реализация алгоритма до неприличия проста:

// algorithms/linked-lists/traverse.js
// Функция принимает связный список и обработчик посещения узла
export default function traverse(list, cb) {
// Берем головной узел
let node = list.head

// Пока есть узлы
while (node) {
// Обрабатываем узел
cb(node.value)
// Берем следующий
node = node.next
}
}

Тестирование

// algorithms/linked-lists/__tests__/traverse.js
import LinkedList from '../../../data-structures/linked-list'
import traverse from '../traverse'

describe('traverse', () => {
it('должен обойти связный список в прямом порядке', () => {
const linkedList = new LinkedList()

linkedList.append(1).append(2).append(3)

const nodeValues = []
const traversalCallback = (nodeValue) => {
nodeValues.push(nodeValue)
}

traverse(linkedList, traversalCallback)

expect(nodeValues).toEqual([1, 2, 3])
})
})

Обратный обход

Описание

Задача состоит в том, чтобы обойти (посетить каждый узел) связный список в обратном порядке (от хвоста до головы).

Например, для такого связного списка:


Порядок обхода будет следующим:

37 → 99 → 12

Сложность

Временная сложность данного алгоритма составляет O(n), поскольку мы должны посетить каждый узел и делаем это один раз.

Реализация

Для обхода списка в обратном порядке достаточно применить рекурсию:

// algorithms/linked-lists/reversal-traverse.js
// Функция принимает узел и обработчик его посещения
function reversalTraverseRecursive(node, cb) {
// Пока есть узел
if (node) {
// Вызываем функцию со следующим узлом
reversalTraverseRecursive(node.next, cb)
// Обрабатываем узел
cb(node.value)
}
}

// Функция принимает связный список и обработчик посещения узла
export default function reversalTraverse(list, cb) {
// Для того, чтобы понять рекурсию, надо сначала понять рекурсию :)
reversalTraverseRecursive(list.head, cb)
}

Тестирование

// algorithms/linked-lists/__tests__/reversal-traverse.js
import LinkedList from '../../../data-structures/linked-list'
import reversalTraverse from '../reversal-traverse'

describe('reversalTraverse', () => {
it('должен обойти связный список в обратном порядке', () => {
const linkedList = new LinkedList()

linkedList.append(1).append(2).append(3)

const nodeValues = []
const traversalCallback = (nodeValue) => {
nodeValues.push(nodeValue)
}

reversalTraverse(linkedList, traversalCallback)

expect(nodeValues).toEqual([3, 2, 1])
})
})

Запускаем тесты:

npm run test ./algorithms/linked-lists/__tests__