lisp中的破坏性排序

时间:2015-04-18 03:47:12

标签: common-lisp practical-common-lisp

我正在阅读 Practical Common Lisp 。在chapter 11,中,它说明了有关排序的内容:

  

通常,在对序列进行排序后,您不会关心序列的未排序版本,因此允许SORTSTABLE-SORT在排序过程中销毁序列是有意义的。但这确实意味着您需要记住写下以下内容:

(setf my-sequence (sort my-sequence #'string<))

我尝试了以下代码:

CL-USER> (defparameter *a* #( 8 4 3 9 5 9 2 3 9 2 9 4 3)) 
*A*            
CL-USER> *a*
#(8 4 3 9 5 9 2 3 9 2 9 4 3)                                     
CL-USER> (sort *a* #'<)
#(2 2 3 3 3 4 4 5 8 9 9 9 9)
CL-USER> *a*
#(2 2 3 3 3 4 4 5 8 9 9 9 9)

在此代码中,我们可以看到变量*a*已被sort函数更改。

那么为什么这本书说要做作业是必要的呢?

我正在使用SBCL + Ubuntu 14.04 + Emacs + Slime

修改 在@Sylwester的评论之后,我添加了*a*的评估,因此很清楚该值已被更改。

2 个答案:

答案 0 :(得分:8)

如果您希望变量在之后包含正确的排序序列值,则必须执行赋值。如果您不关心它并且只想要sort的返回值,则不需要分配。

这有两个原因。首先,允许实现使用非破坏性复制来实现破坏性操作。其次,列表上的破坏性操作可以置换对象,使得传递给操作的值不再指向序列的第一个缺点。

以下是第二个问题的示例(在SBCL下运行):

(let ((xs (list 4 3 2 1)))
  (sort xs '<)
  xs)
=> (4)

如果我们添加作业:

(let ((xs (list 4 3 2 1)))
  (setf xs (sort xs '<))
  xs)
=> (1 2 3 4)

答案 1 :(得分:6)

变量不能被sort函数改变,因为sort函数根本不知道变量。

所有sort函数get都是向量或列表,但不是变量。

在Common Lisp中,sort函数可能具有破坏性。 当它获得用于排序的向量时,它可以返回相同的向量或新的向量。这取决于实现。在一个实现中,它可以返回相同的向量,而在另一个实现中,它可以返回新的向量。但无论如何,它们都会被分类。

如果有一个变量,它指向一个序列,并且作者希望它在排序后指向一个已排序的序列:将变量设置为排序操作的结果。否则可能存在这样的情况,即在潜在破坏性排序之后,变量不会指向SORT结果,但仍然是未排序或以其他方式更改的序列。在矢量的情况下,这可以是旧的和未分类的矢量。

<强>记住 您唯一可以确定的是:SORT函数返回一个排序序列作为其值。