-
Notifications
You must be signed in to change notification settings - Fork 1
/
bst.lisp
145 lines (127 loc) · 4.03 KB
/
bst.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
;;; Graham's BST code, with my fixes and cleanup.
;;;
;;; General changes:
;;; - COND instead of nested IF's
;;; - Replaced EQL with second call to <. x = y if
;;; neither x < y nor y < x.
(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)))
(cond ((funcall < obj elt)
(make-node
:elt elt
:l (bst-insert obj (node-l bst) <)
:r (node-r bst)))
((funcall < elt obj)
(make-node
:elt elt
:r (bst-insert obj (node-r bst) <)
:l (node-l bst)))
(t bst)))))
(defun bst-find (obj bst <)
(if (null bst)
nil
(let ((elt (node-elt bst)))
(cond ((funcall < obj elt)
(bst-find obj (node-l bst) <))
((funcall < elt obj)
(bst-find obj (node-r bst) <))
(t 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)))
;;; Changes from Graham's BST-REMOVE:
;;; - Replace BST-REMOVE-MAX/BST-REMOVE-MIN with
;;; existing BST functions
;;; - Rename PERCOLATE to BST-JOIN
(defun bst-remove (obj bst <)
(if (null bst)
nil
(let ((elt (node-elt bst))
(l (node-l bst))
(r (node-r bst)))
(cond ((funcall < obj elt)
(make-node
:elt elt :l (bst-remove obj l <) :r r))
((funcall < elt obj)
(make-node
:elt elt :l l :r (bst-remove obj r <)))
(t
(bst-join l r <))))))
;;; BST-JOIN joins 2 binary search trees.
;;; Precondition: (bst-max l) <= (bst-min r)
(defun bst-join (l r <)
(cond ((null l) r)
((null r) l)
((zerop (random 2)) ;; random choice for new root
(let ((root (node-elt (bst-max l))))
(make-node :elt root
:l (bst-remove root l <)
:r r)))
(t
(let ((root (node-elt (bst-min r))))
(make-node :elt root
:l l
:r (bst-remove root r <))))))
(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
;;; Changes from Graham's code:
;;; - Just one function
(defun bst-insert! (obj bst <)
(cond ((null bst)
(make-node :elt obj))
(t
(let ((elt (node-elt bst))
(l (node-l bst))
(r (node-r bst)))
(cond ((funcall < obj elt)
(setf (node-l bst)
(bst-insert! obj l <)))
((funcall < elt obj)
(setf (node-r bst)
(bst-insert! obj r <))))
bst))))
;;; Changes from Graham's code:
;;; - Replaced percolate! with bst-join!
(defun bst-delete (obj bst <)
(if (null bst)
nil
(let ((elt (node-elt bst))
(l (node-l bst))
(r (node-r bst)))
(cond ((eql obj elt)
(bst-join! bst l r <))
((funcall < obj elt)
(setf (node-l bst) (bst-delete obj l <))
bst)
(t
(setf (node-r bst) (bst-delete obj r <))
bst)))))
;;; Destructively joins 2 left and right subtrees of node.
;;; Precondition: (bst-max l) <= (bst-min r)
(defun bst-join! (node l r <)
(cond ((null l) r)
((null r) l)
((zerop (random 2)) ;; random choice for new root
(let ((root (node-elt (bst-max l))))
(setf (node-elt node) root
(node-l node) (bst-delete root l <))
node))
(t
(let ((root (node-elt (bst-min r))))
(setf (node-elt node) root
(node-r node) (bst-delete root r <))
node))))