Ответ
Да, конечно. Связный список — это линейная структура данных, состоящая из узлов, где каждый узел хранит данные и ссылку (указатель) на следующий узел в последовательности. В двусвязном списке узел также хранит ссылку на предыдущий узел.
Реализация в Go
В Go можно легко реализовать односвязный список с помощью структур и указателей:
// Node представляет узел в списке
type Node[T any] struct {
data T
next *Node[T]
}
// LinkedList представляет сам список
type LinkedList[T any] struct {
head *Node[T]
size int
}
// Append добавляет новый узел в конец списка
func (l *LinkedList[T]) Append(data T) {
newNode := &Node[T]{data: data}
if l.head == nil {
l.head = newNode
} else {
current := l.head
for current.next != nil {
current = current.next
}
current.next = newNode
}
l.size++
}
В стандартной библиотеке Go есть пакет container/list
, который предоставляет готовую реализацию двусвязного списка.
Связные списки vs. Срезы (Slices)
Выбор между связным списком и срезом зависит от конкретной задачи.
Используйте связный список, когда:
- Нужны частые и быстрые вставки/удаления в начало или середину коллекции. Для списка это операция
O(1)
(если у вас есть указатель на узел), в то время как для среза этоO(n)
, так как требует сдвига всех последующих элементов. - Размер коллекции заранее неизвестен и часто меняется. Списки растут динамически без необходимости переаллокации всего массива, в отличие от срезов, которые при достижении
capacity
создают новый, больший массив и копируют в него все элементы.
Используйте срез (slice), когда:
- Нужен быстрый доступ к элементам по индексу. Доступ к элементу среза — это операция
O(1)
. В связном списке для доступа к i-тому элементу нужно пройтиi
узлов, что является операциейO(n)
. - Важна локальность данных в памяти (cache-friendliness). Элементы среза хранятся в памяти непрерывным блоком, что позволяет процессору эффективно их кешировать. Узлы списка могут быть разбросаны по всей памяти, что приводит к большему числу промахов кеша.
- Накладные расходы на память критичны. Каждый узел списка хранит не только данные, но и один или два указателя, что увеличивает общий расход памяти.
Итог: Срезы в Go являются более универсальной и в большинстве случаев более производительной структурой данных. Связные списки — это нишевый инструмент, который незаменим при определённых требованиях к операциям вставки и удаления.