在Lisp中插入可调整数组中的元素

时间:2013-06-09 10:03:47

标签: lisp common-lisp adjustable-array

首先,我使用LispWorks。 我有一个可调节的阵列,我想在一个位置插入一个元素i<填充指针,所以我需要将所有元素从i移动到它的位置+ 1.我的问题是我不知道如何做到这一点并得到一个可调整的数组,但没有将所有元素复制到另一个数组。表现非常重要。 使用此数组#(0 1 2 3 4 6 7),我在第i = 5位置插入数字5:

(let ((arr (make-array 7 :initial-contents (list 0 1 2 3 4 6 7) 
                     :adjustable T :fill-pointer 7))
      (i 5)) 
    (concatenate 'vector (subseq arr 0 i)
                         (make-array 1 :initial-contents '(5))
                         (subseq arr i (fill-pointer arr))))

我不知道LispWorks是否在内部将所有元素复制到结果数组中,但是给了我想要的数组,尽管它不可​​调整且没有填充指针。 有些想法?

2 个答案:

答案 0 :(得分:3)

首先,你的代码太过分了。

这是一个尽可能少的版本:

(defun insert-into-array (vector value position)
  (vector-push-extend value vector) ; ensure that the array is large enough
  ;; shift the end of the array right
  (loop for i from (1- (length vector)) downto (1+ position) do
      (setf (aref vector i) (aref vector (1- i))))
  (setf (aref vector position) value) ; insert value into the right place
  vector)
(insert-into-array (make-array 9 :initial-contents '(0 1 2 3 4 6 7 8 9) 
                                 :adjustable T :fill-pointer 9) 5 5)
==> #(0 1 2 3 4 5 6 7 8 9)

请注意,这会在更糟糕的情况下进行N分配,因此,如果插入是您设置中的常见操作而您不需要随机访问,则可能需要考虑链接列表而不是数组。 / p>

编辑:我忘记了replace,这使得循环变得不必要了:

(defun insert-into-array (vector value position)
  (replace vector vector :start2 position :start1 (1+ position) 
           :end2 (vector-push-extend value vector))
  (setf (aref vector position) value) 
  vector)

答案 1 :(得分:3)

要增加编译器的优化机会,请尽可能使用专门的简单数组;即,避免填充指针和可调节阵列。此外,更高级别的操作(例如replace)应允许以块(而不是一次一个字)移动内存。

(defun insert-at (vec i val)
  (check-type vec (simple-array fixnum 1))
  (let ((new (make-array (1+ (length vec)) :element-type 'fixnum)))
    (declare (optimize speed))
    (setf (aref new i) val)
    (replace new vec :end1 i)
    (replace new vec :start1 (1+ i) :start2 i)))

重复100次以获得更有意义的基准测试结果(使用sbcl):

(let ((arr (make-array 1000000 :element-type 'fixnum)))
  (time (loop repeat 100 for i from 500000 do
          (insert-at arr i i))))

Evaluation took:
  0.988 seconds of real time
  0.992062 seconds of total run time (0.804051 user, 0.188011 system)
  [ Run times consist of 0.148 seconds GC time, and 0.845 seconds non-GC time. ]
  100.40% CPU
  2,962,811,250 processor cycles
  800,003,200 bytes consed

可能你应该看看heap,它允许在保持(某种)顺序的同时插入O(log n)。通过quicklisp可以获得多种实现方式。