将元素添加到列表,然后反转

时间:2018-11-15 16:21:43

标签: list haskell reverse

我是learning Haskell,并试图理解列表。

通过研究,通常可以将元素添加到列表中

let numbers = [4,8,15,16,23,42] 
numbers ++ [56]

但引用this answer

  

如果您需要这样做,通常可以使用更好的结构方式   您的算法。例如,您可以按相反的顺序构建list   (在开头添加元素),并且仅在末尾调用reverse

代码

let numbers = [23,43,56]
let newNumbers = 69:numbers
reverse newNumbers

输出

[56,43,23,69]

问题

  1. 根据引用的答案,我编写的代码是否正确?
  2. 我想更好地理解术语,是否可以说我正在向head的{​​{1}}添加元素?据我了解,每个新元素都会是第一个元素,并且在我写list时会返回该值。

1 个答案:

答案 0 :(得分:3)

您需要区分链表数据结构和链表要实现的任何类似于列表的数据类型。您可以做两件事来修改链接列表:在列表前添加一个新标题,并删除当前标题(如果链接列表不为空)。

引号所讨论的用例对于队列数据类型很常见:您可以添加到一端,也可以从另一端删除。您可以使用两个链接列表来实现此目的,方法是将新元素添加到一个列表中,然后从另一个列表中删除元素。队列的实现会根据需要进行反向处理,以确保在删除之前插入的所有其他项目之前,不要删除任何项目。

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))

(我们不关心在这里处理从空队列中删除的好方法;只需将其称为错误并留在那儿即可。)

添加到传入列表中和从传出列表中删除很容易。棘手的部分是我们如何以及何时将项目从传入列表转移到传出列表。我们仅在传出列表为空时这样做,当它为空时,我们立即传送 entire 传入列表,并在此过程中将其反转。换句话说,我们正在反向建立传入列表, 但是只有在必要时才将其反转,而不是在添加每一项之后。

经摊销的分析可以显示,尽管reverse 可以变慢,但它可以由之前和之后可以执行的快速操作次数平衡。