кажется вполне поддаются рекурсивной реализации:
mergeQueues :: Queue a -> Queue a -> Queue a
mergeQueues qa qb =
merge qa qb emptyQueue
where
merge qa qb qr
| isEmpty qa = append qb qr
| otherwise = move (merge qb) qa qr
append q qr
| isEmpty q = qr
| otherwise = move append q qr
move f q qr =
let (val,q') = pop q
in f q' (push val qr)
Обратите внимание, что мы просто флип очереди вперед и назад, как мы рекурсию, чтобы чередовать их, пока один не пуст, в какой-то момент мы просто присоединяться от одного к другому.
Обратите внимание, что, хотя это длиннее императивной версии, заданной рибондом, это делает минимальное количество проверок isEmpty
. Если вы не возражаете делать столько проверок, сколько он делает в чуть более оптимизированной версии (учитывая значения isEmpty для переменных для повторного использования ниже), вы можете удалить функцию append
и просто продолжать звонить merge
вместо этого после добавления начального test to merge
, который проверяет, что обе очереди пусты и завершение рекурсии, если это так.
Для тех, кто не знаком с Haskell, мы проходим, чтобы переместить следующую функцию для вызова (это функциональное программирование более высокого порядка); в случае append
, это просто добавление в случае move
, который является «частично примененной» функцией перемещения: он получает первый параметр, qb
, применяемый до того, как мы назовем move
, а затем move
применяет другие два параметра.
Это звучит как разумная задача, которую можно встретить в повседневном бизнес-программировании. Однако, если это домашняя функция, я предлагаю вам внимательно изучить, как работает этот код, и я думаю, что вы что-то узнаете.
Кроме того, есть вероятность, что в приведенном выше коде есть ошибка; доказывая, что он работает (или обнаруживает ошибку), будет отличным упражнением.
Что вы хотите сделать, когда одна очередь выйдет быстрее, чем другая? Стоп? Продолжайте, игнорируя недостающие элементы из короткой очереди? Продолжайте, добавив нулевые элементы вместо недостающих элементов? –