You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Common Lisp二叉搜索树实现中的类型错误排查与打印优化

问题修复与功能增强:Common Lisp BST实现

一、修复TYPE-ERROR: NIL is not of type NODE问题

问题根源

bst-minimum和bst-maximum函数未处理**空树(传入nil)**的场景,直接尝试访问节点的左/右子节点。当树为空时,tree是nil而非NODE类型,触发类型错误;递归过程中若子树为空,也会出现同样问题。

修复后的代码

修改最值查找函数,先判断当前树是否为空,再执行递归逻辑:

;; 查找BST中的最小节点
(defun bst-minimum (tree)
  (if (null tree)
      nil  ; 空树返回nil
      (if (null (lc tree))
          tree
          (bst-minimum (lc tree)))))

;; 查找BST中的最大节点
(defun bst-maximum (tree)
  (if (null tree)
      nil  ; 空树返回nil
      (if (null (rc tree))
          tree
          (bst-maximum (rc tree)))))

安全调用方式

调用时先判断返回值是否为nil,避免后续访问(key ...)触发错误:

(format t "~%~%Finding minimum in the BST:")
(let ((min-node (bst-minimum my-bst)))
  (if min-node
      (format t "Minimum key: ~A" (key min-node))
      (format t "Tree is empty, no minimum")))

(format t "~%~%Finding maximum in the BST:")
(let ((max-node (bst-maximum my-bst)))
  (if max-node
      (format t "Maximum key: ~A" (key max-node))
      (format t "Tree is empty, no maximum")))

二、增强功能:操作后自动打印树结构

方案1:封装操作包装函数

编写通用函数,执行插入/删除操作后自动打印树结构,避免重复代码:

;; 执行BST操作并打印结果
(defun bst-operate-and-print (tree operation-fn &rest args)
  (let ((new-tree (apply operation-fn args)))
    (format t "~%Tree after operation:")
    (print-bst new-tree "")
    new-tree))

使用示例

修改原调用逻辑,用包装函数简化操作:

(defvar my-bst nil) ; 初始化空BST

;; 插入元素
(format t "Inserting 10, 5, 15, 8 into the BST:")
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 10 my-bst #'<))
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 5 my-bst #'<))
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 15 my-bst #'<))
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 8 my-bst #'<))

;; 删除元素
(format t "~%~%Removing 5 from the BST:")
(setq my-bst (bst-operate-and-print my-bst #'bst-remove my-bst 5 #'<))

方案2:优化打印函数(可选)

调整打印格式,标记空节点让树结构更直观:

;; 直观打印BST结构,标记空节点
(defun print-bst (tree indent)
  (if tree
      (progn
        (print-bst (rc tree) (concatenate 'string indent "    "))
        (format t "~%~A└── ~A" indent (key tree))
        (print-bst (lc tree) (concatenate 'string indent "    ")))
      (format t "~%~A└── [EMPTY]" indent)))

完整修复后的核心代码

;; 定义BST节点结构
(defstruct (node (:conc-name nil))
  key     ; 节点存储的键值
  (lc nil) ; 左子节点
  (rc nil) ; 右子节点
  (parent nil)) ; 父节点

;; 插入键值到BST
(defun bst-insert (key tree compare-fn)
  (cond ((null tree) 
         (make-node :key key :lc nil :rc nil)) ; 空树则创建新节点
        ((funcall compare-fn key (key tree)) 
         (setf (lc tree) (bst-insert key (lc tree) compare-fn))) ; 插入左子树
        (t 
         (setf (rc tree) (bst-insert key (rc tree) compare-fn)))) ; 插入右子树
  tree)

;; 在BST中查找键值
(defun bst-find (key tree compare-fn)
  (cond ((null tree) nil) ; 未找到
        ((funcall compare-fn key (key tree)) (bst-find key (lc tree) compare-fn)) ; 左子树查找
        ((funcall compare-fn (key tree) key) (bst-find key (rc tree) compare-fn)) ; 右子树查找
        (t tree))) ; 找到节点

;; 查找BST中的最小节点
(defun bst-minimum (tree)
  (if (null tree)
      nil
      (if (null (lc tree))
          tree
          (bst-minimum (lc tree)))))

;; 查找BST中的最大节点
(defun bst-maximum (tree)
  (if (null tree)
      nil
      (if (null (rc tree))
          tree
          (bst-maximum (rc tree)))))

;; BST移植辅助函数
(defun bst-transplant (tree u v)
  (if (null (parent u))
      (progn
        (when v (setf (parent v) nil))
        v)
    (progn
      (if (eq u (lc (parent u)))
          (setf (lc (parent u)) v)
        (setf (rc (parent u)) v))
      (when v (setf (parent v) (parent u)))
      tree)))

;; 从BST中删除键值
(defun bst-remove (tree key compare-fn)
  (let ((z (bst-find key tree compare-fn)))
    (cond
     ((null z) tree)  ; 未找到键值,返回原树
     ((null (lc z))   ; Z无左子节点
      (bst-transplant tree z (rc z)))
     ((null (rc z))   ; Z无右子节点
      (bst-transplant tree z (lc z)))
     (t               ; Z有两个子节点
      (let* ((y (bst-minimum (rc z)))  ; 找右子树最小节点
             (tree (if (not (eq y (rc z)))
                       (bst-transplant tree y (rc y))
                     tree)))
        (setf (rc y) (rc z))
        (setf (parent (rc z)) y)
        (bst-transplant tree z y)
        (setf (lc y) (lc z))
        (setf (parent (lc z)) y)
        tree)))))

完整使用示例

;; 直观打印BST结构
(defun print-bst (tree indent)
  (if tree
      (progn
        (print-bst (rc tree) (concatenate 'string indent "    "))
        (format t "~%~A└── ~A" indent (key tree))
        (print-bst (lc tree) (concatenate 'string indent "    ")))
      (format t "~%~A└── [EMPTY]" indent)))

;; 执行操作并打印树结构的包装函数
(defun bst-operate-and-print (tree operation-fn &rest args)
  (let ((new-tree (apply operation-fn args)))
    (print-bst new-tree "")
    new-tree))

;; 示例使用
(defvar my-bst nil)

(format t "=== Inserting elements ===")
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 10 my-bst #'<))
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 5 my-bst #'<))
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 15 my-bst #'<))
(setq my-bst (bst-operate-and-print my-bst #'bst-insert 8 my-bst #'<))

(format t "~%=== Finding element 8 ===")
(let ((found-node (bst-find 8 my-bst #'<)))
  (if found-node
      (format t "~%Found node with key: ~A" (key found-node))
      (format t "~%Key not found")))

(format t "~%=== Removing element 5 ===")
(setq my-bst (bst-operate-and-print my-bst #'bst-remove my-bst 5 #'<))

(format t "~%=== Finding minimum ===")
(let ((min-node (bst-minimum my-bst)))
  (if min-node
      (format t "~%Minimum key: ~A" (key min-node))
      (format t "~%Tree is empty")))

(format t "~%=== Finding maximum ===")
(let ((max-node (bst-maximum my-bst)))
  (if max-node
      (format t "~%Maximum key: ~A" (key max-node))
      (format t "~%Tree is empty")))

内容的提问来源于stack exchange,提问作者boss man

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:39:52