CLISP数组单位置修改及TSP随机化算法赋值异常问询
在CLISP里,修改数组单个元素的核心操作是用setf配合aref(数组引用函数)来完成。aref负责定位到数组指定索引的元素,setf则用来给这个位置赋予新值。
举个直观的例子:
;; 先创建一个初始数组(包含5个元素) (setf my-array (make-array 5 :initial-contents '(10 20 30 40 50))) ;; 修改索引为2的元素(CLISP数组索引从0开始,对应第三个元素) (setf (aref my-array 2) 999) ;; 此时数组内容变为:(10 20 999 40 50)
如果是多维数组,只需要在aref后面追加对应维度的索引即可,比如修改二维数组第2行第3列的元素:
(setf (aref multi-dim-array 1 2) "updated-value")
看了你这段代码:
(do ((i 0 (+ i 1))) ((= i n-population)) (setf (aref population i) (shuffle TSP 100)) )
出现“所有数组位置都被设为同一个值”的问题,核心原因是你的shuffle函数没有返回新的数组副本,而是直接在原始的TSP数组上做原地修改,并且每次返回的都是同一个数组的引用。
也就是说,每次调用(shuffle TSP 100)时,它只是把原始TSP数组打乱,然后返回这个数组本身的指针。你把这个指针重复赋值给population的每个位置,最终整个population数组里的所有元素都指向同一个TSP数组,自然看起来所有位置内容都一样。
解决办法很直接:每次打乱前先复制一份原始TSP数组,对副本进行打乱操作,这样每个population[i]都会得到独立的新数组:
(do ((i 0 (+ i 1))) ((= i n-population)) ;; 先复制原始TSP数组,再打乱副本 (setf (aref population i) (shuffle (copy-seq TSP) 100)) )
这里copy-seq会创建一个和原始序列(数组/列表)内容完全一致的新序列,确保每次打乱的都是独立的副本,population的每个位置就会得到不同的打乱结果了。
另外你可以验证一下shuffle的行为:如果调用(shuffle TSP 100)后,原始TSP数组的内容发生了变化,那说明它确实是原地修改的,这时必须用副本。如果shuffle是你自己实现的,也可以直接修改这个函数,让它内部先复制输入序列,打乱副本后再返回,这样调用方就不用额外处理了。
内容的提问来源于stack exchange,提问作者miguel__frtt

