Необходимо различать структуру данных связанного списка и любой тип данных, подобный списку, который вы реализуете со связанным списком.Вы можете сделать ровно две вещи, чтобы изменить связанный список: добавить новый заголовок к списку и удалить текущий заголовок (если связанный список не пустой).
Вариант использования, о котором говорится в цитате:общий для типа данных очереди: вы можете добавить к одному концу и удалить с другого конца.Вы можете реализовать это, используя два связанных списка, добавляя новые элементы в один список и удаляя элементы из другого.Реализация очереди по мере необходимости заботится об обратном направлении, чтобы гарантировать, что вы никогда не удалите элемент до того, как будет удален любой другой ранее вставленный элемент.
data Queue a = Queue [a] [a]
-- Put new elements on the incoming list.
addToQueue :: a -> Queue a -> Queue a
addToQueue x (Queue incoming outgoing) = Queue (x:incoming) outgoing
-- Take elements from the outgoing list, whose elements are stored
-- in the reverse order that they were added to the incoming list
-- previously.
removeFromQueue :: Queue a -> (a, Queue a)
removeFromQueue (Queue [] []) = error "Cannot remove from empty queue"
removeFromQueue (Queue incoming (x:xs)) = (x, Queue incoming xs)
removeFromQueue (Queue incoming []) = removeFromQueue (Queue [] (reverse incoming))
(Мы не заинтересованы в хороших способах удаленияиз пустой очереди здесь, просто назовите это ошибкой и оставьте это при этом.)
Добавить в список входящих и удалить из списка исходящих просто.Самое сложное в том, как и когда мы переносим элементы из входящего списка в исходящий список.Мы делаем это только тогда, когда исходящий список пуст, и когда он есть, мы сразу передаем весь входящий список, обращая его в процессе.Другими словами, мы строим входящий список в обратном порядке, но обращаем его только в случае необходимости, а не после добавления каждого отдельного элемента.
Амортизированный анализ можно использовать, чтобы показать, что хотя reverse
может быть медленным, оно уравновешивается количеством быстрых операций, которые предшествуют и могут следовать за ним.