问题描述
考虑到二维Nxn位数组,我正在尝试评估确定位数组是否已经存在于以前见过的大量位数组中的最佳方法。
一种直接的方法是将位数组放在哈希表中。但是比较数组需要一个#'equalp:test函数,这可能不是很有效。 (但是SBCL可能会自动针对不同的密钥类型进行优化吗?)
另一个计划是将所有位数组转换为整数,并将整数放入哈希表中。然后测试可以是#'eql:
(defun bit-arr-to-int (bit-array)
(reduce (lambda (bit1 bit2)
(+ (* bit1 2) bit2))
(make-array (array-total-size bit-array)
:displaced-to bit-array)))
但是,不确定这是否比让SBCL处理事情更有效,因为它仍然单独处理每个元素。也许定制的哈希表可以提供效率优势?
第三个选项可能涉及将基本表示形式从位数组更改为简单位矢量(又名整数),因为原始位数组的尺寸是已知的。为了允许等效于数组的元素引用,这将需要一个函数,该函数将隐式数组的行坐标转换为显式的简单位向量索引。如上所述,与按每次哈希表查找将整个位数组转换为整数相比,根据需要计算索引可能更有效。
欣赏一些经验丰富的见解。
解决方法
我认为了解这一点的唯一方法是尝试事物,看看最快的方法。
您可以尝试的一个可怕技巧是将位向量表示为(row-length . integer-of-bits)
的缺点。您需要行长,以便可以以位整数形式计算偏移量。然后您可以执行以下操作(这些可能是错误的,因为我总是被dpb
和ldb
所迷惑):
(deftype index ()
`(integer 0,most-positive-fixnum))
(defun make-bv (columns)
(declare (type index columns))
(cons columns 0))
(defun bv-ref (bv row column)
(declare (type (cons index integer) bv)
(type index row column))
(let ((columns (car bv)))
(assert (< column columns) (column) "column out of range")
(ldb (byte 1 (+ (* row columns) column)) (cdr bv))))
(defun (setf bv-ref) (bit bv row column)
(declare (type bit bit)
(type (cons index integer) bv)
(type index row column))
(let ((columns (car bv)))
(assert (< column columns) (column) "column out of range")
(setf (cdr bv) (dpb bit (byte 1 (+ (* row columns) column)) (cdr bv)))
bit))
在现实生活中,您当然想内嵌这些内容。
像这样的表示形式可能对散列很有用(您可以仅对equal
进行散列,甚至在缺点中为两个元素嵌套eql
散列表),但存在一个明显的问题,即它不能不必关心对象有多少行:它们本质上都具有无限制的行数。
如果'arrays'非常大并且您对其进行了很多更改,那会很糟糕,因为每次更改时都会浪费一个新的bignum。
但是我认为了解 的唯一方法是测量。