File: binary-tree.lisp

package info (click to toggle)
cl-aima 20020509-2
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 1,188 kB
  • ctags: 1,574
  • sloc: lisp: 6,593; makefile: 57; sh: 28
file content (356 lines) | stat: -rw-r--r-- 13,402 bytes parent folder | download | duplicates (3)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
;;; File: binary-tree.lisp -*- Mode: Lisp; Syntax: Common-Lisp -*-

;;;;  The following definitions implement binary search trees.

;;;  They are not balanced as yet.  Currently, they all order their
;;;  elements by #'<, and test for identity of elements by #'eq.


(defstruct search-tree-node
  "node for binary search tree"
  value        ;; list of objects with equal key
  num-elements ;; size of the value set
  key          ;; f-cost of the a-star-nodes
  parent       ;; parent of search-tree-node
  leftson      ;; direction of search-tree-nodes with lesser f-cost
  rightson     ;; direction of search-tree-nodes with greater f-cost
  )


 
(defun make-search-tree (root-elem root-key &aux root)
  "return dummy header for binary search tree, with initial
  element root-elem whose key is root-key."
  (setq root
	(make-search-tree-node
	  :value nil
	  :parent nil
	  :rightson nil
	  :leftson (make-search-tree-node
		     :value (list root-elem)
		     :num-elements 1
		     :key root-key
		     :leftson nil :rightson nil)))
  (setf (search-tree-node-parent
	  (search-tree-node-leftson root)) root)
  root)



(defun create-sorted-tree (list-of-elems key-fun &aux root-elem root)
  "return binary search tree containing list-of-elems ordered according
  tp key-fun"
  (if (null list-of-elems)
      nil
      (progn
	(setq root-elem (nth (random (length list-of-elems)) list-of-elems))
	(setq list-of-elems (remove root-elem list-of-elems :test #'eq))
	(setq root (make-search-tree root-elem
				     (funcall key-fun root-elem)))
	(dolist (elem list-of-elems)
	  (insert-element elem root (funcall key-fun elem)))
	root)))



(defun empty-tree (root)
  "Predicate of search trees; return t iff empty."
  (null (search-tree-node-leftson root)))



(defun leftmost (tree-node &aux next)
  "return leftmost descendant of tree-node"
  ;; used by pop-least-element and inorder-successor
  (loop (if (null (setq next (search-tree-node-leftson tree-node)))
	    (return tree-node)
	    (setq tree-node next))))



(defun rightmost (header &aux next tree-node)
  "return rightmost descendant of header"
  ;; used by pop-largest-element
  ;; recall that root of tree is leftson of header, which is a dummy
  (setq tree-node (search-tree-node-leftson header))
  (loop (if (null (setq next (search-tree-node-rightson tree-node)))
	    (return tree-node)
	    (setq tree-node next))))


 
(defun pop-least-element (header)
  "return least element of binary search tree; delete from tree as side-effect"
  ;; Note value slots of search-tree-nodes are lists of a-star-nodes, all of
  ;; which have same f-cost = key slot of search-tree-node.  This function
  ;; arbitrarily returns first element of list with smallest f-cost,
  ;; then deletes it from the list.  If it was the last element of the list
  ;; for the node with smallest key, that node is deleted from the search
  ;; tree.  (That's why we have a pointer to the node's parent).
  ;; Node with smallest f-cost is leftmost descendant of header.
  (let* ( (place (leftmost header))
	 (result (pop (search-tree-node-value place))) )
      (decf (search-tree-node-num-elements place))
      (when (null (search-tree-node-value place))
	(when (search-tree-node-rightson place)
	  (setf (search-tree-node-parent
		  (search-tree-node-rightson place))
		(search-tree-node-parent place)))
	(setf (search-tree-node-leftson
	        (search-tree-node-parent place))
	      (search-tree-node-rightson place)))
      result))




(defun pop-largest-element (header)
  "return largest element of binary search tree; delete from tree as side-effect"
  ;; Note value slots of search-tree-nodes are lists of a-star-nodes, all of
  ;; which have same  key slot of search-tree-node.  This function
  ;; arbitrarily returns first element of list with largest key
  ;; then deletes it from the list.  If it was the last element of the list
  ;; for the node with largest key, that node is deleted from the search
  ;; tree. We need to take special account of the case when the largest element
  ;; is the last element in the root node of the search-tree.  In this case, it
  ;; will be in the leftson of the dummy header.  In all other cases,
  ;; it will be in the rightson of its parent.
  (let* ( (place (rightmost header)) 
	 (result (pop (search-tree-node-value place))) )
      (decf (search-tree-node-num-elements place))      
      (when (null (search-tree-node-value place))
	(cond ( (eq place (search-tree-node-leftson header))
	       (setf (search-tree-node-leftson header)
		     (search-tree-node-leftson place)) )
	      (t (when (search-tree-node-leftson place)
		   (setf (search-tree-node-parent
			   (search-tree-node-leftson place))
			 (search-tree-node-parent place)))
		 (setf (search-tree-node-rightson
			 (search-tree-node-parent place))
		       (search-tree-node-leftson place)))))
      result))




(defun least-key (header)
  "return least key of binary search tree; no side effects"
  (search-tree-node-key (leftmost header)))


(defun largest-key (header)
  "return least key of binary search tree; no side effects"
  (search-tree-node-key (rightmost header)))



(defun insert-element (element parent key
		       &optional (direction #'search-tree-node-leftson)
		       &aux place)
  "insert new element at proper place in binary search tree"
  ;; See Reingold and Hansen, Data Structures, sect. 7.2.
  ;; When called initially, parent will be the header, hence go left.
  ;; Element is an a-star-node.  If tree node with key = f-cost of
  ;; element already exists, just push element onto list in that
  ;; node's value slot.  Else have to make new tree node.
  (loop (cond ( (null (setq place (funcall direction parent)))
	       (let ( (new-node (make-search-tree-node
				  :value (list element) :num-elements 1
				  :parent parent :key key
				  :leftson nil :rightson nil)) )
		 (if (eq direction #'search-tree-node-leftson)
		     (setf (search-tree-node-leftson parent) new-node)
		     (setf (search-tree-node-rightson parent) new-node)))
	       (return t))
	      ( (= key (search-tree-node-key place))
	       (push element (search-tree-node-value place))
	       (incf (search-tree-node-num-elements place))
	       (return t))
	      ( (< key (search-tree-node-key place))
	       (setq parent place)
	       (setq direction #'search-tree-node-leftson) )
	      (t (setq parent place)
		 (setq direction #'search-tree-node-rightson)))))




(defun randomized-insert-element (element parent key
		       &optional (direction #'search-tree-node-leftson)
		       &aux place)
  "insert new element at proper place in binary search tree -- break
   ties randomly"
  ;; This is just like the above, except that elements with equal keys
  ;; are shuffled randomly.  Not a "perfect shuffle", but the point is
  ;; just to randomize whenever  an arbitrary choice is to be made.

  (loop (cond ( (null (setq place (funcall direction parent)))
	       (let ( (new-node (make-search-tree-node
				  :value (list element) :num-elements 1
				  :parent parent :key key
				  :leftson nil :rightson nil)) )
		 (if (eq direction #'search-tree-node-leftson)
		     (setf (search-tree-node-leftson parent) new-node)
		     (setf (search-tree-node-rightson parent) new-node)))
	       (return t))
	      ( (= key (search-tree-node-key place))
	       (setf (search-tree-node-value place)
		     (randomized-push element (search-tree-node-value place)))
	       (incf (search-tree-node-num-elements place))	       
	       (return t))
	      ( (< key (search-tree-node-key place))
	       (setq parent place)
	       (setq direction #'search-tree-node-leftson) )
	      (t (setq parent place)
		 (setq direction #'search-tree-node-rightson)))))




(defun randomized-push (element list)
  "return list with element destructively inserted at random into list"
  (let ((n (random (+ 1 (length list)))) )
    (cond ((= 0 n)
	   (cons element list))
	  (t (push element (cdr (nthcdr (- n 1) list)))
	     list))))




(defun find-element (element parent key
		       &optional (direction #'search-tree-node-leftson)
		       &aux place)
  "return t if element is int tree"
  (loop (cond ( (null (setq place (funcall direction parent)))
		  (return nil) )
		 ( (= key (search-tree-node-key place))
		  (return (find element (search-tree-node-value place)
				:test #'eq)) ) 
		 ( (< key (search-tree-node-key place))
		  (setq parent place)
		  (setq direction #'search-tree-node-leftson) )
		 (t (setq parent place)
		    (setq direction #'search-tree-node-rightson)))))





(defun delete-element (element parent key &optional (error-p t)
		       &aux (direction #'search-tree-node-leftson)
		       place)
  "delete element from binary search tree"
  ;; When called initially, parent will be the header.
  ;; Have to search for node containing element, using key, also
  ;; keep track of parent of node.  Delete element from list for
  ;; node;  if it's the last element on that list, delete node from
  ;; binary tree.  See Reingold and Hansen, Data Structures, pp. 301, 309.
  ;; if error-p is t, signals error if element not found;  else just
  ;; returns t if element found, nil otherwise.
  (loop (setq place (funcall direction parent))
	(cond ( (null place) (if error-p
				 (error "delete-element: element not found") 
				 (return nil)) )
	      ( (= key (search-tree-node-key place))
	       (cond ( (find element (search-tree-node-value place) :test #'eq)
		      ;; In this case we've found the right binary
		      ;; search-tree node, so we should delete the
		      ;; element from the list of nodes 
		      (setf (search-tree-node-value place)
			    (remove element (search-tree-node-value place)
				    :test #'eq))
		      (decf (search-tree-node-num-elements place))
		      (when (null (search-tree-node-value place))
			;; If we've deleted the last element, we
			;; should delete the node from the binary search tree.
			(cond ( (null (search-tree-node-leftson place))
			       ;; If place has no leftson sub-tree, replace it
			       ;; by its right sub-tree.
			       (when (search-tree-node-rightson place)
				 (setf (search-tree-node-parent
					 (search-tree-node-rightson place))
				       parent))
			       (if (eq direction #'search-tree-node-leftson)
				   (setf (search-tree-node-leftson parent)
					 (search-tree-node-rightson place))
				   (setf (search-tree-node-rightson parent)
					 (search-tree-node-rightson place))) )
			      ( (null (search-tree-node-rightson place) )
			       ;; Else if place has no right sub-tree,
			       ;; replace it by its left sub-tree.
			       (when (search-tree-node-leftson place)
				 (setf (search-tree-node-parent
					 (search-tree-node-leftson place))
				       parent))
			       (if (eq direction #'search-tree-node-leftson)
				   (setf (search-tree-node-leftson parent)
					 (search-tree-node-leftson place))
				   (setf (search-tree-node-rightson parent)
					 (search-tree-node-leftson place))) )
			      (t ;; Else find the "inorder-successor" of
			       ;; place,  which must have nil leftson.
			       ;; Let it replace place, making its left
			       ;; sub-tree be place's current left
			       ;; sub-tree, and replace it by its own
			       ;; right sub-tree. (For details, see
			       ;; Reingold & Hansen, Data Structures, p. 301.)
			       (let ( (next (inorder-successor place)) )
				 (setf (search-tree-node-leftson next)
				       (search-tree-node-leftson place))
				 (setf (search-tree-node-parent
					 (search-tree-node-leftson next))
				       next)
				 (if (eq direction #'search-tree-node-leftson)
				     (setf (search-tree-node-leftson
					    parent) next) 
				     (setf (search-tree-node-rightson parent)
					   next))
				 (unless (eq next (search-tree-node-rightson
						    place))
				   (setf (search-tree-node-leftson
					   (search-tree-node-parent next))
					 (search-tree-node-rightson next))
				   (when (search-tree-node-rightson next)
				     (setf (search-tree-node-parent
					     (search-tree-node-rightson next))
					   (search-tree-node-parent next)))
				   (setf (search-tree-node-rightson next)
					 (search-tree-node-rightson
					   place))
				   (setf (search-tree-node-parent
					   (search-tree-node-rightson next))
					 next))
				 (setf (search-tree-node-parent next)
				       (search-tree-node-parent place))))))
		      (return t))
		     (t (if error-p
			    (error "delete-element:  element not found") 
			    (return nil)))) )
	      ( (< key (search-tree-node-key place))
	       (setq parent place)
	       (setq direction #'search-tree-node-leftson))
	      (t (setq parent place)
		 (setq direction #'search-tree-node-rightson)))))





(defun inorder-successor (tree-node)
  "return inorder-successor of tree-node assuming it has a right son"
  ;; this is used by function delete-element when deleting a node from
  ;; the binary search tree.  See Reingold and Hansen, pp. 301, 309.
  ;; The inorder-successor is the leftmost descendant of the rightson.
  (leftmost (search-tree-node-rightson tree-node)))



(defun list-elements (parent &aux child)
  "return list of elements in tree"
  (append (when (setq child (search-tree-node-leftson parent))
            (list-elements child))
          (search-tree-node-value parent)
          (when (setq child (search-tree-node-rightson parent))
            (list-elements child))))