1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include <libpspp/heap.h>
22 #include <libpspp/pool.h>
23 #include <libpspp/assertion.h>
30 /* Comparison function and auxiliary data. */
31 heap_compare_func *compare;
35 struct heap_node **nodes; /* Element 0 unused, 1...CNT are the heap. */
36 size_t cnt; /* Number of elements in heap. */
37 size_t cap; /* Max CNT without allocating more memory. */
40 static inline void set_node (struct heap *, size_t idx, struct heap_node *);
41 static inline bool less (const struct heap *, size_t a, size_t b);
42 static bool UNUSED is_heap (const struct heap *);
43 static inline void propagate_down (struct heap *, size_t idx);
44 static inline bool propagate_up (struct heap *, size_t idx);
46 /* Creates and return a new min-heap. COMPARE is used as
47 comparison function and passed AUX as auxiliary data.
49 To obtain a max-heap, negate the return value of the
50 comparison function. */
52 heap_create (heap_compare_func *compare, const void *aux)
54 struct heap *h = xmalloc (sizeof *h);
63 /* Destroys H (callback for pool). */
65 destroy_callback (void *h)
70 /* Creates and return a new min-heap and registers for its
71 destruction with POOL. COMPARE is used as comparison function
72 and passed AUX as auxiliary data.
74 To obtain a max-heap, negate the return value of the
75 comparison function. */
77 heap_create_pool (struct pool *pool,
78 heap_compare_func *compare, const void *aux)
80 struct heap *h = heap_create (compare, aux);
81 pool_register (pool, destroy_callback, h);
85 /* Destroys heap H. */
87 heap_destroy (struct heap *h)
96 /* Returns true if H is empty, false if it contains at least one
99 heap_is_empty (const struct heap *h)
104 /* Returns the number of elements in H. */
106 heap_count (const struct heap *h)
111 /* Heap nodes may be moved around in memory as necessary, e.g. as
112 the result of an realloc operation on a block that contains a
113 heap node. Once this is done, call this function passing the
114 NODE that was moved and its heap H before attempting any other
117 heap_moved (struct heap *h, struct heap_node *node)
119 assert (node->idx <= h->cnt);
120 h->nodes[node->idx] = node;
123 /* Returns the node with the minimum value in H, which must not
126 heap_minimum (const struct heap *h)
128 assert (!heap_is_empty (h));
132 /* Inserts the given NODE into H. */
134 heap_insert (struct heap *h, struct heap_node *node)
136 if (h->cnt >= h->cap)
138 h->cap = 2 * (h->cap + 8);
139 h->nodes = xnrealloc (h->nodes, h->cap + 1, sizeof *h->nodes);
143 set_node (h, h->cnt, node);
144 propagate_up (h, h->cnt);
146 expensive_assert (is_heap (h));
149 /* Deletes the given NODE from H. */
151 heap_delete (struct heap *h, struct heap_node *node)
153 assert (node->idx <= h->cnt);
154 assert (h->nodes[node->idx] == node);
156 if (node->idx < h->cnt)
158 set_node (h, node->idx, h->nodes[h->cnt--]);
159 heap_changed (h, h->nodes[node->idx]);
165 /* After client code changes the value represented by a heap
166 node, it must use this function to update the heap structure.
167 It is also safe (but not useful) to call this function if
168 NODE's value has not changed.
170 It is not safe to update more than one node's value in the
171 heap, then to call this function for each node. Instead,
172 update a single node's value, call this function, update
173 another node's value, and so on. Alternatively, remove all
174 the nodes from the heap, update their values, then re-insert
177 heap_changed (struct heap *h, struct heap_node *node)
179 assert (node->idx <= h->cnt);
180 assert (h->nodes[node->idx] == node);
182 if (!propagate_up (h, node->idx))
183 propagate_down (h, node->idx);
185 expensive_assert (is_heap (h));
188 static inline size_t lesser_node (const struct heap *, size_t a, size_t b);
189 static inline void swap_nodes (struct heap *, size_t a, size_t b);
191 /* Sets h->nodes[IDX] and updates NODE's 'idx' field
194 set_node (struct heap *h, size_t idx, struct heap_node *node)
196 h->nodes[idx] = node;
197 h->nodes[idx]->idx = idx;
200 /* Moves the node with the given IDX down the heap as necessary
201 to restore the heap property. */
203 propagate_down (struct heap *h, size_t idx)
208 least = lesser_node (h, idx, 2 * idx);
209 least = lesser_node (h, least, 2 * idx + 1);
213 swap_nodes (h, least, idx);
218 /* Moves the node with the given IDX up the heap as necessary
219 to restore the heap property. Returns true if the node was
220 moved, false otherwise.*/
222 propagate_up (struct heap *h, size_t idx)
225 for (; idx > 1 && less (h, idx, idx / 2); idx /= 2)
227 swap_nodes (h, idx, idx / 2);
233 /* Returns true if, in H, the node with index A has value less
234 than the node with index B. */
236 less (const struct heap *h, size_t a, size_t b)
238 return h->compare (h->nodes[a], h->nodes[b], h->aux) < 0;
241 /* Returns A or B according to which is the index of the node
242 with the lesser value. B is allowed to be out of the range of
243 valid node indexes, in which case A is returned. */
245 lesser_node (const struct heap *h, size_t a, size_t b)
247 assert (a <= h->cnt);
248 return b > h->cnt || less (h, a, b) ? a : b;
251 /* Swaps, in H, the nodes with indexes A and B. */
253 swap_nodes (struct heap *h, size_t a, size_t b)
257 assert (a <= h->cnt);
258 assert (b <= h->cnt);
261 set_node (h, a, h->nodes[b]);
265 /* Returns true if H is a valid heap,
268 is_heap (const struct heap *h)
272 for (i = 2; i <= h->cnt; i++)
273 if (less (h, i, i / 2))
276 for (i = 1; i <= h->cnt; i++)
277 if (h->nodes[i]->idx != i)