2 This file is part of GNUnet.
3 Copyright (C) 2008, 2009 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file util/container_heap.c
23 * @brief Implementation of a heap
24 * @author Nathan Evans
25 * @author Christian Grothoff
29 #include "gnunet_container_lib.h"
31 #define LOG(kind, ...) GNUNET_log_from(kind, "util-container-heap", __VA_ARGS__)
33 #define EXTRA_CHECKS 0
38 struct GNUNET_CONTAINER_HeapNode {
40 * Heap this node belongs to.
42 struct GNUNET_CONTAINER_Heap *heap;
47 struct GNUNET_CONTAINER_HeapNode *parent;
52 struct GNUNET_CONTAINER_HeapNode *left_child;
57 struct GNUNET_CONTAINER_HeapNode *right_child;
65 * Cost for this element.
67 GNUNET_CONTAINER_HeapCostType cost;
70 * Number of elements below this node in the heap
71 * (excluding this node itself).
73 unsigned int tree_size;
77 * Handle to a node in a heap.
79 struct GNUNET_CONTAINER_Heap {
83 struct GNUNET_CONTAINER_HeapNode *root;
86 * Current position of our random walk.
88 struct GNUNET_CONTAINER_HeapNode *walk_pos;
91 * Number of elements in the heap.
96 * How is the heap sorted?
98 enum GNUNET_CONTAINER_HeapOrder order;
104 * Check if internal invariants hold for the given node.
106 * @param node subtree to check
109 check(const struct GNUNET_CONTAINER_HeapNode *node)
113 GNUNET_assert(node->tree_size ==
114 ((node->left_child ==
115 NULL) ? 0 : 1 + node->left_child->tree_size) +
116 ((node->right_child ==
117 NULL) ? 0 : 1 + node->right_child->tree_size));
118 check(node->left_child);
119 check(node->right_child);
123 #define CHECK(n) check(n)
125 #define CHECK(n) do {} while (0)
132 * @param order how should the heap be sorted?
133 * @return handle to the heap
135 struct GNUNET_CONTAINER_Heap *
136 GNUNET_CONTAINER_heap_create(enum GNUNET_CONTAINER_HeapOrder order)
138 struct GNUNET_CONTAINER_Heap *heap;
140 heap = GNUNET_new(struct GNUNET_CONTAINER_Heap);
147 * Destroys the heap. Only call on a heap that
150 * @param heap heap to destroy
153 GNUNET_CONTAINER_heap_destroy(struct GNUNET_CONTAINER_Heap *heap)
155 GNUNET_break(heap->size == 0);
161 * Get element stored at the root of @a heap.
163 * @param heap Heap to inspect.
164 * @return Element at the root, or NULL if heap is empty.
167 GNUNET_CONTAINER_heap_peek(const struct GNUNET_CONTAINER_Heap *heap)
169 if (heap->root == NULL)
171 return heap->root->element;
176 * Get @a element and @a cost stored at the root of @a heap.
178 * @param[in] heap Heap to inspect.
179 * @param[out] element Root element is returned here.
180 * @param[out] cost Cost of @a element is returned here.
181 * @return #GNUNET_YES if an element is returned,
182 * #GNUNET_NO if the heap is empty.
185 GNUNET_CONTAINER_heap_peek2(const struct GNUNET_CONTAINER_Heap *heap,
187 GNUNET_CONTAINER_HeapCostType *cost)
189 if (NULL == heap->root)
192 *element = heap->root->element;
194 *cost = heap->root->cost;
200 * Get the current size of the heap
202 * @param heap the heap to get the size of
203 * @return number of elements stored
206 GNUNET_CONTAINER_heap_get_size(const struct GNUNET_CONTAINER_Heap *heap)
213 * Get the current cost of the node
215 * @param node the node to get the cost of
216 * @return cost of the node
218 GNUNET_CONTAINER_HeapCostType
219 GNUNET_CONTAINER_heap_node_get_cost(const struct GNUNET_CONTAINER_HeapNode
227 * Iterate over the children of the given node.
229 * @param heap argument to give to iterator
230 * @param node node to iterate over
231 * @param iterator function to call on each node
232 * @param iterator_cls closure for iterator
233 * @return GNUNET_YES to continue to iterate
236 node_iterator(const struct GNUNET_CONTAINER_Heap *heap,
237 struct GNUNET_CONTAINER_HeapNode *node,
238 GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
243 node_iterator(heap, node->left_child, iterator, iterator_cls))
246 node_iterator(heap, node->right_child, iterator, iterator_cls))
248 return iterator(iterator_cls, node, node->element, node->cost);
253 * Iterate over all entries in the heap.
255 * @param heap the heap
256 * @param iterator function to call on each entry
257 * @param iterator_cls closure for iterator
260 GNUNET_CONTAINER_heap_iterate(const struct GNUNET_CONTAINER_Heap *heap,
261 GNUNET_CONTAINER_HeapIterator iterator,
264 (void)node_iterator(heap, heap->root, iterator, iterator_cls);
269 * Perform a random walk of the tree. The walk is biased
270 * towards elements closer to the root of the tree (since
271 * each walk starts at the root and ends at a random leaf).
272 * The heap internally tracks the current position of the
275 * @param heap heap to walk
276 * @return data stored at the next random node in the walk;
277 * NULL if the tree is empty.
280 GNUNET_CONTAINER_heap_walk_get_next(struct GNUNET_CONTAINER_Heap *heap)
282 struct GNUNET_CONTAINER_HeapNode *pos;
285 if (heap->root == NULL)
287 pos = heap->walk_pos;
290 element = pos->element;
293 GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK,
294 2)) ? pos->right_child : pos->left_child;
300 * Insert the given node 'node' into the subtree starting
301 * at 'pos' (while keeping the tree somewhat balanced).
303 * @param heap heap to modify
304 * @param pos existing tree
305 * @param node node to insert (which may be a subtree itself)
308 insert_node(struct GNUNET_CONTAINER_Heap *heap,
309 struct GNUNET_CONTAINER_HeapNode *pos,
310 struct GNUNET_CONTAINER_HeapNode *node)
312 struct GNUNET_CONTAINER_HeapNode *parent;
314 GNUNET_assert(node->parent == NULL);
315 while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >=
317 : (pos->cost <= node->cost))
319 /* node is descendent of pos */
320 pos->tree_size += (1 + node->tree_size);
321 if (pos->left_child == NULL)
323 pos->left_child = node;
327 if (pos->right_child == NULL)
329 pos->right_child = node;
333 /* keep it balanced by descending into smaller subtree */
334 if (pos->left_child->tree_size < pos->right_child->tree_size)
335 pos = pos->left_child;
337 pos = pos->right_child;
339 /* make 'node' parent of 'pos' */
340 parent = pos->parent;
342 node->parent = parent;
349 if (parent->left_child == pos)
350 parent->left_child = node;
352 parent->right_child = node;
354 /* insert 'pos' below 'node' */
355 insert_node(heap, node, pos);
361 * Inserts a new element into the heap.
363 * @param heap heap to modify
364 * @param element element to insert
365 * @param cost cost for the element
366 * @return node for the new element
368 struct GNUNET_CONTAINER_HeapNode *
369 GNUNET_CONTAINER_heap_insert(struct GNUNET_CONTAINER_Heap *heap, void *element,
370 GNUNET_CONTAINER_HeapCostType cost)
372 struct GNUNET_CONTAINER_HeapNode *node;
374 node = GNUNET_new(struct GNUNET_CONTAINER_HeapNode);
376 node->element = element;
379 if (NULL == heap->root)
382 insert_node(heap, heap->root, node);
383 GNUNET_assert(heap->size == heap->root->tree_size + 1);
390 * Remove root of the heap.
392 * @param heap heap to modify
393 * @return element data stored at the root node, NULL if heap is empty
396 GNUNET_CONTAINER_heap_remove_root(struct GNUNET_CONTAINER_Heap *heap)
399 struct GNUNET_CONTAINER_HeapNode *root;
401 if (NULL == (root = heap->root))
405 if (root->left_child == NULL)
407 heap->root = root->right_child;
408 if (root->right_child != NULL)
409 root->right_child->parent = NULL;
411 else if (root->right_child == NULL)
413 heap->root = root->left_child;
414 root->left_child->parent = NULL;
418 root->left_child->parent = NULL;
419 root->right_child->parent = NULL;
420 heap->root = root->left_child;
421 insert_node(heap, heap->root, root->right_child);
423 if (heap->walk_pos == root)
424 heap->walk_pos = heap->root;
427 GNUNET_assert(((heap->size == 0) && (heap->root == NULL)) ||
428 (heap->size == heap->root->tree_size + 1));
436 * Remove the given node 'node' from the tree and update
437 * the 'tree_size' fields accordingly. Preserves the
438 * children of 'node' and does NOT change the overall
439 * 'size' field of the tree.
442 remove_node(struct GNUNET_CONTAINER_HeapNode *node)
444 struct GNUNET_CONTAINER_HeapNode *ancestor;
445 struct GNUNET_CONTAINER_Heap *heap = node->heap;
447 /* update 'size' of the ancestors */
449 while (NULL != (ancestor = ancestor->parent))
450 ancestor->tree_size--;
452 /* update 'size' of node itself */
453 if (node->left_child != NULL)
454 node->tree_size -= (1 + node->left_child->tree_size);
455 if (node->right_child != NULL)
456 node->tree_size -= (1 + node->right_child->tree_size);
458 /* unlink 'node' itself and insert children in its place */
459 if (node->parent == NULL)
461 if (node->left_child != NULL)
463 heap->root = node->left_child;
464 node->left_child->parent = NULL;
465 if (node->right_child != NULL)
467 node->right_child->parent = NULL;
468 insert_node(heap, heap->root, node->right_child);
473 heap->root = node->right_child;
474 if (node->right_child != NULL)
475 node->right_child->parent = NULL;
480 if (node->parent->left_child == node)
481 node->parent->left_child = NULL;
483 node->parent->right_child = NULL;
484 if (node->left_child != NULL)
486 node->left_child->parent = NULL;
487 node->parent->tree_size -= (1 + node->left_child->tree_size);
488 insert_node(heap, node->parent, node->left_child);
490 if (node->right_child != NULL)
492 node->right_child->parent = NULL;
493 node->parent->tree_size -= (1 + node->right_child->tree_size);
494 insert_node(heap, node->parent, node->right_child);
498 node->left_child = NULL;
499 node->right_child = NULL;
500 GNUNET_assert(node->tree_size == 0);
506 * Removes a node from the heap.
508 * @param node node to remove
509 * @return element data stored at the node
512 GNUNET_CONTAINER_heap_remove_node(struct GNUNET_CONTAINER_HeapNode *node)
515 struct GNUNET_CONTAINER_Heap *heap;
519 if (heap->walk_pos == node)
520 (void)GNUNET_CONTAINER_heap_walk_get_next(heap);
524 if (heap->walk_pos == node)
525 heap->walk_pos = NULL;
529 GNUNET_assert(((heap->size == 0) && (heap->root == NULL)) ||
530 (heap->size == heap->root->tree_size + 1));
537 * Updates the cost of any node in the tree
539 * @param node node for which the cost is to be changed
540 * @param new_cost new cost for the node
543 GNUNET_CONTAINER_heap_update_cost(struct GNUNET_CONTAINER_HeapNode *node,
544 GNUNET_CONTAINER_HeapCostType new_cost)
546 struct GNUNET_CONTAINER_Heap *heap = node->heap;
549 node->cost = new_cost;
550 if (NULL == heap->root)