12.5 示例:二叉搜索树 (Example: Binary Search Trees)

在某些情况下,使用破坏性操作比使用非破坏性的显得更自然。第 4.7 节中展示了如何维护一个具有二分搜索格式的有序对象集 (或者说维护一个二叉搜索树 (BST))。第 4.7 节中给出的函数都是非破坏性的,但在我们真正使用BST的时候,这是一个不必要的保护措施。本节将展示如何定义更符合实际应用的具有破坏性的插入函数和删除函数。

图 12.8 展示了如何定义一个具有破坏性的 bst-insert (第 72 页「译者注:第 4.7 节」)。相同的输入参数,能够得到相同返回值。唯一的区别是,它将修改作为第二个参数输入的 BST。 在第 2.12 节中说过,具有破坏性并不意味着一个函数调用具有副作用。的确如此,如果你想使用 bst-insert! 构造一个 BST,你必须像调用 bst-insert 那样调用它:

  1. > (setf *bst* nil)
  2. NIL
  3. > (dolist (x '(7 2 9 8 4 1 5 12))
  4. (setf *bst* (bst-insert! x *bst* #'<)))
  5. NIL
  1. (defun bst-insert! (obj bst <)
  2. (if (null bst)
  3. (make-node :elt obj)
  4. (progn (bsti obj bst <)
  5. bst)))
  6. (defun bsti (obj bst <)
  7. (let ((elt (node-elt bst)))
  8. (if (eql obj elt)
  9. bst
  10. (if (funcall < obj elt)
  11. (let ((l (node-l bst)))
  12. (if l
  13. (bsti obj l <)
  14. (setf (node-l bst)
  15. (make-node :elt obj))))
  16. (let ((r (node-r bst)))
  17. (if r
  18. (bsti obj r <)
  19. (setf (node-r bst)
  20. (make-node :elt obj))))))))

图 12.8: 二叉搜索树:破坏性插入

你也可以为 BST 定义一个类似 push 的功能,但这超出了本书的范围。(好奇的话,可以参考第 409 页 「译者注:即备注 204 」 的宏定义。)

bst-remove (第 74 页「译者注:第 4.7 节」) 对应,图 12.9 展示了一个破坏性版本的 bst-delete 。同 delete 一样,我们调用它并不是因为它的副作用。你应该像调用 bst-remove 那样调用 bst-delete

  1. > (setf *bst* (bst-delete 2 *bst* #'<) )
  2. #<7>
  3. > (bst-find 2 *bst* #'<)
  4. NIL
  1. (defun bst-delete (obj bst <)
  2. (if bst (bstd obj bst nil nil <))
  3. bst)
  4. (defun bstd (obj bst prev dir <)
  5. (let ((elt (node-elt bst)))
  6. (if (eql elt obj)
  7. (let ((rest (percolate! bst)))
  8. (case dir
  9. (:l (setf (node-l prev) rest))
  10. (:r (setf (node-r prev) rest))))
  11. (if (funcall < obj elt)
  12. (if (node-l bst)
  13. (bstd obj (node-l bst) bst :l <))
  14. (if (node-r bst)
  15. (bstd obj (node-r bst) bst :r <))))))
  16. (defun percolate! (bst)
  17. (cond ((null (node-l bst))
  18. (if (null (node-r bst))
  19. nil
  20. (rperc! bst)))
  21. ((null (node-r bst)) (lperc! bst))
  22. (t (if (zerop (random 2))
  23. (lperc! bst)
  24. (rperc! bst)))))
  25. (defun lperc! (bst)
  26. (setf (node-elt bst) (node-elt (node-l bst)))
  27. (percolate! (node-l bst)))
  28. (defun rperc! (bst)
  29. (setf (node-elt bst) (node-elt (node-r bst)))
  30. (percolate! (node-r bst)))

图 12.9: 二叉搜索树:破坏性删除

译注: 此范例已被回报为错误的,一个修复的版本请造访这里