LISP - 向量
Lisp - 向量(Vectors)
Section titled “Lisp - 向量(Vectors)”向量(Vectors)是一维数组,与列表(lists)一样,是 Common Lisp 中基本的序列类型。与列表(其针对顺序访问和前端修改进行了优化)不同,向量提供对其元素的快速、常数时间(O(1))随机访问。这使得它们非常适合需要按索引查找元素的集合。
创建向量有多种方法,每种方法都适用于不同的需求。
1. vector 函数
Section titled “1. vector 函数”使用 vector 函数是创建带有预定义元素的向量最简单的方法。它接受任意数量的参数(arguments),并返回一个包含这些参数的新向量。
(let ((v1 (vector 1 2 3 4 5)) (v2 (vector 'a "hello" t))) (format t "Numeric vector: ~a~%" v1) (format t "Mixed vector: ~a~%" v2))Numeric vector: #(1 2 3 4 5)Mixed vector: #(A "hello" T)2. #(...) 读取器宏(Reader Macro)
Section titled “2. #(...) 读取器宏(Reader Macro)”Lisp 提供了一种用于向量的字面量(literal)语法:#(...)。这对于直接在代码中嵌入常量向量数据非常方便。
警告: 根据标准,你绝不应修改字面量对象。这样做可能导致未定义行为(undefined behavior),因为 Lisp 系统可能将字面量存储在只读内存中。对于你打算修改的向量,请始终使用 vector 或 make-array。
(defvar *my-constant-vector* #(A B C))(write *my-constant-vector*)3. make-array 函数
Section titled “3. make-array 函数”make-array 是创建数组(包括向量)最通用和功能强大的函数。对于向量,你只需提供一个维度。
;; 创建一个大小为 5 的向量,每个元素都初始化为 0。(let ((zero-vec (make-array 5 :initial-element 0))) (format t "Zero-initialized vector: ~a~%" zero-vec))
;; 从现有内容列表创建向量(let ((from-list (make-array 3 :initial-contents '(10 20 30)))) (format t "Vector from list: ~a~%" from-list))Zero-initialized vector: #(0 0 0 0 0)Vector from list: #(10 20 30)带填充指针(Fill Pointers)的动态向量
Section titled “带填充指针(Fill Pointers)的动态向量”Lisp 向量的一个关键特性是填充指针(fill pointer)。带填充指针的向量类似于其他语言(例如,C++ std::vector 或 Python list)中的动态数组或列表。它维护一个独立于其总分配容量的长度,从而允许高效地在末尾添加元素。
你可以通过向 make-array 传递 :fill-pointer 参数来创建一个带填充指针的向量。
vector-push(向量压入):在向量末尾添加一个元素并增加填充指针。它返回添加元素的索引,如果向量已满则返回nil。vector-pop(向量弹出):移除并返回最后一个元素(在填充指针位置),并减少填充指针。
;; 创建一个容量为 5 但初始长度为 0 的向量(let ((dyn-vec (make-array 5 :fill-pointer 0))) (format t "Initial: ~a (Length: ~a)~%" dyn-vec (length dyn-vec))
;; 压入一些元素 (vector-push 'a dyn-vec) (vector-push 'b dyn-vec) (vector-push 'c dyn-vec) (format t "After 3 pushes: ~a (Length: ~a)~%" dyn-vec (length dyn-vec))
;; 弹出一个元素 (let ((popped-item (vector-pop dyn-vec))) (format t "Popped '~a'. Vector is now: ~a (Length: ~a)~%" popped-item dyn-vec (length dyn-vec)))
;; 填充剩余容量 (vector-push 'd dyn-vec) (vector-push 'e dyn-vec) (format t "Filled to capacity: ~a~%" dyn-vec)
;; 此次压入将失败,因为向量已满 (let ((result (vector-push 'f dyn-vec))) (format t "Attempting to push past capacity returned: ~a~%" result)))Initial: #() (Length: 0)After 3 pushes: #(A B C) (Length: 3)Popped 'C'. Vector is now: #(A B) (Length: 2)Filled to capacity: #(A B D E)Attempting to push past capacity returned: NIL专业提示: 对于真正动态、可调整大小的向量,请使用 make-array 并同时设置 :fill-pointer 和 :adjustable t。这允许你使用 vector-push-extend(一个常用工具,通常来自库),它在向量满时会自动调整向量的容量。