首先,我使用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是否在内部将所有元素复制到结果数组中,但是给了我想要的数组,尽管它不可调整且没有填充指针。 有些想法?
答案 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可以获得多种实现方式。