container_heap.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2008, 2009 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file util/container_heap.c
  18. * @brief Implementation of a heap
  19. * @author Nathan Evans
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_container_lib.h"
  24. #define LOG(kind, ...) GNUNET_log_from (kind, "util-container-heap", \
  25. __VA_ARGS__)
  26. #define EXTRA_CHECKS 0
  27. /**
  28. * Node in the heap.
  29. */
  30. struct GNUNET_CONTAINER_HeapNode
  31. {
  32. /**
  33. * Heap this node belongs to.
  34. */
  35. struct GNUNET_CONTAINER_Heap *heap;
  36. /**
  37. * Parent node.
  38. */
  39. struct GNUNET_CONTAINER_HeapNode *parent;
  40. /**
  41. * Left child.
  42. */
  43. struct GNUNET_CONTAINER_HeapNode *left_child;
  44. /**
  45. * Right child.
  46. */
  47. struct GNUNET_CONTAINER_HeapNode *right_child;
  48. /**
  49. * Our element.
  50. */
  51. void *element;
  52. /**
  53. * Cost for this element.
  54. */
  55. GNUNET_CONTAINER_HeapCostType cost;
  56. /**
  57. * Number of elements below this node in the heap
  58. * (excluding this node itself).
  59. */
  60. unsigned int tree_size;
  61. };
  62. /**
  63. * Handle to a node in a heap.
  64. */
  65. struct GNUNET_CONTAINER_Heap
  66. {
  67. /**
  68. * Root of the heap.
  69. */
  70. struct GNUNET_CONTAINER_HeapNode *root;
  71. /**
  72. * Current position of our random walk.
  73. */
  74. struct GNUNET_CONTAINER_HeapNode *walk_pos;
  75. /**
  76. * Number of elements in the heap.
  77. */
  78. unsigned int size;
  79. /**
  80. * How is the heap sorted?
  81. */
  82. enum GNUNET_CONTAINER_HeapOrder order;
  83. };
  84. #if EXTRA_CHECKS
  85. /**
  86. * Check if internal invariants hold for the given node.
  87. *
  88. * @param node subtree to check
  89. */
  90. static void
  91. check (const struct GNUNET_CONTAINER_HeapNode *node)
  92. {
  93. if (NULL == node)
  94. return;
  95. GNUNET_assert (node->tree_size ==
  96. ((node->left_child ==
  97. NULL) ? 0 : 1 + node->left_child->tree_size)
  98. + ((node->right_child ==
  99. NULL) ? 0 : 1 + node->right_child->tree_size));
  100. check (node->left_child);
  101. check (node->right_child);
  102. }
  103. #define CHECK(n) check (n)
  104. #else
  105. #define CHECK(n) do {} while (0)
  106. #endif
  107. /**
  108. * Create a new heap.
  109. *
  110. * @param order how should the heap be sorted?
  111. * @return handle to the heap
  112. */
  113. struct GNUNET_CONTAINER_Heap *
  114. GNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order)
  115. {
  116. struct GNUNET_CONTAINER_Heap *heap;
  117. heap = GNUNET_new (struct GNUNET_CONTAINER_Heap);
  118. heap->order = order;
  119. return heap;
  120. }
  121. /**
  122. * Destroys the heap. Only call on a heap that
  123. * is already empty.
  124. *
  125. * @param heap heap to destroy
  126. */
  127. void
  128. GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap)
  129. {
  130. GNUNET_break (heap->size == 0);
  131. GNUNET_free (heap);
  132. }
  133. /**
  134. * Get element stored at the root of @a heap.
  135. *
  136. * @param heap Heap to inspect.
  137. * @return Element at the root, or NULL if heap is empty.
  138. */
  139. void *
  140. GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap)
  141. {
  142. if (heap->root == NULL)
  143. return NULL;
  144. return heap->root->element;
  145. }
  146. /**
  147. * Get @a element and @a cost stored at the root of @a heap.
  148. *
  149. * @param[in] heap Heap to inspect.
  150. * @param[out] element Root element is returned here.
  151. * @param[out] cost Cost of @a element is returned here.
  152. * @return #GNUNET_YES if an element is returned,
  153. * #GNUNET_NO if the heap is empty.
  154. */
  155. int
  156. GNUNET_CONTAINER_heap_peek2 (const struct GNUNET_CONTAINER_Heap *heap,
  157. void **element,
  158. GNUNET_CONTAINER_HeapCostType *cost)
  159. {
  160. if (NULL == heap->root)
  161. return GNUNET_NO;
  162. if (NULL != element)
  163. *element = heap->root->element;
  164. if (NULL != cost)
  165. *cost = heap->root->cost;
  166. return GNUNET_YES;
  167. }
  168. /**
  169. * Get the current size of the heap
  170. *
  171. * @param heap the heap to get the size of
  172. * @return number of elements stored
  173. */
  174. unsigned int
  175. GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap)
  176. {
  177. return heap->size;
  178. }
  179. /**
  180. * Get the current cost of the node
  181. *
  182. * @param node the node to get the cost of
  183. * @return cost of the node
  184. */
  185. GNUNET_CONTAINER_HeapCostType
  186. GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode
  187. *node)
  188. {
  189. return node->cost;
  190. }
  191. /**
  192. * Iterate over the children of the given node.
  193. *
  194. * @param heap argument to give to iterator
  195. * @param node node to iterate over
  196. * @param iterator function to call on each node
  197. * @param iterator_cls closure for iterator
  198. * @return GNUNET_YES to continue to iterate
  199. */
  200. static int
  201. node_iterator (const struct GNUNET_CONTAINER_Heap *heap,
  202. struct GNUNET_CONTAINER_HeapNode *node,
  203. GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
  204. {
  205. if (node == NULL)
  206. return GNUNET_YES;
  207. if (GNUNET_YES !=
  208. node_iterator (heap, node->left_child, iterator, iterator_cls))
  209. return GNUNET_NO;
  210. if (GNUNET_YES !=
  211. node_iterator (heap, node->right_child, iterator, iterator_cls))
  212. return GNUNET_NO;
  213. return iterator (iterator_cls, node, node->element, node->cost);
  214. }
  215. /**
  216. * Iterate over all entries in the heap.
  217. *
  218. * @param heap the heap
  219. * @param iterator function to call on each entry
  220. * @param iterator_cls closure for iterator
  221. */
  222. void
  223. GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap,
  224. GNUNET_CONTAINER_HeapIterator iterator,
  225. void *iterator_cls)
  226. {
  227. (void) node_iterator (heap, heap->root, iterator, iterator_cls);
  228. }
  229. /**
  230. * Perform a random walk of the tree. The walk is biased
  231. * towards elements closer to the root of the tree (since
  232. * each walk starts at the root and ends at a random leaf).
  233. * The heap internally tracks the current position of the
  234. * walk.
  235. *
  236. * @param heap heap to walk
  237. * @return data stored at the next random node in the walk;
  238. * NULL if the tree is empty.
  239. */
  240. void *
  241. GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap)
  242. {
  243. struct GNUNET_CONTAINER_HeapNode *pos;
  244. void *element;
  245. if (heap->root == NULL)
  246. return NULL;
  247. pos = heap->walk_pos;
  248. if (pos == NULL)
  249. pos = heap->root;
  250. element = pos->element;
  251. heap->walk_pos =
  252. (0 ==
  253. GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
  254. 2)) ? pos->right_child : pos->left_child;
  255. return element;
  256. }
  257. /**
  258. * Insert the given node 'node' into the subtree starting
  259. * at 'pos' (while keeping the tree somewhat balanced).
  260. *
  261. * @param heap heap to modify
  262. * @param pos existing tree
  263. * @param node node to insert (which may be a subtree itself)
  264. */
  265. static void
  266. insert_node (struct GNUNET_CONTAINER_Heap *heap,
  267. struct GNUNET_CONTAINER_HeapNode *pos,
  268. struct GNUNET_CONTAINER_HeapNode *node)
  269. {
  270. struct GNUNET_CONTAINER_HeapNode *parent;
  271. GNUNET_assert (node->parent == NULL);
  272. while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >=
  273. node->cost)
  274. : (pos->cost <= node->cost))
  275. {
  276. /* node is descendent of pos */
  277. pos->tree_size += (1 + node->tree_size);
  278. if (pos->left_child == NULL)
  279. {
  280. pos->left_child = node;
  281. node->parent = pos;
  282. return;
  283. }
  284. if (pos->right_child == NULL)
  285. {
  286. pos->right_child = node;
  287. node->parent = pos;
  288. return;
  289. }
  290. /* keep it balanced by descending into smaller subtree */
  291. if (pos->left_child->tree_size < pos->right_child->tree_size)
  292. pos = pos->left_child;
  293. else
  294. pos = pos->right_child;
  295. }
  296. /* make 'node' parent of 'pos' */
  297. parent = pos->parent;
  298. pos->parent = NULL;
  299. node->parent = parent;
  300. if (NULL == parent)
  301. {
  302. heap->root = node;
  303. }
  304. else
  305. {
  306. if (parent->left_child == pos)
  307. parent->left_child = node;
  308. else
  309. parent->right_child = node;
  310. }
  311. /* insert 'pos' below 'node' */
  312. insert_node (heap, node, pos);
  313. CHECK (pos);
  314. }
  315. /**
  316. * Inserts a new element into the heap.
  317. *
  318. * @param heap heap to modify
  319. * @param element element to insert
  320. * @param cost cost for the element
  321. * @return node for the new element
  322. */
  323. struct GNUNET_CONTAINER_HeapNode *
  324. GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element,
  325. GNUNET_CONTAINER_HeapCostType cost)
  326. {
  327. struct GNUNET_CONTAINER_HeapNode *node;
  328. node = GNUNET_new (struct GNUNET_CONTAINER_HeapNode);
  329. node->heap = heap;
  330. node->element = element;
  331. node->cost = cost;
  332. heap->size++;
  333. if (NULL == heap->root)
  334. heap->root = node;
  335. else
  336. insert_node (heap, heap->root, node);
  337. GNUNET_assert (heap->size == heap->root->tree_size + 1);
  338. CHECK (heap->root);
  339. return node;
  340. }
  341. /**
  342. * Remove root of the heap.
  343. *
  344. * @param heap heap to modify
  345. * @return element data stored at the root node, NULL if heap is empty
  346. */
  347. void *
  348. GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap)
  349. {
  350. void *ret;
  351. struct GNUNET_CONTAINER_HeapNode *root;
  352. if (NULL == (root = heap->root))
  353. return NULL;
  354. heap->size--;
  355. ret = root->element;
  356. if (root->left_child == NULL)
  357. {
  358. heap->root = root->right_child;
  359. if (root->right_child != NULL)
  360. root->right_child->parent = NULL;
  361. }
  362. else if (root->right_child == NULL)
  363. {
  364. heap->root = root->left_child;
  365. root->left_child->parent = NULL;
  366. }
  367. else
  368. {
  369. root->left_child->parent = NULL;
  370. root->right_child->parent = NULL;
  371. heap->root = root->left_child;
  372. insert_node (heap, heap->root, root->right_child);
  373. }
  374. if (heap->walk_pos == root)
  375. heap->walk_pos = heap->root;
  376. GNUNET_free (root);
  377. #if EXTRA_CHECKS
  378. GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
  379. (heap->size == heap->root->tree_size + 1));
  380. CHECK (heap->root);
  381. #endif
  382. return ret;
  383. }
  384. /**
  385. * Remove the given node 'node' from the tree and update
  386. * the 'tree_size' fields accordingly. Preserves the
  387. * children of 'node' and does NOT change the overall
  388. * 'size' field of the tree.
  389. */
  390. static void
  391. remove_node (struct GNUNET_CONTAINER_HeapNode *node)
  392. {
  393. struct GNUNET_CONTAINER_HeapNode *ancestor;
  394. struct GNUNET_CONTAINER_Heap *heap = node->heap;
  395. /* update 'size' of the ancestors */
  396. ancestor = node;
  397. while (NULL != (ancestor = ancestor->parent))
  398. ancestor->tree_size--;
  399. /* update 'size' of node itself */
  400. if (node->left_child != NULL)
  401. node->tree_size -= (1 + node->left_child->tree_size);
  402. if (node->right_child != NULL)
  403. node->tree_size -= (1 + node->right_child->tree_size);
  404. /* unlink 'node' itself and insert children in its place */
  405. if (node->parent == NULL)
  406. {
  407. if (node->left_child != NULL)
  408. {
  409. heap->root = node->left_child;
  410. node->left_child->parent = NULL;
  411. if (node->right_child != NULL)
  412. {
  413. node->right_child->parent = NULL;
  414. insert_node (heap, heap->root, node->right_child);
  415. }
  416. }
  417. else
  418. {
  419. heap->root = node->right_child;
  420. if (node->right_child != NULL)
  421. node->right_child->parent = NULL;
  422. }
  423. }
  424. else
  425. {
  426. if (node->parent->left_child == node)
  427. node->parent->left_child = NULL;
  428. else
  429. node->parent->right_child = NULL;
  430. if (node->left_child != NULL)
  431. {
  432. node->left_child->parent = NULL;
  433. node->parent->tree_size -= (1 + node->left_child->tree_size);
  434. insert_node (heap, node->parent, node->left_child);
  435. }
  436. if (node->right_child != NULL)
  437. {
  438. node->right_child->parent = NULL;
  439. node->parent->tree_size -= (1 + node->right_child->tree_size);
  440. insert_node (heap, node->parent, node->right_child);
  441. }
  442. }
  443. node->parent = NULL;
  444. node->left_child = NULL;
  445. node->right_child = NULL;
  446. GNUNET_assert (node->tree_size == 0);
  447. CHECK (heap->root);
  448. }
  449. /**
  450. * Removes a node from the heap.
  451. *
  452. * @param node node to remove
  453. * @return element data stored at the node
  454. */
  455. void *
  456. GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node)
  457. {
  458. void *ret;
  459. struct GNUNET_CONTAINER_Heap *heap;
  460. heap = node->heap;
  461. CHECK (heap->root);
  462. if (heap->walk_pos == node)
  463. (void) GNUNET_CONTAINER_heap_walk_get_next (heap);
  464. remove_node (node);
  465. heap->size--;
  466. ret = node->element;
  467. if (heap->walk_pos == node)
  468. heap->walk_pos = NULL;
  469. GNUNET_free (node);
  470. #if EXTRA_CHECKS
  471. CHECK (heap->root);
  472. GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
  473. (heap->size == heap->root->tree_size + 1));
  474. #endif
  475. return ret;
  476. }
  477. /**
  478. * Updates the cost of any node in the tree
  479. *
  480. * @param node node for which the cost is to be changed
  481. * @param new_cost new cost for the node
  482. */
  483. void
  484. GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_HeapNode *node,
  485. GNUNET_CONTAINER_HeapCostType new_cost)
  486. {
  487. struct GNUNET_CONTAINER_Heap *heap = node->heap;
  488. remove_node (node);
  489. node->cost = new_cost;
  490. if (NULL == heap->root)
  491. heap->root = node;
  492. else
  493. insert_node (heap,
  494. heap->root,
  495. node);
  496. }
  497. /* end of heap.c */