Skip to content

LISP - 创建向量

**向量(vector)**是 Common Lisp 中的一维数组。与列表(lists)不同,列表优化了在头部添加/删除元素的操作,而向量通过索引提供了快速、常数时间(O(1))的任意元素访问。这使得它们非常适合随机访问数据存储。

Common Lisp 提供了三种主要的创建向量的方式,每种都适用于不同的情况。

当你在创建时就已知向量的元素时,可以使用 vector 函数。

;; 创建一个数字向量
(vector 10 20 30) ; => #(10 20 30)
;; 创建一个混合类型的向量
(vector "apple" 3.14 t) ; => #("apple" 3.14 T)

#(...) 语法是一种简洁的字面量方式来定义向量。它在代码编译之前由 Lisp 读取器(reader)进行求值,这使得它对于常量数据非常高效。

;; 读取器宏常用于常量向量
(defparameter *my-constants* #(1 2 3))
(defparameter *fruit* #("apple" "banana" "orange"))

3. 使用 make-array 实现最大灵活性

Section titled “3. 使用 make-array 实现最大灵活性”

make-array 是创建向量(以及多维数组)最强大的工具。它允许你指定大小、所有元素的初始值、元素类型,以及向量是否应该是可调整的。

;; 创建一个大小为 5,所有元素初始化为 0 的向量
(make-array 5 :initial-element 0) ; => #(0 0 0 0 0)
;; 从一个包含初始内容的列表创建向量
(make-array 3 :initial-contents '(1 2 3)) ; => #(1 2 3)
;; 创建一个只能存储字符串的专业化向量
(make-array 4 :element-type 'string :initial-element "empty")
; => #("empty" "empty" "empty" "empty")

对于需要动态、可增长数组(如 C++ 中的 std::vector 或 Java 中的 ArrayList)的情况,你可以创建一个带填充指针的可调整向量。

:fill-pointer 跟踪活动元素的数量,而 :adjustable t 允许向量在空间不足时进行调整大小。你可以使用 vector-push-extend 添加元素。

;; 创建一个初始容量为 5 的动态向量
(defparameter *dynamic-vector*
(make-array 5 :adjustable t :fill-pointer 0))
(print *dynamic-vector*)
(format t "Initial length (fill-pointer): ~a~%" (fill-pointer *dynamic-vector*))
;; 向向量中添加元素
(vector-push-extend 'a *dynamic-vector*)
(vector-push-extend 'b *dynamic-vector*)
(print *dynamic-vector*)
(format t "New length (fill-pointer): ~a~%" (fill-pointer *dynamic-vector*))
;; 使用 AREF 访问元素
(format t "First element: ~a~%" (aref *dynamic-vector* 0))

执行这段代码会演示整个过程:

#()
Initial length (fill-pointer): 0
#(A B)
New length (fill-pointer): 2
First element: A
  • 使用列表(Lists)的场景: 栈(Stacks)、顺序处理,以及当你频繁地在集合开头添加或删除元素时。它们的优势在于 cons、first 和 rest 等操作。
  • 使用向量(Vectors)的场景: 通过索引进行随机访问、固定大小的集合,或者你通常在末尾添加元素的动态数组。它们的优势在于 aref 操作。