何时以及为何在 CL 中使用哈希表而不是 a-list?

Vin*_*inn 2 hashtable sbcl common-lisp data-structures

我一直使用 a-lists。

您何时以及为何(或应该)使用哈希表?

我不愿意使用它们是因为,与其他数据结构不同,CL 中的哈希表不是可见的列表。老实说,考虑到几乎所有东西都是列表,我觉得很奇怪。

也许我因缺乏经验而错过了一些东西?

Ren*_*nzo 6

当您必须通过键访问大量值时,散列表非常有用,因为使用散列表的操作复杂度为O(1),而使用 a-list 的操作复杂度为O( n),其中n是列表的长度。

因此,当我需要多次访问一组包含多个元素的值时,我会使用它。


cor*_*ump 5

您的问题中有很多假设需要解决:

我相信 Common Lisp 是我使用过的唯一一种拥有各种极其有用的数据结构的语言。

我不认为这是特别正确的,流行语言的标准库也充满了大量的数据结构(C++、Java、Rust、Python)

您何时以及为何(或应该)使用哈希表?

数据结构在内存和处理器使用方面存在成本:必须线性搜索列表才能找到元素,而哈希表具有恒定的查找成本:对于小型列表,线性搜索可能比恒定查找更快。此外,还有其他标准,例如:我是否要同时访问数据?列表可以以纯函数的方式进行操作,使得跨线程的数据共享比哈希表更容易(但哈希表可以与互斥锁等关联)

我不愿意使用它们是因为,与其他数据结构不同,CL 中的哈希表不是可见的列表。老实说,考虑到几乎所有东西都是列表,我觉得很奇怪。

Lisp 程序的源代码主要由列表和符号组成,即使没有这样的限制。但在运行时,CL 有许多与列表完全无关的不同类型:bignum、浮点数、有理数、复数、向量、数组、包、符号、字符串、类和结构、哈希表、可读表您可以通过将大量数据放入列表中来在运行时对它们进行建模,这在很多情况下都很有效,但到目前为止它们并不是唯一可用的类型。

只是强调一点,当你写下:

(vector 0 1 2)
Run Code Online (Sandbox Code Playgroud)

这可能看起来像代码中的列表,但在运行时该值实际上是一种不同类型的对象,即向量。不要对代码中事物的表达方式以及代码执行期间的表示方式感到困惑。

如果您还没有使用它,我建议安装并使用 Alexandria Lisp 库(请参阅https://alexandria.common-lisp.dev/)。有一些有用的函数可以将 alist 或 plist 与哈希表进行相互转换。

更一般地说,我认为以隐藏实现细节的方式构建库和程序非常重要:定义函数make-person和访问器person-ageperson-name以及其他面向用户的函数。实际的实现可以使用哈希表、列表等。但这并不是真正应该暴露的问题,因为暴露它是有风险的:如果您发现以后您将无法轻易改变主意性能不好或者如果你想添加缓存、使用数据库等。

然而,我发现 CL 擅长制作漂亮的界面,并且不会带来太多意外的复杂性。

  • @Vinn——显式表示公开了实现细节。假设您想要处理一堆数据表,并且决定用 plist 表示这些表。您编写了一堆函数来对表进行操作。如果您将函数设计为在 plist 上显式操作,那么如果您认为列表或哈希表更好,则必须重写所有函数。大多数函数并不关心表的表示方式,它们只希望能够从表中获取所需的数据。 (2认同)
  • 相反,您可以编写一些通过显式操作 plist 来获取数据的函数。其他函数可以使用这些基本函数,而无需知道表是如何实现的。如果您需要更改表表示形式,则只需重写所有其他函数用于访问表的几个函数。 (2认同)