LISP 学习——特殊数据类型的操作练习

本贴最后更新于 1603 天前,其中的信息可能已经时异事殊

用二分法搜索一个有序向量

要点

  • length 获取列表长度
  • aref 取向量中的元素,也可以用 svref svref 专门用来对向量进行操作,速度比 aref
  • 递归求解

代码

;;; 二分搜索
(defun b-search (obj vec)
  (let ((len (length vec)))
    (and (not (zerop len))
         (finder obj vec 0 (- len 1)))))

(defun finder (target vec start end)
  (if (eql end start) ; 如果起点等于终点相等
    (if (eql target (aref vec start))
      target
      nil)
    (let ((mid (+ start (round (/ (- end start) 2)))))
      (let ((e (aref vec mid))) ; 取到中间的元素
        (if (< target e)
          (finder target vec start (- mid 1))
 ; 若目标元素在左边对左半部分继续二分搜索
          (if (> target e)
            (finder target vec (+ mid 1) end)

 ; 若目标元素在右边对右半部分继续二分搜索
            target))))))

(format t "~A~%" (b-search 3 #(0 1 2 3 4 5 6 7 8 9)))
; Expected: 3

不使用原生 reverse 方法将列表倒序

要点

  • car 获取列表的首个元素
  • cdr 获取列表除首个元素之外的所有元素构成的列表
  • list 构造列表
  • append 合并多个列表
  • 递归倒序

代码

;;; 将列表倒序
(defun my-rev-lst (l)
  (if (null l)
    (list)
    (append (my-rev-lst (cdr l)) (list (car l)))))

(format t "~A~%" (my-rev-lst '(a b c d)))
; Expected: (D C B A)

不使用原生 copy-list 复制列表

要点

  • reduce 对列表进行积累操作
  • list 构造列表
  • append 合并列表

代码

;;; 复制列表
(defun my-cp-lst (l)
  (reduce
    #'(lambda (new-l e)
      (if (listp new-l)
        (append new-l (list e))
        (list new-l e))
      )
    l))

(format t "~A~%" (my-cp-lst '(a b c d)))

将一个相同维度的数组顺时针转 90 度

要点

  • make-array 构造数组
  • do 双层循环遍历
  • setf 搭配 aref 更改数组元素

代码

; 将一个等纬度的二维数组顺时针旋转90度
(defun rotate-square-array (arr)
  (let
    ((n (car (array-dimensions arr)))
    (new-arr nil))
    (setf new-arr (make-array (list n n) :initial-element nil))
    (do ((i 0 (+ i 1)))
      ((eql i n))
      (do ((j 0 (+ j 1)))
        ((eql j n))
          (setf (aref new-arr i j) (aref arr (- (- n 1) j) i))))
    new-arr))

(let
  ((arr (make-array '(3 3) :initial-element nil)))
  (do ((i 0 (+ i 1)))
    ((eql i 3))
    (do ((j 0 (+ j 1)))
      ((eql j 3))
      (setf (aref arr i j) (+ (* i 3) (+ j 1)))))
  (format t "Before rotate: ~A~%" arr)
  (format t "After rotate: ~A~%" (rotate-square-array arr)))
; Expected: 
; Before rotate: #2A((1 2 3) (4 5 6) (7 8 9))
; After rotate: #2A((7 4 1) (8 5 2) (9 6 3))

哈希表与关联列表的相互转换

要点

  • make-hash-table 构造哈希表
  • maphash 遍历哈希表
  • setf 搭配 gethash 添加或设置哈希表中的值
  • 关联列表是由 cons 对象组成的列表
  • cons 构造 cons 对象
;;; 哈希表转关联列表
(defun hash-table-to-lst (ht)
  (let ((l (list)))
    (maphash
      #'(lambda (k v)
        (setf l (append l (list (cons k v))))
      )
      ht
    )
    l))

(let ((ht (make-hash-table)))
  (setf (gethash 'color ht) 'red)
  (setf (gethash 'size ht) 'big)
  (format t "~A~%" (hash-table-to-lst ht)))
; Expected: ((COLOR . RED) (SIZE . BIG))

;;; 关联列表转哈希表
(defun lst-to-hash-table (l)
  (if (null l)
    (make-hash-table)
    (let (
      (e (car l))
      (ht (lst-to-hash-table (cdr l))))
      (setf (gethash (car e) ht) (cdr e))
      ht)))

(maphash
  #'(lambda (k v)
    (format t "~A = ~A~%" k v))
  (lst-to-hash-table '((+ . "add") (- . "subtract"))))
; Expected: 
; - = subtract
; + = add

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...