aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToby Cubitt2011-05-27 19:58:29 -0300
committerStefan Monnier2011-05-27 19:58:29 -0300
commiteb95d01d15ed25ed7e27ee4d1b883588c58ce306 (patch)
treecbe322b2633ef81c26549854a60f6a04e66bc763
parent3769ddcf1eeb85bb3f408d90a8bb44f383620882 (diff)
downloademacs-eb95d01d15ed25ed7e27ee4d1b883588c58ce306.tar.gz
emacs-eb95d01d15ed25ed7e27ee4d1b883588c58ce306.zip
* lisp/emacs-lisp/avl-tree.el: New avl-tree-stack datatype. Add new
traversal functions for avl-trees. (avl-tree--stack): New struct. (avl-tree-stack-p, avl-tree--stack-repopulate): New funs. (avl-tree-enter): Add optional `updatefun' arg. (avl-tree--do-enter): Add optional `updatefun' arg. Change return value. (avl-tree-delete): Add optional `test' and `nilflag' args. (avl-tree--do-delete): Add `test' and `nilflag' args. Change return value. (avl-tree-member): Add optional `nilflag' (avl-tree-member-p): New function. (avl-tree-mapc, avl-tree-mapf, avl-tree-mapcar): New functions. (avl-tree-stack, avl-tree-stack-pop, avl-tree-stack-first) (avl-tree-stack-empty-p): New functions.
-rw-r--r--lisp/ChangeLog18
-rw-r--r--lisp/emacs-lisp/avl-tree.el304
2 files changed, 270 insertions, 52 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 2b6e0dc41f9..8c40eab356b 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,5 +1,21 @@
12009-11-23 Toby Cubitt <toby-predictive@dr-qubit.org> 12009-11-23 Toby Cubitt <toby-predictive@dr-qubit.org>
2 2
3 * emacs-lisp/avl-tree.el: New avl-tree-stack datatype. Add new
4 traversal functions for avl-trees.
5 (avl-tree--stack): New struct.
6 (avl-tree-stack-p, avl-tree--stack-repopulate): New funs.
7 (avl-tree-enter): Add optional `updatefun' arg.
8 (avl-tree--do-enter): Add optional `updatefun' arg. Change return value.
9 (avl-tree-delete): Add optional `test' and `nilflag' args.
10 (avl-tree--do-delete): Add `test' and `nilflag' args. Change return value.
11 (avl-tree-member): Add optional `nilflag'
12 (avl-tree-member-p): New function.
13 (avl-tree-mapc, avl-tree-mapf, avl-tree-mapcar): New functions.
14 (avl-tree-stack, avl-tree-stack-pop, avl-tree-stack-first)
15 (avl-tree-stack-empty-p): New functions.
16
172009-11-23 Toby Cubitt <toby-predictive@dr-qubit.org>
18
3 * emacs-lisp/avl-tree.el (avl-tree--del-balance): Rename from 19 * emacs-lisp/avl-tree.el (avl-tree--del-balance): Rename from
4 avl-tree--del-balance1 and make it work both ways. 20 avl-tree--del-balance1 and make it work both ways.
5 (avl-tree--del-balance2): Remove. 21 (avl-tree--del-balance2): Remove.
@@ -10,7 +26,7 @@
10 New macros. 26 New macros.
11 (avl-tree--mapc, avl-tree-map): Add direction argument. 27 (avl-tree--mapc, avl-tree-map): Add direction argument.
12 28
132011-05-27 David Michael <fedora.dm0@gmail.com> 292011-05-27 David Michael <fedora.dm0@gmail.com> (tiny change)
14 30
15 * files.el (interpreter-mode-alist): Add rbash (bug#8745). 31 * files.el (interpreter-mode-alist): Add rbash (bug#8745).
16 32
diff --git a/lisp/emacs-lisp/avl-tree.el b/lisp/emacs-lisp/avl-tree.el
index 82585fd4322..e8b7a1f9a8b 100644
--- a/lisp/emacs-lisp/avl-tree.el
+++ b/lisp/emacs-lisp/avl-tree.el
@@ -200,36 +200,52 @@ Return t if the height of the tree has shrunk."
200 (avl-tree--node-left br)) 200 (avl-tree--node-left br))
201 t))) 201 t)))
202 202
203(defun avl-tree--do-delete (cmpfun root branch data) 203(defun avl-tree--do-delete (cmpfun root branch data test nilflag)
204 ;; Return t if the height of the tree has shrunk. 204 "Delete DATA from BRANCH of node ROOT.
205\(See `avl-tree-delete' for TEST and NILFLAG).
206
207Return cons cell (SHRUNK . DATA), where SHRUNK is t if the
208height of the tree has shrunk and nil otherwise, and DATA is
209the releted data."
205 (let ((br (avl-tree--node-branch root branch))) 210 (let ((br (avl-tree--node-branch root branch)))
206 (cond 211 (cond
212 ;; DATA not in tree.
207 ((null br) 213 ((null br)
208 nil) 214 (cons nil nilflag))
209 215
210 ((funcall cmpfun data (avl-tree--node-data br)) 216 ((funcall cmpfun data (avl-tree--node-data br))
211 (if (avl-tree--do-delete cmpfun br 0 data) 217 (let ((ret (avl-tree--do-delete cmpfun br 0 data test nilflag)))
212 (avl-tree--del-balance root branch 0))) 218 (cons (if (car ret) (avl-tree--del-balance root branch 0))
219 (cdr ret))))
213 220
214 ((funcall cmpfun (avl-tree--node-data br) data) 221 ((funcall cmpfun (avl-tree--node-data br) data)
215 (if (avl-tree--do-delete cmpfun br 1 data) 222 (let ((ret (avl-tree--do-delete cmpfun br 1 data test nilflag)))
216 (avl-tree--del-balance root branch 1))) 223 (cons (if (car ret) (avl-tree--del-balance root branch 1))
224 (cdr ret))))
225
226 (t ; Found it.
227 ;; if it fails TEST, do nothing
228 (if (and test (not (funcall test (avl-tree--node-data br))))
229 (cons nil nilflag)
230 (cond
231 ((null (avl-tree--node-right br))
232 (setf (avl-tree--node-branch root branch)
233 (avl-tree--node-left br))
234 (cons t (avl-tree--node-data br)))
217 235
218 (t 236 ((null (avl-tree--node-left br))
219 ;; Found it. Let's delete it. 237 (setf (avl-tree--node-branch root branch)
220 (cond 238 (avl-tree--node-right br))
221 ((null (avl-tree--node-right br)) 239 (cons t (avl-tree--node-data br)))
222 (setf (avl-tree--node-branch root branch) (avl-tree--node-left br)) 240
223 t) 241 (t
242 (if (avl-tree--do-del-internal br 0 br)
243 (cons (avl-tree--del-balance root branch 0)
244 (avl-tree--node-data br))
245 (cons nil (avl-tree--node-data br))))
246 ))))))
224 247
225 ((null (avl-tree--node-left br))
226 (setf (avl-tree--node-branch root branch)
227 (avl-tree--node-right br))
228 t)
229 248
230 (t
231 (if (avl-tree--do-del-internal br 0 br)
232 (avl-tree--del-balance root branch 0))))))))
233 249
234;; ---------------------------------------------------------------- 250;; ----------------------------------------------------------------
235;; Entering data 251;; Entering data
@@ -284,27 +300,44 @@ Return t if the height of the tree has grown."
284 (avl-tree--node-branch node branch)) 0)) 300 (avl-tree--node-branch node branch)) 0))
285 nil)))) 301 nil))))
286 302
287(defun avl-tree--do-enter (cmpfun root branch data) 303(defun avl-tree--do-enter (cmpfun root branch data &optional updatefun)
288 ;; Return t if height of tree ROOT has grown. INTERNAL USE ONLY. 304 "Enter DATA in BRANCH of ROOT node.
305\(See `avl-tree-enter' for UPDATEFUN).
306
307Return cons cell (GREW . DATA), where GREW is t if height
308of tree ROOT has grown and nil otherwise, and DATA is the
309inserted data."
289 (let ((br (avl-tree--node-branch root branch))) 310 (let ((br (avl-tree--node-branch root branch)))
290 (cond 311 (cond
291 ((null br) 312 ((null br)
292 ;; Data not in tree, insert it. 313 ;; Data not in tree, insert it.
293 (setf (avl-tree--node-branch root branch) 314 (setf (avl-tree--node-branch root branch)
294 (avl-tree--node-create nil nil data 0)) 315 (avl-tree--node-create nil nil data 0))
295 t) 316 (cons t data))
296 317
297 ((funcall cmpfun data (avl-tree--node-data br)) 318 ((funcall cmpfun data (avl-tree--node-data br))
298 (and (avl-tree--do-enter cmpfun br 0 data) 319 (let ((ret (avl-tree--do-enter cmpfun br 0 data updatefun)))
299 (avl-tree--enter-balance root branch 0))) 320 (cons (and (car ret) (avl-tree--enter-balance root branch 0))
321 (cdr ret))))
300 322
301 ((funcall cmpfun (avl-tree--node-data br) data) 323 ((funcall cmpfun (avl-tree--node-data br) data)
302 (and (avl-tree--do-enter cmpfun br 1 data) 324 (let ((ret (avl-tree--do-enter cmpfun br 1 data updatefun)))
303 (avl-tree--enter-balance root branch 1))) 325 (cons (and (car ret) (avl-tree--enter-balance root branch 1))
326 (cdr ret))))
304 327
328 ;; Data already in tree, update it.
305 (t 329 (t
306 (setf (avl-tree--node-data br) data) 330 (let ((newdata
307 nil)))) 331 (if updatefun
332 (funcall updatefun data (avl-tree--node-data br))
333 data)))
334 (if (or (funcall cmpfun newdata data)
335 (funcall cmpfun data newdata))
336 (error "avl-tree-enter:\
337 updated data does not match existing data"))
338 (setf (avl-tree--node-data br) newdata)
339 (cons nil newdata)) ; return value
340 ))))
308 341
309;; ---------------------------------------------------------------- 342;; ----------------------------------------------------------------
310 343
@@ -348,6 +381,30 @@ itself."
348 (avl-tree--node-data root) 381 (avl-tree--node-data root)
349 (avl-tree--node-balance root)))) 382 (avl-tree--node-balance root))))
350 383
384(defstruct (avl-tree--stack
385 (:constructor nil)
386 (:constructor avl-tree--stack-create
387 (tree &optional reverse
388 &aux
389 (store
390 (if (avl-tree-empty tree)
391 nil
392 (list (avl-tree--root tree))))))
393 (:copier nil))
394 reverse store)
395
396(defalias 'avl-tree-stack-p 'avl-tree--stack-p
397 "Return t if argument is an avl-tree-stack, nil otherwise.")
398
399(defun avl-tree--stack-repopulate (stack)
400 ;; Recursively push children of the node at the head of STACK onto the
401 ;; front of the STACK, until a leaf is reached.
402 (let ((node (car (avl-tree--stack-store stack)))
403 (dir (if (avl-tree--stack-reverse stack) 1 0)))
404 (when node ; check for emtpy stack
405 (while (setq node (avl-tree--node-branch node dir))
406 (push node (avl-tree--stack-store stack))))))
407
351 408
352;; ================================================================ 409;; ================================================================
353;;; The public functions which operate on AVL trees. 410;;; The public functions which operate on AVL trees.
@@ -367,30 +424,56 @@ and returns non-nil if A is less than B, and nil otherwise.")
367 "Return t if avl tree TREE is emtpy, otherwise return nil." 424 "Return t if avl tree TREE is emtpy, otherwise return nil."
368 (null (avl-tree--root tree))) 425 (null (avl-tree--root tree)))
369 426
370(defun avl-tree-enter (tree data) 427(defun avl-tree-enter (tree data &optional updatefun)
371 "In the avl tree TREE insert DATA. 428 "Insert DATA into the avl tree TREE.
372Return DATA." 429
373 (avl-tree--do-enter (avl-tree--cmpfun tree) 430If an element that matches DATA (according to the tree's
374 (avl-tree--dummyroot tree) 431comparison function, see `avl-tree-create') already exists in
375 0 432TREE, it will be replaced by DATA by default.
376 data) 433
377 data) 434If UPDATEFUN is supplied and an element matching DATA already
378 435exists in TREE, UPDATEFUN is called with two arguments: DATA, and
379(defun avl-tree-delete (tree data) 436the matching element. Its return value replaces the existing
380 "From the avl tree TREE, delete DATA. 437element. This value *must* itself match DATA (and hence the
381Return the element in TREE which matched DATA, 438pre-existing data), or an error will occur.
382nil if no element matched." 439
383 (avl-tree--do-delete (avl-tree--cmpfun tree) 440Returns the new data."
384 (avl-tree--dummyroot tree) 441 (cdr (avl-tree--do-enter (avl-tree--cmpfun tree)
385 0 442 (avl-tree--dummyroot tree)
386 data)) 443 0 data updatefun)))
387 444
388(defun avl-tree-member (tree data) 445(defun avl-tree-delete (tree data &optional test nilflag)
446 "Delete the element matching DATA from the avl tree TREE.
447Matching uses the comparison function previously specified in
448`avl-tree-create' when TREE was created.
449
450Returns the deleted element, or nil if no matching element was
451found.
452
453Optional argument NILFLAG specifies a value to return instead of
454nil if nothing was deleted, so that this case can be
455distinguished from the case of a successfully deleted null
456element.
457
458If supplied, TEST specifies a test that a matching element must
459pass before it is deleted. If a matching element is found, it is
460passed as an argument to TEST, and is deleted only if the return
461value is non-nil."
462 (cdr (avl-tree--do-delete (avl-tree--cmpfun tree)
463 (avl-tree--dummyroot tree)
464 0 data test nilflag)))
465
466
467(defun avl-tree-member (tree data &optional nilflag)
389 "Return the element in the avl tree TREE which matches DATA. 468 "Return the element in the avl tree TREE which matches DATA.
390Matching uses the compare function previously specified in 469Matching uses the comparison function previously specified in
391`avl-tree-create' when TREE was created. 470`avl-tree-create' when TREE was created.
392 471
393If there is no such element in the tree, the value is nil." 472If there is no such element in the tree, nil is
473returned. Optional argument NILFLAG specifies a value to return
474instead of nil in this case. This allows non-existent elements to
475be distinguished from a null element. (See also
476`avl-tree-member-p', which does this for you.)"
394 (let ((node (avl-tree--root tree)) 477 (let ((node (avl-tree--root tree))
395 (compare-function (avl-tree--cmpfun tree))) 478 (compare-function (avl-tree--cmpfun tree)))
396 (catch 'found 479 (catch 'found
@@ -401,7 +484,16 @@ If there is no such element in the tree, the value is nil."
401 ((funcall compare-function (avl-tree--node-data node) data) 484 ((funcall compare-function (avl-tree--node-data node) data)
402 (setq node (avl-tree--node-right node))) 485 (setq node (avl-tree--node-right node)))
403 (t (throw 'found (avl-tree--node-data node))))) 486 (t (throw 'found (avl-tree--node-data node)))))
404 nil))) 487 nilflag)))
488
489
490(defun avl-tree-member-p (tree data)
491 "Return t if an element matching DATA exists in the avl tree TREE,
492otherwise return nil. Matching uses the comparison function
493previously specified in `avl-tree-create' when TREE was created."
494 (let ((flag '(nil)))
495 (not (eq (avl-tree-member tree data flag) flag))))
496
405 497
406(defun avl-tree-map (__map-function__ tree &optional reverse) 498(defun avl-tree-map (__map-function__ tree &optional reverse)
407 "Modify all elements in the avl tree TREE by applying FUNCTION. 499 "Modify all elements in the avl tree TREE by applying FUNCTION.
@@ -418,6 +510,57 @@ descending order if REVERSE is non-nil."
418 (avl-tree--root tree) 510 (avl-tree--root tree)
419 (if reverse 1 0))) 511 (if reverse 1 0)))
420 512
513
514(defun avl-tree-mapc (__map-function__ tree &optional reverse)
515 "Apply FUNCTION to all elements in avl tree TREE,
516for side-effect only.
517
518FUNCTION is applied to the elements in ascending order, or
519descending order if REVERSE is non-nil."
520 (avl-tree--mapc
521 (lambda (node)
522 (funcall __map-function__ (avl-tree--node-data node)))
523 (avl-tree--root tree)
524 (if reverse 1 0)))
525
526
527(defun avl-tree-mapf
528 (__map-function__ combinator tree &optional reverse)
529 "Apply FUNCTION to all elements in avl tree TREE,
530and combine the results using COMBINATOR.
531
532The FUNCTION is applied and the results are combined in ascending
533order, or descending order if REVERSE is non-nil."
534 (let (avl-tree-mapf--accumulate)
535 (avl-tree--mapc
536 (lambda (node)
537 (setq avl-tree-mapf--accumulate
538 (funcall combinator
539 (funcall __map-function__
540 (avl-tree--node-data node))
541 avl-tree-mapf--accumulate)))
542 (avl-tree--root tree)
543 (if reverse 0 1))
544 (nreverse avl-tree-mapf--accumulate)))
545
546
547(defun avl-tree-mapcar (__map-function__ tree &optional reverse)
548 "Apply FUNCTION to all elements in avl tree TREE,
549and make a list of the results.
550
551The FUNCTION is applied and the list constructed in ascending
552order, or descending order if REVERSE is non-nil.
553
554Note that if you don't care about the order in which FUNCTION is
555applied, just that the resulting list is in the correct order,
556then
557
558 (avl-tree-mapf function 'cons tree (not reverse))
559
560is more efficient."
561 (nreverse (avl-tree-mapf __map-function__ 'cons tree reverse)))
562
563
421(defun avl-tree-first (tree) 564(defun avl-tree-first (tree)
422 "Return the first element in TREE, or nil if TREE is empty." 565 "Return the first element in TREE, or nil if TREE is empty."
423 (let ((node (avl-tree--root tree))) 566 (let ((node (avl-tree--root tree)))
@@ -460,6 +603,65 @@ descending order if REVERSE is non-nil."
460 "Clear the avl tree TREE." 603 "Clear the avl tree TREE."
461 (setf (avl-tree--root tree) nil)) 604 (setf (avl-tree--root tree) nil))
462 605
606
607(defun avl-tree-stack (tree &optional reverse)
608 "Return an object that behaves like a sorted stack
609of all elements of TREE.
610
611If REVERSE is non-nil, the stack is sorted in reverse order.
612\(See also `avl-tree-stack-pop'\).
613
614Note that any modification to TREE *immediately* invalidates all
615avl-tree-stacks created before the modification (in particular,
616calling `avl-tree-stack-pop' will give unpredictable results).
617
618Operations on these objects are significantly more efficient than
619constructing a real stack with `avl-tree-flatten' and using
620standard stack functions. As such, they can be useful in
621implementing efficient algorithms of AVL trees. However, in cases
622where mapping functions `avl-tree-mapc', `avl-tree-mapcar' or
623`avl-tree-mapf' would be sufficient, it is better to use one of
624those instead."
625 (let ((stack (avl-tree--stack-create tree reverse)))
626 (avl-tree--stack-repopulate stack)
627 stack))
628
629
630(defun avl-tree-stack-pop (avl-tree-stack &optional nilflag)
631 "Pop the first element from AVL-TREE-STACK.
632\(See also `avl-tree-stack'\).
633
634Returns nil if the stack is empty, or NILFLAG if specified. (The
635latter allows an empty stack to be distinguished from a null
636element stored in the AVL tree.)"
637 (let (node next)
638 (if (not (setq node (pop (avl-tree--stack-store avl-tree-stack))))
639 nilflag
640 (when (setq next
641 (avl-tree--node-branch
642 node
643 (if (avl-tree--stack-reverse avl-tree-stack) 0 1)))
644 (push next (avl-tree--stack-store avl-tree-stack))
645 (avl-tree--stack-repopulate avl-tree-stack))
646 (avl-tree--node-data node))))
647
648
649(defun avl-tree-stack-first (avl-tree-stack &optional nilflag)
650 "Return the first element of AVL-TREE-STACK, without removing it
651from the stack.
652
653Returns nil if the stack is empty, or NILFLAG if specified. (The
654latter allows an empty stack to be distinguished from a null
655element stored in the AVL tree.)"
656 (or (car (avl-tree--stack-store avl-tree-stack))
657 nilflag))
658
659
660(defun avl-tree-stack-empty-p (avl-tree-stack)
661 "Return t if AVL-TREE-STACK is empty, nil otherwise."
662 (null (avl-tree--stack-store avl-tree-stack)))
663
664
463(provide 'avl-tree) 665(provide 'avl-tree)
464 666
465;;; avl-tree.el ends here 667;;; avl-tree.el ends here