/usr/share/acl2-6.3/books/leftist-trees/leftist-tree-defuns.lisp is in acl2-books-source 6.3-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 | #|
Leftist Trees, Version 0.1
Copyright (C) 2012 by Ben Selfridge <benself@cs.utexas.edu>
leftist-tree-defuns.lisp
This file contains the function definitions and lays out
the structure of leftist trees (otherwise known as leftist
heaps). With an eye towards heapsort, we use lexorder as
the basic ordering function, since that is the ordering
used in the other sorting algorithms in books/sorting.
This implementation follows "Purely Functional Data
Structures" by Chris Okasaki.
|#
(in-package "ACL2")
(deflabel leftist-trees :doc ":DOC-SECTION leftist-trees
An implementation of Leftist Trees. ~/~/
Leftist trees are an efficient implementation of binary heaps. Regular
(completely balanced) binary heaps are tricky, and in most cases near
impossible, to implement in functional languages because of the need
for constant-time access to the last element in the tree (that element
being the node in the bottom-most level of the tree, furthest to the
right). Leftist trees avoid this by replacing this \"balanced\"
requirement with the requirement that the right-most spine of the tree
be small relative to the overal number of elements in the tree. Since
the fundamental heap operations (insert, delete-min) only recur on the
right spine of the tree in question, this guarantees that these
operations are O(log(n)), where n is the size of the tree.
Leftist trees look like this:
(rank root left right)
where \"rank\" is defined to be the length of the right spine of the
tree, \"root\" is the root element of the tree, \"left\" is the left
sub-tree, and \"right\" is the right sub-tree.
Leftist trees are heap-ordered, and they are \"balanced\" in a loose
sense. In particular, the size of the tree is at least as big as an
exponential function of the rank:
size(tree) >= 2^(rank(tree)) - 1,
or, solving for rank(tree) and noting that the rank is always an
integer,
rank(tree) <= floor(log(size(tree) + 1)).
The important tree operations are INSERT-LT, FIND-MIN-LT, and
DELETE-MIN-LT. A useful function called BUILD-LT is also provided,
which constructs a leftist tree from a list. An important constant is
*EMPTY-LT*, which is the empty tree (for this implementation, just
NIL).
To learn how to use the trees, see :DOC LEFTIST-TREE-FNS. To see some
useful theorems about leftist trees, including the rank bound above,
see :DOC LEFTIST-TREE-THMS.
Sources:
- Okasaki, Chris. Purely Functional Data Structures. Cambridge,
U.K.: Cambridge UP, 1998. 17-20. Print.
~/
")
(defdoc leftist-tree-fns
":doc-section leftist-trees
All functions and constants related to leftist trees.~/~/
------------------------------------------------------------
Functions and Constants
------------------------------------------------------------
Function/Constant Name Result
(supporting function) Type
---------------------- ----
** STRUCTURE **
RANK-LT natural
ROOT-LT ?
LEFT-LT ltree
RIGHT-LT ltree
*EMPTY-LT* NIL
IS-EMPTY-LT boolean
PROPER-LT boolean
** OPERATIONS **
MERGE-LT ltree
MAKE-LT ltree
INSERT-LT ltree
FIND-MIN-LT ?
DELETE-MIN-LT ltree
BUILD-LT ltree
** MISCELLANEOUS **
SIZE-LT natural
MEMBER-LT boolean
LENGTH-RIGHT-SPINE-LT natural
LENGTH-TO-NIL-LT natural
~/")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; STRUCTURE OF LEFTIST TREES ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defdoc leftist-tree-structure
":doc-section leftist-tree-fns
Functions relating to building and recognizing leftist trees.
~/~/
~/")
(defun rank-lt (tree)
":doc-section leftist-tree-structure
rank of a leftist tree~/~/
Returns the rank of the tree. The rank of a tree is formally defined
to be the length of its right spine. Empty trees have rank 0.~/"
(if (atom tree)
0
(car tree)))
(defun root-lt (tree)
":doc-section leftist-tree-structure
root of a leftist tree~/~/
Returns the root of a non-empty tree.~/"
(cadr tree))
(defun left-lt (tree)
":doc-section leftist-tree-structure
left sub-tree of a leftist tree~/~/
Returns the left sub-tree of a non-empty tree.~/"
(caddr tree))
(defun right-lt (tree)
":doc-section leftist-tree-structure
right sub-tree of a leftist tree~/~/
Returns the right sub-tree of a non-empty tree.~/"
(cadddr tree))
(defconst *empty-lt* NIL
":doc-section leftist-tree-structure
the default empty leftist tree~/~/
The default \"empty\" tree (just NIL)~/"
)
(defun is-empty-lt (tree)
":doc-section leftist-tree-structure
checks if a tree is empty~/~/
Checks if a tree is empty. For simplicity, we only require (atom
tree).~/"
(atom tree))
(defun proper-lt (tree)
":doc-section leftist-tree-structure
checks that a tree is a legitimate leftist tree~/~/
Checks that a tree is a legitimate Leftist Tree.
The basic recursive requirements are:
* both the left and right sub-trees are proper
* (rank) the rank is 1 + the rank of the right sub-tree
* (leftist) the rank of right sub-tree is less than or
equal to the rank of the left sub-tree
* (heap-ordered) if either of the sub-trees are non-trivial,
then their roots are larger than the root of the tree
~/"
(if (is-empty-lt tree)
(and (null tree)
(equal (rank-lt tree) 0))
(and (proper-lt (left-lt tree))
(proper-lt (right-lt tree))
(equal (rank-lt tree)
(+ 1 (rank-lt (right-lt tree))))
(<= (rank-lt (right-lt tree))
(rank-lt (left-lt tree)))
(implies (consp (left-lt tree))
(lexorder (root-lt tree)
(root-lt (left-lt tree))))
(implies (consp (right-lt tree))
(lexorder (root-lt tree)
(root-lt (right-lt tree)))))))
;;;;;;;;;;;;;;;;;;;;;
;; HEAP OPERATIONS ;;
;;;;;;;;;;;;;;;;;;;;;
(defdoc leftist-tree-ops
":doc-section leftist-tree-fns
The basic heap operations of leftist trees.~/~/
The core operation here is MERGE-LT. All the other operations are
defined in terms of MERGE-LT, which makes leftist trees relatively
easy to reason about.~/")
(defun make-lt (x a b)
(if (<= (rank-lt b) (rank-lt a))
(list (+ 1 (rank-lt b)) x a b)
(list (+ 1 (rank-lt a)) x b a)))
(defun merge-lt (tree1 tree2)
":doc-section leftist-tree-ops
merge two leftist trees~/~/
Merge two leftist trees.
Two leftist trees are merged by \"merging their right spines as you
would merge two sorted lists, and then swapping the children of nodes
along this path as necessary to restore the leftist property.\"
(Okasaki)~/"
(declare (xargs :measure (+ (acl2-count tree1)
(acl2-count tree2))))
(cond ((is-empty-lt tree2) tree1)
((is-empty-lt tree1) tree2)
(t (if (lexorder (root-lt tree1) (root-lt tree2))
(make-lt (root-lt tree1)
(left-lt tree1)
(merge-lt (right-lt tree1) tree2))
(make-lt (root-lt tree2)
(left-lt tree2)
(merge-lt tree1 (right-lt tree2)))))))
(defun insert-lt (x tree)
":doc-section leftist-tree-ops
insert an element into a leftist tree~/~/
Insert an element into a leftist tree. This function is defined in
terms of MERGE-LT.
Example usage:
(INSERT-LT 2 (INSERT-LT 3 (INSERT-LT 4 *EMPTY-LT*)))
This creates a leftist tree with elements 2, 3, 4.~/"
(merge-lt (list 1 x NIL NIL) tree))
(defun find-min-lt (tree)
":doc-section leftist-tree-ops
get the minimum element of a leftist tree~/~/
Get the minimum element of a nonempty tree. Assuming the tree in
question is PROPER-LT, this is just the root of the tree.~/"
(cond ((is-empty-lt tree) nil)
(t (root-lt tree))))
(defun delete-min-lt (tree)
":doc-section leftist-tree-ops
delete the minimum element of a leftist tree~/~/
Delete the minimum element of a nonempty tree. This is accomplisghed
by simply merging the two subtrees.~/"
(cond ((is-empty-lt tree) nil)
(t (merge-lt (left-lt tree) (right-lt tree)))))
(defun build-lt (l)
":doc-section leftist-tree-ops
build a leftist tree from a list~/~/
Builds a leftist tree from a list of elements. This is accomplished by
right-folding the INSERT-LT function over the list, starting with
*EMPTY-LT*.~/"
(if (atom l)
*empty-lt*
(insert-lt (car l) (build-lt (cdr l)))))
;;;;;;;;;;;;;;;;;;;
;; MISCELLANEOUS ;;
;;;;;;;;;;;;;;;;;;;
(defdoc leftist-tree-misc
":doc-section leftist-tree-fns
Miscellaneous, but nonetheless useful, functions for leftist trees~/~/
~/")
(defun size-lt (tree)
":doc-section leftist-tree-misc
total number of elements in a leftist tree~/~/
Returns the total number of elements in the tree.~/"
(cond ((is-empty-lt tree) 0)
(t (+ 1
(size-lt (left-lt tree))
(size-lt (right-lt tree))))))
(defun member-lt (x tree)
":doc-section leftist-tree-misc
tests membership in a leftist tree~/~/
Tests whether something is an element of the tree. Note that this is
not simply a brute-force search; if the root of the tree is greater
than what we are looking for, we return nil. So in order for this
function to work, the tree has to be PROPER-LT.~/"
(cond ((is-empty-lt tree) nil)
((equal x (root-lt tree)) t)
((lexorder x (root-lt tree)) nil)
(t (or (member-lt x (left-lt tree))
(member-lt x (right-lt tree))))))
(defun length-right-spine-lt (tree)
":doc-section leftist-tree-misc
length of the right spine of a leftist tree~/
This is equivalent to RANK-LT.~/
This function actually counts the length of the right spine of the
tree. We will prove that this equals the rank of the tree.~/"
(if (is-empty-lt tree)
0
(+ 1 (length-right-spine-lt (right-lt tree)))))
(defun length-to-nil-lt (tree)
":doc-section leftist-tree-misc
length of the shortest path to an empty node~/
This is equivalent to RANK-LT.~/
Returns the length of the shortest path to an empty node. We will
prove that this equals the rank of the tree.~/"
(cond ((is-empty-lt tree) 0)
(t (+ 1 (min (length-to-nil-lt (left-lt tree))
(length-to-nil-lt (right-lt tree)))))))
|