我在使用常见的lisp计算两个位向量之间的距离时遇到了问题。
我是lisp的新手,这是我的人工智能家庭作业的最终作业问题,并且相信我遇到的问题是语法问题。
以下是问题:
在两个位向量之间写入递归函数DISTANCE 由1和0的列表表示的相同长度。对于 例如,
(距离'(1 0 1 1)'(0 1 0 1))
答案:3
如果向量是a,那么讨论必须做什么 不同的长度。
根据我的理解,两个位向量之间的距离只是对两个向量进行异或,然后向上计数1。
使用这个例子,我们将得到1011 ^ 0101 = 1110,它等于3。
假设这是计算距离的正确方法,那么我的问题是找到一种在lisp中进行XOR的方法,除了使其递归之外。
如何获取两个列表并将其放入我可以使用logxor
(shown here)之类的格式,然后在结果列表中计算1?
在尝试(logxor '(1 0 1 1) '(0 1 0 1))
时,它告诉我'(1 0 1 1)不是一个整数,因此看起来logxor
不适用于让我不知所措的列表。< / p>
您可以提供任何帮助,我们将不胜感激
谢谢!
答案 0 :(得分:7)
您的问题提到“位向量”,但您实际上正在使用位列表。 Common Lisp实际上提供了bit-vector
类型。这是一种特殊类型的数组。但它仍然是一个向量,所以你可以使用适用于任意序列(向量或列表)的序列函数,因此你可以编写一个适用于位向量的解决方案以及其元素为位的任何其他序列。 map
:
(defun distance (bits1 bits2)
(reduce '+ (map 'bit-vector 'logxor bits1 bits2)))
它按预期工作,但请注意,您可以使用位向量(可以使用#*…
表示法轻松编写)以及列表。 mapcar
只能在列表上使用(reduce '+ …)
,因此无法获得这种灵活性。另请注意使用(apply '+ …)
而不是reduce
。这有两个原因
apply
适用于任意序列,因此您可以将它与矢量和列表一起使用。CL-USER> (distance #*1011 #*0101)
3
CL-USER> (distance '(1 0 1 1) '(0 1 0 1))
3
CL-USER> (distance #*1011 '(0 1 0 1))
3
受call-arguments-limit
的约束,Rainer Joswig's answer是可以传递给函数的最大参数数。虽然这里的小案例不会与此相反,但如果你有更大的位向量,你可能会遇到这个问题。(logcount (logxor … …))
{{3}}指出你也可以用整数进行位操作。因为这是一个非常合理的事情(特别是因为你可以使用二进制整数表示法),所以值得制作一个适用于它的版本。这是一个实现,它将所有参数转换为整数(无论它们是否已经是整数或位序列)并使用(defun distance (bits1 bits2)
(flet ((to-int (bits)
(if (integerp bits) bits
(reduce (lambda (int bit)
(logior (ash int 1) bit))
bits))))
(logcount (logxor (to-int bits1) (to-int bits2)))))
:
CL-USER> (distance #b1011 '(0 1 0 1))
3
CL-USER> (distance #*1011 '(0 1 0 1))
3
CL-USER> (distance #*1011 5)
3
CL-USER> (distance 11 5)
3
{{1}}
答案 1 :(得分:4)
LOGXOR适用于数字:
CL-USER 43 > (logxor 2 1)
3
还有一种将数字写为0和1的符号。
CL-USER 44 > (logxor #b1010 #b0101)
15
另见:
CL-USER 45 > (logcount (logxor #b1011 #b0101))
3
答案 2 :(得分:1)
只需将logxor
映射到您的列表:
? (mapcar #'logxor '(1 0 1 1) '(0 1 0 1))
(1 1 1 0)
并计算一下:
? (count 1 (mapcar #'logxor '(1 0 1 1) '(0 1 0 1)))
3
或者只是将所有内容添加到一起:
? (apply #'+ (mapcar #'logxor '(1 0 1 1) '(0 1 0 1)))
3
现在您只需要将其转换为递归
(defun distance (lst1 lst2)
(if (or (null lst1) (null lst2))
0
(+ (logxor (car lst1) (car lst2))
(distance (cdr lst1) (cdr lst2)))))
或尾递归版:
(defun distance (lst1 lst2 &optional (res 0))
(if (or (null lst1) (null lst2))
res
(distance (cdr lst1)
(cdr lst2)
(+ res (logxor (car lst1) (car lst2)))))))
然后
? (distance '(1 0 1 1) '(0 1 0 1))
3
答案 3 :(得分:1)
简单的递归版本不是尾递归的:
(defun distance (v u)
(cond ((null v) (length u)) ; assume that missing is different from both 0 & 1
((null u) (length v)) ; ditto
(t (+ (if (= (first u) (first v)) 0 1)
(distance (rest v) (rest u))))))
这对应于距离的公理定义(差异的数量)
dist(v1,u1)+dist(v2,u2)=dist(v1+v2,u1+u2)
如果length(v1)=length(u1)
; +
表示连接length(v1)=length(v2)=1
,则dist(v1,v2):=(v1==v2? 0 : 1)
如果你需要一个尾递归版本(可以通过编译器更容易地转换为迭代),你需要使用该函数来携带部分结果。
答案 4 :(得分:0)
如果你想使用一个简单的defun语句,你总是可以做类似的事情。
(defun distance (a b)
(cond
((equal nil a) 0)
(t (+ (rem (+ (first a) (first b)) 2) (distance (rest a) (rest b))))
)
)