Вы можете использовать Array
для решения с динамическим массивом , что также приведет к амортизированной стоимости, или вы можете внедрить двусвязные списки используя типы ref
и option
.Я связался с решениями C, поскольку такие решения аналогичны, хотя синтаксически более сложны в SML, и потому что я не смог найти никаких примеров в SML.Решение с двусвязным списком повлечет за собой затраты памяти, поскольку каждый узел упакован, но не будет амортизированной стоимости решения с динамическим массивом или полностью функциональной deque, которую вы описываете.
Функциональный двустороннийочереди были предметом многих исследований;в этой статье Википедии есть ссылки на несколько структур данных и подходы, основанные как на лени, так и нет.Я не знаю, кто из них O (1) ;кажется, что все они либо O (1) амортизируются, либо O (lg n) , но все еще эффективны.
Вот как нефункционально вдвойнеТип данных связанного списка может выглядеть следующим образом:
datatype 'a node = Node of { elem : 'a
, prev : 'a node option ref
, next : 'a node option ref
}
datatype 'a deque = Empty | NonEmpty of 'a node
У такой реализации есть некоторые недостатки:
Отслеживание ссылок не является синтаксически хорошим.В C вы можете написать
if (nd->prev) nd->prev->next = nd;
, но в SML это выглядит гораздо более неясным, если вы не определите набор вспомогательных функций для получения и установки предыдущих / следующих узлов.И даже когда вы это делаете, поскольку ссылки обычно не используются, ваши геттеры и сеттеры будут выглядеть нестандартно в отличие от синтаксиса указателей C.
Вы заново изобретаете нулевые указатели.Сама реализация хрупка, так как у вас могут быть случаи, когда предыдущий / следующий узел является ссылкой на NONE
, когда это не должно быть.Операции не будут выходить за пределы push, pop, shift и unshift, поэтому, когда вы их выполнили, вы можете положиться на тестирование (на основе единиц или свойств).Вы должны обязательно проверить это, я бы сказал, не покупая сильные стороны, обычно используемые ML.
Ваша очередь изменчива, так что теперь вы должны быть осторожны с тем, где вы проходитеэто вместе.Если ваше использование очереди входит в нарушенное состояние, вы не можете так легко найти источник, который вызвал его.Вы в основном кодируете C с более уродливым синтаксисом.
Итак, краткий ответ таков: Вы, безусловно, можете написать ту же реализацию, но язык не поощряет это, и функциональные программисты часто полагаются нанеизменяемые структуры данных с логарифмическим или амортизированным временем выполнения.