我正在寻找支持以下操作的功能数据结构:
正常的功能链接列表仅支持O(n)追加,而我可以使用普通LL然后反转它,反向操作也是O(n),它(部分地)否定O(1)缺点操作
答案 0 :(得分:9)
你可以使用John Hughes的常数追加列表,这些列表现在似乎被称为DList
。表示是从列表到列表的函数:空列表是标识函数;追加是组合,单身是缺点(部分应用)。在此表示中,每个枚举将花费您n
分配,因此可能不太好。
另一种方法是将相同的代数作为数据结构:
type 'a seq = Empty | Single of 'a | Append of 'a seq * 'a seq
枚举是一个树遍历,它要么花费一些堆栈空间,要么需要某种拉链表示。这是一个转换为list但使用堆栈空间的树遍历:
let to_list t =
let rec walk t xs = match t with
| Empty -> xs
| Single x -> x :: xs
| Append (t1, t2) -> walk t1 (walk t2 xs) in
walk t []
这是相同的,但使用不变的堆栈空间:
let to_list' t =
let rec walk lefts t xs = match t with
| Empty -> finish lefts xs
| Single x -> finish lefts (x :: xs)
| Append (t1, t2) -> walk (t1 :: lefts) t2 xs
and finish lefts xs = match lefts with
| [] -> xs
| t::ts -> walk ts t xs in
walk [] t []
您可以编写一个折叠函数来访问相同的元素,但实际上并没有重新列出该列表;只需用更通用的东西替换cons和nil:
val fold : ('a * 'b -> 'b) -> 'b -> 'a seq -> 'b
let fold f z t =
let rec walk lefts t xs = match t with
| Empty -> finish lefts xs
| Single x -> finish lefts (f (x, xs))
| Append (t1, t2) -> walk (t1 :: lefts) t2 xs
and finish lefts xs = match lefts with
| [] -> xs
| t::ts -> walk ts t xs in
walk [] t z
这是你的线性时间,常量堆栈枚举。玩得开心!
答案 1 :(得分:5)
我相信你可以使用标准功能链表:
答案 2 :(得分:5)
差异清单怎么样?
type 'a DList = DList of ('a list -> 'a list)
module DList =
let append (DList f) (DList g) = (DList (f << g))
let cons x (DList f) = (DList (fun l -> x::(f l)))
let snoc (DList f) x = (DList (fun l -> f(x::l)))
let empty = DList id
let ofList = List.fold snoc empty
let toList (DList f) = f []
答案 3 :(得分:1)
circularly-linked list怎么样?它支持O( 1 )追加和O( n )迭代。
答案 4 :(得分:1)
您可以创建一个功能性Deque,它可以向任意一端添加O(1)
,并在任一方向上提供O(N)
迭代。 Eric Lippert写了一篇关于不可变的Deque on his blog的有趣版本的文章,如果你环顾四周,你会发现该系列的其他部分,但这是对最终产品的解释。另请注意,通过稍微调整,可以修改它以利用F#区分联合和模式匹配(尽管这取决于您)。
此版本的另一个有趣属性,O(1)
从任一端偷看,删除和添加(即dequeueLeft,dequeueRight,dequeueLeft,dequeueRight等仍然是O(N),而O(N * N) )使用双列表方法)。