【发布时间】:2016-04-24 23:49:02
【问题描述】:
为什么在性能方面复合词比列表更受欢迎? 例如,
matrix(row(1,2,3),row(1,2,3),row(1,2,3))
优于
[[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
【问题讨论】:
标签: prolog
为什么在性能方面复合词比列表更受欢迎? 例如,
matrix(row(1,2,3),row(1,2,3),row(1,2,3))
优于
[[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
【问题讨论】:
标签: prolog
首先,明确一点:列表是一种复合词。
要查看列表是什么,请使用write_canonical/1。例如,使用 GNU Prolog:
| ?- write_canonical([1,2,3]).
'.'(1,'.'(2,'.'(3,[])))
关于内存中的表示,我推荐 Richard O'Keefe 的书。系统之间的细节有所不同,但您可以确定要在内存中表示术语 row(1,2,3),您需要:
对于术语.(1, .(2, .(3, []) 在直接的内存表示中,您需要:
'.'/2 函子[])。由此,您已经看到,在这种表示形式中,使用列表至少会占用大约 两倍 的内存。
您可以自己执行一些简单的测试,以帮助您了解这些表示在您的系统中的内存消耗差异。
【讨论】:
[] 和术语'.'/2,因此(浅)第一个参数索引无法区分(例如)长度为1、2、3 等的列表。赞成列表:您的Prolog 系统可能对复合术语的arity 有固有的限制,因此在某些情况下,可能需要使用类似列表的结构来表示非常多元素的集合。 Richard 的书包含有关这两个方面的更有价值的信息以及更多信息。
其他(优秀)答案没有提到的事情:
通过位置访问列表成员意味着您需要遍历列表。应该可以在恒定时间内访问术语的参数。因此,对于随机访问,术语应该更有效。
顺便说一句:您可以尝试使列表遍历速度稍微快一些。但是SWI-Prolog implementation of nth0_det/3 几乎是绝望的气味;)
您可能对this thread 感兴趣,尤其是。 this summary 谈论列表和术语等。
遵循一些经验法则。
用例:
效率:
从最后一点开始:尝试寻找使用链表而不是随机访问数组的算法。这并不总是可能的,但对于许多问题,您可以选择。经典的例子是快速排序与归并排序:在 Prolog 中,归并排序肯定更快。
无论哪种方式,首先确保你做对了,然后再担心效率。并确保在开始优化之前衡量性能瓶颈。
当然,选择最佳算法和数据结构意味着您需要了解您的问题和可用的工具。与您的问题无关,但曾经是 C++ 的“标准模板库”的美妙之处在于,对于算法和数据结构,时间复杂度(“大 O 表示法”)是固有属性,而不是实现细节。
【讨论】:
=.. 相当快。我想知道将列表变成一个术语并使用nb_setarg 进行交换是否会使快速排序更快(这也可能避免相当多的垃圾创建/收集?)。不知道这算不算“作弊”。
另一方面是访问特定元素时的时间性能。使用列表,您可以线性访问其元素。但是使用functor(arg1, arg2, ..., argn, ...) 形式的复合术语,我们可以使用标准的arg/3 内置谓词来不断访问任何参数。 IE。 O(N) 与 O(1) 与任何合理的 Prolog 实现。
但是对于您提出的问题,没有明确的答案。最佳解决方案取决于您要解决的特定问题。例如,使用列表对所有参数应用操作可能会更快(与使用基于arg/3 的解决方案相比)。但这也取决于使用的 Prolog 系统。如果性能是主要关注点,那么基准测试是关键。只需避免在微观层面上进行操作,而是考虑如何在应用程序的所有处理它的部分中创建和访问术语。
【讨论】: