;;; Graham's Binary Search Tree code ;;; including bst-insert! and bst-delete from ;;; Chapter 12. ;;; ;;; bst-remove and bst-delete are broken. See ;;; ;;; http://www.paulgraham.com/howbroken.html ;;; ;;; bst.lisp contains Graham's fixes. (in-package :cs325-user) (defstruct (node (:print-function (lambda (n s d) (format s "#<~A>" (node-elt n))))) elt (l nil) (r nil)) (defun bst-insert (obj bst <) (if (null bst) (make-node :elt obj) (let ((elt (node-elt bst))) (if (eql obj elt) bst (if (funcall < obj elt) (make-node :elt elt :l (bst-insert obj (node-l bst) <) :r (node-r bst)) (make-node :elt elt :r (bst-insert obj (node-r bst) <) :l (node-l bst))))))) (defun bst-find (obj bst <) (if (null bst) nil (let ((elt (node-elt bst))) (if (eql obj elt) bst (if (funcall < obj elt) (bst-find obj (node-l bst) <) (bst-find obj (node-r bst) <)))))) (defun bst-min (bst) (and bst (or (bst-min (node-l bst)) bst))) (defun bst-max (bst) (and bst (or (bst-max (node-r bst)) bst))) ;;; BROKEN (defun bst-remove (obj bst <) (if (null bst) nil (let ((elt (node-elt bst))) (if (eql obj elt) (percolate bst) (if (funcall < obj elt) (make-node :elt elt :l (bst-remove obj (node-l bst) <) :r (node-r bst)) (make-node :elt elt :r (bst-remove obj (node-r bst) <) :l (node-l bst))))))) (defun percolate (bst) (cond ((null (node-l bst)) (if (null (node-r bst)) nil (rperc bst))) ((null (node-r bst)) (lperc bst)) (t (if (zerop (random 2)) (lperc bst) (rperc bst))))) (defun rperc (bst) (make-node :elt (node-elt (node-r bst)) :l (node-l bst) :r (percolate (node-r bst)))) (defun lperc (bst) (make-node :elt (node-elt (node-l bst)) :l (percolate (node-l bst)) :r (node-r bst))) (defun bst-traverse (fn bst) (when bst (bst-traverse fn (node-l bst)) (funcall fn (node-elt bst)) (bst-traverse fn (node-r bst)))) ;;; Destructive BST functions from Chapter 12 ;;; bst-delete is BROKEN. In fact, I think it's ;;; even more broken than bst-remove. (defun bst-insert! (obj bst <) (if (null bst) (make-node :elt obj) (progn (bsti obj bst <) bst))) (defun bsti (obj bst <) (let ((elt (node-elt bst))) (if (eql obj elt) bst (if (funcall < obj elt) (let ((l (node-l bst))) (if l (bsti obj l <) (setf (node-l bst) (make-node :elt obj)))) (let ((r (node-r bst))) (if r (bsti obj r <) (setf (node-r bst) (make-node :elt obj)))))))) (defun bst-delete (obj bst <) (if bst (bstd obj bst nil nil <)) bst) (defun bstd (obj bst prev dir <) (let ((elt (node-elt bst))) (if (eql elt obj) (let ((rest (percolate! bst))) (case dir (:l (setf (node-l prev) rest)) (:r (setf (node-r prev) rest)))) (if (funcall < obj elt) (if (node-l bst) (bstd obj (node-l bst) bst :l <)) (if (node-r bst) (bstd obj (node-r bst) bst :r <)))))) (defun percolate! (bst) (cond ((null (node-l bst)) (if (null (node-r bst)) nil (rperc! bst))) ((null (node-r bst)) (lperc! bst)) (t (if (zerop (random 2)) (lperc! bst) (rperc! bst))))) (defun lperc! (bst) (setf (node-elt bst) (node-elt (node-l bst))) (percolate! (node-l bst))) (defun rperc! (bst) (setf (node-elt bst) (node-elt (node-r bst))) (percolate! (node-r bst)))