我注意到Scheme和Lisp(我猜)支持循环列表,我在C / C ++中使用循环列表来“简化”元素的插入和删除,但它们有什么用呢?
Scheme确保可以构建和处理它们,但是为了什么?
是否存在需要为圆形或尾循环的'杀手'数据结构?
答案 0 :(得分:6)
说它支持'循环列表'有点多。您可以在Lisp中构建各种循环数据结构。就像许多编程语言一样。关于Lisp在这方面没有太多特别之处。采用典型的“算法和数据结构”一书并实现任何循环数据结构:图形,环,......一些Lisps提供的是可以打印和读取循环数据结构。对此的支持是因为在典型的Lisp编程领域中,循环数据结构很常见:解析器,关系表达式,单词网络,计划,......
数据结构包含循环是很常见的。真正的“循环列表”并不经常使用。例如,考虑运行任务的任务调度程序,并在一段时间后切换到下一个任务。任务列表可以是循环的,以便在“最后”任务之后,调度程序执行“第一个”任务。实际上没有'last'和'first' - 它只是一个循环的任务列表,而调度程序运行它们没有结束。您还可以在窗口系统中有一个窗口列表,并使用一些键命令切换到下一个窗口。窗口列表可以是循环的。
当您需要廉价的下一步操作并且数据结构的大小事先未知时,列表非常有用。您始终可以将另一个节点添加到列表中,或从列表中删除节点。列表的通常实现使得获取下一个节点并且廉价地添加/移除项目。从数组中获取下一个元素也相对简单(增加索引,在最后一个索引转到第一个索引),但添加/删除元素通常需要更昂贵的移位操作。
此外,由于构建循环数据结构很容易,因此在交互式编程期间可能会这样做。如果然后使用内置例程打印循环数据结构,那么打印机是否可以处理它是个好主意,否则它可能永远打印循环列表......
答案 1 :(得分:4)
你玩过大富翁吗?
如果不使用计数器和模数等游戏,你会如何在游戏的计算机实现中代表Monopoly板?循环清单是很自然的。
答案 2 :(得分:2)
例如,双链表数据结构在Scheme / LISP的观点中是“循环的”,即如果你试图打印出cons-structure,你会得到反向引用,即“循环”。所以它并不是真的让数据结构看起来像“环”,任何具有某种后退指针的数据结构都是从Scheme / LISP的角度来看是“循环的”。
“正常”LISP列表是单链接的,这意味着从列表内部删除项目的破坏性突变是O(n)操作;对于双链表,它是O(1)。这是双链表的“杀手级功能”,在Scheme / LISP环境中是“循环的”。
答案 3 :(得分:2)
在列表的开头添加和删除元素很便宜。至 添加或删除列表末尾的元素,您必须遍历 整个清单。
使用循环列表,您可以拥有一种固定长度的队列。
设置长度为5的循环列表:
> (import (srfi :1 lists))
> (define q (circular-list 1 2 3 4 5))
让我们在列表中添加一个数字:
> (set-car! q 6)
现在,让我们把它作为列表的最后一个元素:
> (set! q (cdr q))
显示列表:
> (take q 5)
(2 3 4 5 6)
因此,您可以将其视为一个队列,其中元素在列表末尾输入并从头部删除。
让我们在列表中添加7:
> (set-car! q 7)
> (set! q (cdr q))
> (take q 5)
(3 4 5 6 7)
等等...
无论如何,这是我使用循环列表的一种方式。
我在OpenGL demo中使用此技术,我从Processing book中的示例移植。
版
答案 4 :(得分:0)
圆形列表的一个用途是在使用srfi-1版本的地图时“重复”值。例如,要将val
添加到lst
的每个元素,我们可以写:
(map + (circular-list val) lst)
例如:
(map + (circular-list 10) (list 0 1 2 3 4 5))
返回:
(10 11 12 13 14 15)
当然,您可以将+
替换为(lambda (x) (+ x val))
来实现此目的,但有时候上述习惯用语更方便。请注意,这仅适用于srfi-1版本的map,它可以接受不同大小的列表。