2 This file is part of GNUnet.
3 (C) 2008 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @author Nathan Evans
23 * @file util/container_heap.c
24 * @brief Implementation of heap operations
28 #include "gnunet_protocols.h"
29 #include "gnunet_util_lib.h"
32 * Generic heap node structure, contains pointer to parent
33 * left child, right child, and actual neighbor.
35 struct GNUNET_CONTAINER_heap_node
37 struct GNUNET_CONTAINER_heap_node *parent;
39 struct GNUNET_CONTAINER_heap_node *left_child;
41 struct GNUNET_CONTAINER_heap_node *right_child;
43 GNUNET_CONTAINER_HeapCost cost;
49 struct GNUNET_CONTAINER_Heap
53 unsigned int max_size;
55 enum GNUNET_CONTAINER_HeapOrder type;
57 struct GNUNET_CONTAINER_heap_node *root;
59 struct GNUNET_CONTAINER_heap_node *traversal_pos;
65 * Returns element stored at root of tree, doesn't effect anything
67 * @param heap the heap
68 * @return NULL if the heap is empty
71 GNUNET_CONTAINER_heap_peek (struct GNUNET_CONTAINER_Heap *heap)
73 if ((heap == NULL) || (heap->root == NULL))
76 return heap->root->element;
80 next_power_of_2 (int v)
93 internal_print (struct GNUNET_CONTAINER_heap_node *root)
95 fprintf (stdout, "%llu\n", (unsigned long long) root->cost);
96 if (root->left_child != NULL)
98 fprintf (stdout, "LEFT of %llu\n", (unsigned long long) root->cost);
99 internal_print (root->left_child);
101 if (root->right_child != NULL)
103 fprintf (stdout, "RIGHT of %llu\n", (unsigned long long) root->cost);
104 internal_print (root->right_child);
109 printTree (struct GNUNET_CONTAINER_Heap *root)
111 internal_print (root->root);
115 struct GNUNET_CONTAINER_Heap *
116 GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder type)
118 struct GNUNET_CONTAINER_Heap *heap;
119 heap = malloc (sizeof (struct GNUNET_CONTAINER_Heap));
123 heap->traversal_pos = NULL;
130 GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap)
132 while (heap->size > 0)
133 GNUNET_CONTAINER_heap_remove_root (heap);
138 static struct GNUNET_CONTAINER_heap_node *
139 find_element (struct GNUNET_CONTAINER_heap_node *node, void *element)
141 struct GNUNET_CONTAINER_heap_node *ret;
146 if (node->element == element)
149 if (node->left_child != NULL)
150 ret = find_element (node->left_child, element);
152 if ((ret == NULL) && (node->right_child != NULL))
153 ret = find_element (node->right_child, element);
158 static struct GNUNET_CONTAINER_heap_node *
159 getNextPos (struct GNUNET_CONTAINER_Heap *root)
161 struct GNUNET_CONTAINER_heap_node *ret;
162 struct GNUNET_CONTAINER_heap_node *parent;
166 ret = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_heap_node));
167 pos = root->size + 1;
168 ret->left_child = NULL;
169 ret->right_child = NULL;
179 for (i = next_power_of_2 (pos) >> 2; i > 1; i >>= 1)
181 if (((pos / i) % 2) == 0)
182 parent = parent->left_child;
184 parent = parent->right_child;
187 ret->parent = parent;
189 parent->left_child = ret;
191 parent->right_child = ret;
199 static struct GNUNET_CONTAINER_heap_node *
200 getPos (struct GNUNET_CONTAINER_Heap *root, unsigned int pos)
202 struct GNUNET_CONTAINER_heap_node *ret;
206 if (pos > root->size)
213 for (i = next_power_of_2 (pos) >> 2; i > 0; i >>= 1)
215 if (((pos / i) % 2) == 0)
216 ret = ret->left_child;
218 ret = ret->right_child;
227 swapNodes (struct GNUNET_CONTAINER_heap_node *first,
228 struct GNUNET_CONTAINER_heap_node *second,
229 struct GNUNET_CONTAINER_Heap *root)
232 GNUNET_CONTAINER_HeapCost temp_cost;
234 temp_element = first->element;
235 temp_cost = first->cost;
236 first->element = second->element;
237 first->cost = second->cost;
238 second->element = temp_element;
239 second->cost = temp_cost;
245 percolateHeap (struct GNUNET_CONTAINER_heap_node *pos,
246 struct GNUNET_CONTAINER_Heap *root)
249 while ((pos->parent != NULL) &&
250 (((root->type == GNUNET_CONTAINER_HEAP_ORDER_MAX)
251 && (pos->parent->cost < pos->cost))
252 || ((root->type == GNUNET_CONTAINER_HEAP_ORDER_MIN)
253 && (pos->parent->cost > pos->cost))))
255 swapNodes (pos, pos->parent, root);
265 percolateDownHeap (struct GNUNET_CONTAINER_heap_node *pos,
266 struct GNUNET_CONTAINER_Heap *root)
268 struct GNUNET_CONTAINER_heap_node *switchNeighbor;
270 switchNeighbor = pos;
272 if ((root->type == GNUNET_CONTAINER_HEAP_ORDER_MAX))
274 if ((pos->left_child != NULL)
275 && (pos->left_child->cost > switchNeighbor->cost))
277 switchNeighbor = pos->left_child;
280 if ((pos->right_child != NULL)
281 && (pos->right_child->cost > switchNeighbor->cost))
283 switchNeighbor = pos->right_child;
286 else if ((root->type == GNUNET_CONTAINER_HEAP_ORDER_MIN))
288 if ((pos->left_child != NULL)
289 && (pos->left_child->cost < switchNeighbor->cost))
291 switchNeighbor = pos->left_child;
294 if ((pos->right_child != NULL)
295 && (pos->right_child->cost < switchNeighbor->cost))
297 switchNeighbor = pos->right_child;
301 if (switchNeighbor != pos)
303 swapNodes (switchNeighbor, pos, root);
304 percolateDownHeap (switchNeighbor, root);
311 GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_Heap *root,
315 struct GNUNET_CONTAINER_heap_node *del_node;
316 struct GNUNET_CONTAINER_heap_node *last;
317 GNUNET_CONTAINER_HeapCost old_cost;
320 del_node = find_element (root->root, element);
322 if (del_node == NULL)
324 else if (del_node == root->root)
325 return GNUNET_CONTAINER_heap_remove_root (root);
327 ret = del_node->element;
328 last = getPos (root, root->size);
330 old_cost = del_node->cost;
331 del_node->element = last->element;
332 del_node->cost = last->cost;
334 if (last->parent->left_child == last)
335 last->parent->left_child = NULL;
336 if (last->parent->right_child == last)
337 last->parent->right_child = NULL;
339 if (root->traversal_pos == last)
341 root->traversal_pos = root->root;
346 if (del_node->cost > old_cost)
348 if (root->type == GNUNET_CONTAINER_HEAP_ORDER_MAX)
349 percolateHeap (del_node, root);
350 else if (root->type == GNUNET_CONTAINER_HEAP_ORDER_MIN)
351 percolateDownHeap (del_node, root);
353 else if (del_node->cost < old_cost)
355 if (root->type == GNUNET_CONTAINER_HEAP_ORDER_MAX)
356 percolateDownHeap (del_node, root);
357 else if (root->type == GNUNET_CONTAINER_HEAP_ORDER_MIN)
358 percolateHeap (del_node, root);
365 GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *root,
366 void *element, GNUNET_CONTAINER_HeapCost cost)
368 struct GNUNET_CONTAINER_heap_node *new_pos;
372 if (root->max_size > root->size)
374 new_pos = getNextPos (root);
375 new_pos->element = element;
376 new_pos->cost = cost;
379 percolateHeap (new_pos, root);
390 GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *root)
393 struct GNUNET_CONTAINER_heap_node *root_node;
394 struct GNUNET_CONTAINER_heap_node *last;
396 if ((root == NULL) || (root->size == 0) || (root->root == NULL))
399 root_node = root->root;
400 ret = root_node->element;
401 last = getPos (root, root->size);
403 if ((root_node == last) && (root->size == 1))
405 /* We are removing the last node in the heap! */
407 root->traversal_pos = NULL;
408 GNUNET_assert (0 == --root->size);
412 if (last->parent->left_child == last)
413 last->parent->left_child = NULL;
414 else if (last->parent->right_child == last)
415 last->parent->right_child = NULL;
417 root_node->element = last->element;
418 root_node->cost = last->cost;
420 if (root->traversal_pos == last)
422 root->traversal_pos = root->root;
427 percolateDownHeap (root->root, root);
432 updatedCost (struct GNUNET_CONTAINER_Heap *root,
433 struct GNUNET_CONTAINER_heap_node *node)
435 struct GNUNET_CONTAINER_heap_node *parent;
438 return GNUNET_SYSERR;
440 parent = node->parent;
442 if ((root->type == GNUNET_CONTAINER_HEAP_ORDER_MAX) && (parent != NULL)
443 && (node->cost > parent->cost))
444 percolateHeap (node, root);
445 else if ((root->type == GNUNET_CONTAINER_HEAP_ORDER_MIN) && (parent != NULL)
446 && (node->cost < parent->cost))
447 percolateHeap (node, root);
448 else if (root->type == GNUNET_CONTAINER_HEAP_ORDER_MAX)
449 percolateDownHeap (node, root);
450 else if (root->type == GNUNET_CONTAINER_HEAP_ORDER_MIN)
451 percolateDownHeap (node, root);
458 GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *root,
460 GNUNET_CONTAINER_HeapCost new_cost)
462 struct GNUNET_CONTAINER_heap_node *node;
463 int ret = GNUNET_YES;
464 node = find_element (root->root, element);
468 node->cost = new_cost;
469 ret = updatedCost (root, node);
474 internal_iterator (struct GNUNET_CONTAINER_Heap *root,
475 struct GNUNET_CONTAINER_heap_node *node,
476 GNUNET_CONTAINER_HeapIterator iterator, void *cls)
480 internal_iterator (root, node->left_child, iterator, cls);
481 internal_iterator (root, node->right_child, iterator, cls);
482 iterator (cls, node->element, node->cost);
486 GNUNET_CONTAINER_heap_iterate (struct GNUNET_CONTAINER_Heap *heap,
487 GNUNET_CONTAINER_HeapIterator iterator,
490 internal_iterator (heap, heap->root, iterator, cls);
495 GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *root)
500 if ((root->traversal_pos == NULL) && (root->root != NULL))
502 root->traversal_pos = root->root;
505 if (root->traversal_pos == NULL)
508 element = root->traversal_pos->element;
510 choice = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
515 root->traversal_pos = root->traversal_pos->right_child;
518 root->traversal_pos = root->traversal_pos->left_child;
527 GNUNET_CONTAINER_heap_get_size (struct GNUNET_CONTAINER_Heap *heap)