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
41 * Heap this node belongs to.
43 struct GNUNET_CONTAINER_Heap *heap;
48 struct GNUNET_CONTAINER_HeapNode *parent;
53 struct GNUNET_CONTAINER_HeapNode *left_child;
58 struct GNUNET_CONTAINER_HeapNode *right_child;
66 * Cost for this element.
68 GNUNET_CONTAINER_HeapCostType cost;
71 * Number of elements below this node in the heap
72 * (excluding this node itself).
74 unsigned int tree_size;
79 * Handle to a node in a heap.
81 struct GNUNET_CONTAINER_Heap
87 struct GNUNET_CONTAINER_HeapNode *root;
90 * Current position of our random walk.
92 struct GNUNET_CONTAINER_HeapNode *walk_pos;
95 * Number of elements in the heap.
100 * How is the heap sorted?
102 enum GNUNET_CONTAINER_HeapOrder order;
109 * Check if internal invariants hold for the given node.
111 * @param node subtree to check
114 check (const struct GNUNET_CONTAINER_HeapNode *node)
118 GNUNET_assert (node->tree_size ==
119 ((node->left_child ==
120 NULL) ? 0 : 1 + node->left_child->tree_size) +
121 ((node->right_child ==
122 NULL) ? 0 : 1 + node->right_child->tree_size));
123 check (node->left_child);
124 check (node->right_child);
128 #define CHECK(n) check(n)
130 #define CHECK(n) do {} while (0)
137 * @param order how should the heap be sorted?
138 * @return handle to the heap
140 struct GNUNET_CONTAINER_Heap *
141 GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order)
143 struct GNUNET_CONTAINER_Heap *heap;
145 heap = GNUNET_new (struct GNUNET_CONTAINER_Heap);
152 * Destroys the heap. Only call on a heap that
155 * @param heap heap to destroy
158 GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap)
160 GNUNET_break (heap->size == 0);
166 * Get element stored at the root of @a heap.
168 * @param heap Heap to inspect.
169 * @return Element at the root, or NULL if heap is empty.
172 GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap)
174 if (heap->root == NULL)
176 return heap->root->element;
181 * Get @a element and @a cost stored at the root of @a heap.
183 * @param[in] heap Heap to inspect.
184 * @param[out] element Root element is returned here.
185 * @param[out] cost Cost of @a element is returned here.
186 * @return #GNUNET_YES if an element is returned,
187 * #GNUNET_NO if the heap is empty.
190 GNUNET_CONTAINER_heap_peek2 (const struct GNUNET_CONTAINER_Heap *heap,
192 GNUNET_CONTAINER_HeapCostType *cost)
194 if (NULL == heap->root)
197 *element = heap->root->element;
199 *cost = heap->root->cost;
205 * Get the current size of the heap
207 * @param heap the heap to get the size of
208 * @return number of elements stored
211 GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap)
218 * Get the current cost of the node
220 * @param node the node to get the cost of
221 * @return cost of the node
223 GNUNET_CONTAINER_HeapCostType
224 GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode
232 * Iterate over the children of the given node.
234 * @param heap argument to give to iterator
235 * @param node node to iterate over
236 * @param iterator function to call on each node
237 * @param iterator_cls closure for iterator
238 * @return GNUNET_YES to continue to iterate
241 node_iterator (const struct GNUNET_CONTAINER_Heap *heap,
242 struct GNUNET_CONTAINER_HeapNode *node,
243 GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
248 node_iterator (heap, node->left_child, iterator, iterator_cls))
251 node_iterator (heap, node->right_child, iterator, iterator_cls))
253 return iterator (iterator_cls, node, node->element, node->cost);
258 * Iterate over all entries in the heap.
260 * @param heap the heap
261 * @param iterator function to call on each entry
262 * @param iterator_cls closure for iterator
265 GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap,
266 GNUNET_CONTAINER_HeapIterator iterator,
269 (void) node_iterator (heap, heap->root, iterator, iterator_cls);
274 * Perform a random walk of the tree. The walk is biased
275 * towards elements closer to the root of the tree (since
276 * each walk starts at the root and ends at a random leaf).
277 * The heap internally tracks the current position of the
280 * @param heap heap to walk
281 * @return data stored at the next random node in the walk;
282 * NULL if the tree is empty.
285 GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap)
287 struct GNUNET_CONTAINER_HeapNode *pos;
290 if (heap->root == NULL)
292 pos = heap->walk_pos;
295 element = pos->element;
298 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
299 2)) ? pos->right_child : pos->left_child;
305 * Insert the given node 'node' into the subtree starting
306 * at 'pos' (while keeping the tree somewhat balanced).
308 * @param heap heap to modify
309 * @param pos existing tree
310 * @param node node to insert (which may be a subtree itself)
313 insert_node (struct GNUNET_CONTAINER_Heap *heap,
314 struct GNUNET_CONTAINER_HeapNode *pos,
315 struct GNUNET_CONTAINER_HeapNode *node)
317 struct GNUNET_CONTAINER_HeapNode *parent;
319 GNUNET_assert (node->parent == NULL);
320 while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >=
322 : (pos->cost <= node->cost))
324 /* node is descendent of pos */
325 pos->tree_size += (1 + node->tree_size);
326 if (pos->left_child == NULL)
328 pos->left_child = node;
332 if (pos->right_child == NULL)
334 pos->right_child = node;
338 /* keep it balanced by descending into smaller subtree */
339 if (pos->left_child->tree_size < pos->right_child->tree_size)
340 pos = pos->left_child;
342 pos = pos->right_child;
344 /* make 'node' parent of 'pos' */
345 parent = pos->parent;
347 node->parent = parent;
354 if (parent->left_child == pos)
355 parent->left_child = node;
357 parent->right_child = node;
359 /* insert 'pos' below 'node' */
360 insert_node (heap, node, pos);
366 * Inserts a new element into the heap.
368 * @param heap heap to modify
369 * @param element element to insert
370 * @param cost cost for the element
371 * @return node for the new element
373 struct GNUNET_CONTAINER_HeapNode *
374 GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element,
375 GNUNET_CONTAINER_HeapCostType cost)
377 struct GNUNET_CONTAINER_HeapNode *node;
379 node = GNUNET_new (struct GNUNET_CONTAINER_HeapNode);
381 node->element = element;
384 if (NULL == heap->root)
387 insert_node (heap, heap->root, node);
388 GNUNET_assert (heap->size == heap->root->tree_size + 1);
395 * Remove root of the heap.
397 * @param heap heap to modify
398 * @return element data stored at the root node, NULL if heap is empty
401 GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap)
404 struct GNUNET_CONTAINER_HeapNode *root;
406 if (NULL == (root = heap->root))
410 if (root->left_child == NULL)
412 heap->root = root->right_child;
413 if (root->right_child != NULL)
414 root->right_child->parent = NULL;
416 else if (root->right_child == NULL)
418 heap->root = root->left_child;
419 root->left_child->parent = NULL;
423 root->left_child->parent = NULL;
424 root->right_child->parent = NULL;
425 heap->root = root->left_child;
426 insert_node (heap, heap->root, root->right_child);
428 if (heap->walk_pos == root)
429 heap->walk_pos = heap->root;
432 GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
433 (heap->size == heap->root->tree_size + 1));
441 * Remove the given node 'node' from the tree and update
442 * the 'tree_size' fields accordingly. Preserves the
443 * children of 'node' and does NOT change the overall
444 * 'size' field of the tree.
447 remove_node (struct GNUNET_CONTAINER_HeapNode *node)
449 struct GNUNET_CONTAINER_HeapNode *ancestor;
450 struct GNUNET_CONTAINER_Heap *heap = node->heap;
452 /* update 'size' of the ancestors */
454 while (NULL != (ancestor = ancestor->parent))
455 ancestor->tree_size--;
457 /* update 'size' of node itself */
458 if (node->left_child != NULL)
459 node->tree_size -= (1 + node->left_child->tree_size);
460 if (node->right_child != NULL)
461 node->tree_size -= (1 + node->right_child->tree_size);
463 /* unlink 'node' itself and insert children in its place */
464 if (node->parent == NULL)
466 if (node->left_child != NULL)
468 heap->root = node->left_child;
469 node->left_child->parent = NULL;
470 if (node->right_child != NULL)
472 node->right_child->parent = NULL;
473 insert_node (heap, heap->root, node->right_child);
478 heap->root = node->right_child;
479 if (node->right_child != NULL)
480 node->right_child->parent = NULL;
485 if (node->parent->left_child == node)
486 node->parent->left_child = NULL;
488 node->parent->right_child = NULL;
489 if (node->left_child != NULL)
491 node->left_child->parent = NULL;
492 node->parent->tree_size -= (1 + node->left_child->tree_size);
493 insert_node (heap, node->parent, node->left_child);
495 if (node->right_child != NULL)
497 node->right_child->parent = NULL;
498 node->parent->tree_size -= (1 + node->right_child->tree_size);
499 insert_node (heap, node->parent, node->right_child);
503 node->left_child = NULL;
504 node->right_child = NULL;
505 GNUNET_assert (node->tree_size == 0);
511 * Removes a node from the heap.
513 * @param node node to remove
514 * @return element data stored at the node
517 GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node)
520 struct GNUNET_CONTAINER_Heap *heap;
524 if (heap->walk_pos == node)
525 (void) GNUNET_CONTAINER_heap_walk_get_next (heap);
529 if (heap->walk_pos == node)
530 heap->walk_pos = NULL;
534 GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
535 (heap->size == heap->root->tree_size + 1));
542 * Updates the cost of any node in the tree
544 * @param node node for which the cost is to be changed
545 * @param new_cost new cost for the node
548 GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_HeapNode *node,
549 GNUNET_CONTAINER_HeapCostType new_cost)
551 struct GNUNET_CONTAINER_Heap *heap = node->heap;
554 node->cost = new_cost;
555 if (NULL == heap->root)