Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
96da93ec1790deff20cffefe0203c2242cfb4e90
[simgrid.git] / src / xbt / heap.c
1 /* a generic and efficient heap                                             */
2
3 /* Copyright (c) 2004-2005, 2007-2015. The SimGrid Team.
4  * All rights reserved.                                                     */
5
6 /* This program is free software; you can redistribute it and/or modify it
7  * under the terms of the license (GNU LGPL) which comes with this package. */
8
9 #include "xbt/sysdep.h"
10 #include "xbt/log.h"
11 #include "heap_private.h"
12
13 #include <stdio.h>
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_heap, xbt, "Heap");
15
16 static void xbt_heap_max_heapify(xbt_heap_t H, int i);
17 static void xbt_heap_increase_key(xbt_heap_t H, int i);
18
19 /** @addtogroup XBT_heap
20  *  \brief This section describes the API to generic heap with O(log(n)) access.
21  */
22
23 /**
24  * @brief Creates a new heap.
25  * \param init_size initial size of the heap
26  * \param free_func function to call on each element when you want to free the whole heap (or NULL if nothing to do).
27  *
28  * Creates a new heap.
29  */
30 inline xbt_heap_t xbt_heap_new(int init_size, void_f_pvoid_t const free_func)
31 {
32   xbt_heap_t H = xbt_new0(struct xbt_heap, 1);
33   H->size = init_size;
34   H->count = 0;
35   H->items = (xbt_heap_item_t) xbt_new0(struct xbt_heap_item, init_size);
36   H->free = free_func;
37   return H;
38 }
39
40 /**
41  * @brief Set the update callback function.
42  * @param H the heap we're working on
43  * \param update_callback function to call on each element to update its index when needed.
44  */
45 inline void xbt_heap_set_update_callback(xbt_heap_t H, void (*update_callback) (void*, int))
46 {
47   H->update_callback = update_callback;
48 }
49
50 /**
51  * @brief kilkil a heap and its content
52  * @param H poor victim
53  */
54 void xbt_heap_free(xbt_heap_t H)
55 {
56   int i;
57   if (H->free)
58     for (i = 0; i < H->count; i++)
59       H->free(H->items[i].content);
60   free(H->items);
61   free(H);
62   return;
63 }
64
65 /**
66  * @brief returns the number of elements in the heap
67  * @param H the heap we're working on
68  * @return the number of elements in the heap
69  */
70 inline int xbt_heap_size(xbt_heap_t H)
71 {
72   return (H->count);
73 }
74
75 /**
76  * @brief Add an element into the heap.
77  * \param H the heap we're working on
78  * \param content the object you want to add to the heap
79  * \param key the key associated to this object
80  *
81  * The element with the smallest key is automatically moved at the top of the heap.
82  */
83 void xbt_heap_push(xbt_heap_t H, void *content, double key)
84 {
85   int count = ++(H->count);
86
87   int size = H->size;
88   xbt_heap_item_t item;
89
90   if (count > size) {
91     H->size = (size << 1) + 1;
92     H->items = (void *) xbt_realloc(H->items, (H->size) * sizeof(struct xbt_heap_item));
93   }
94
95   item = &(H->items[count - 1]);
96   item->key = key;
97   item->content = content;
98   xbt_heap_increase_key(H, count - 1);
99   XBT_DEBUG("Heap has now %d elements and max elem is %g",xbt_heap_size(H),xbt_heap_maxkey(H));
100   return;
101 }
102
103 /**
104  * @brief Extracts from the heap and returns the element with the smallest key.
105  * \param H the heap we're working on
106  * \return the element with the smallest key
107  *
108  * Extracts from the heap and returns the element with the smallest key. The element with the next smallest key is
109  * automatically moved at the top of the heap.
110  */
111 void *xbt_heap_pop(xbt_heap_t H)
112 {
113   xbt_heap_item_t items = H->items;
114   int size = H->size;
115   void *max;
116
117   if (H->count == 0)
118     return NULL;
119
120   XBT_DEBUG("Heap has %d elements before extraction and max elem was %g",xbt_heap_size(H),xbt_heap_maxkey(H));
121
122   max = CONTENT(H, 0);
123
124   items[0] = items[(H->count) - 1];
125   (H->count)--;
126   xbt_heap_max_heapify(H,0);
127   if (H->count < size >> 2 && size > 16) {
128     size = (size >> 1) + 1;
129     H->items = (void *) xbt_realloc(items, size * sizeof(struct xbt_heap_item));
130     H->size = size;
131   }
132
133   if (H->update_callback)
134     H->update_callback(max, -1);
135   return max;
136 }
137
138 /**
139  * @brief Extracts from the heap and returns the element at position i.
140  * \param H the heap we're working on
141  * \param i  element position
142  * \return the element at position i if ok, NULL otherwise
143  *
144  * Extracts from the heap and returns the element at position i. The heap is automatically reordered.
145  */
146 void *xbt_heap_remove(xbt_heap_t H, int i)
147 {
148   XBT_DEBUG("Heap has %d elements: extracting element %d",xbt_heap_size(H),i);
149
150   if ((i < 0) || (i > H->count - 1))
151     return NULL;
152   /* put element i at head */
153   if (i > 0) {
154     KEY(H, i) = MIN_KEY_VALUE;
155     xbt_heap_increase_key(H, i);
156   }
157
158   return xbt_heap_pop(H);
159 }
160 /** @brief Remove an arbitrary element from the heap
161  *  @param H the heap we're working on
162  *  @param content the object you want to add to the heap
163  *  @param key the key associated to this object
164  */
165 void xbt_heap_rm_elm(xbt_heap_t H, void *content, double key) {
166   int i=0;
167   while (i < H->count && (KEY(H, i) != key || CONTENT(H, i) != content))
168     i++;
169   if (i == H->count)
170     return;
171   xbt_heap_remove(H,i);
172 }
173
174 /**
175  * @brief Updates an element of the heap with a new value.
176  * \param H the heap we're working on
177  * \param i  element position
178  * \param key new value for the element
179  *
180  * Updates an element of the heap with a new value.
181  */
182 void xbt_heap_update(xbt_heap_t H, int i, double key)
183 {
184   XBT_DEBUG("Heap has %d elements: updating element %d : was %1.12f to %1.12f ",xbt_heap_size(H),i,KEY(H, i), key);
185
186   if ((i < 0) || (i > H->count - 1) || key == KEY(H, i))
187     return ;
188
189   if(key< KEY(H, i)){
190     KEY(H, i)=key;
191     xbt_heap_increase_key(H, i);
192   }else{
193     KEY(H, i)=key;
194     xbt_heap_max_heapify(H,i);
195   }
196 }
197
198 /**
199  * @brief returns the smallest key in the heap (heap unchanged)
200  * \param H the heap we're working on
201  *
202  * \return the smallest key in the heap without modifying the heap.
203  */
204 inline double xbt_heap_maxkey(xbt_heap_t H)
205 {
206   xbt_assert(H->count != 0, "Empty heap");
207   return KEY(H, 0);
208 }
209
210 /**
211  * @brief returns the value associated to the smallest key in the heap (heap unchanged)
212  * \param H the heap we're working on
213  *
214  * \return the value associated to the smallest key in the heap
215  * without modifying the heap.
216  */
217 void *xbt_heap_maxcontent(xbt_heap_t H)
218 {
219   xbt_assert(H->count != 0, "Empty heap");
220   return CONTENT(H, 0);
221 }
222
223 /* <<<< private >>>>
224  * \param H the heap we're working on
225  *
226  * Restores the heap property once an element has been deleted.
227  */
228 static void xbt_heap_max_heapify(xbt_heap_t H, int index)
229 {
230   int i = index;
231   int count = H->count;
232   xbt_heap_item_t items = H->items;
233
234   while (1) {
235     int greatest = i;
236     int l = LEFT(i);
237     int r = l + 1;
238     if (l < count && items[l].key < items[i].key)
239       greatest = l;
240     if (r < count && items[r].key < items[greatest].key)
241       greatest = r;
242     if (greatest != i) {
243       struct xbt_heap_item tmp = items[i];
244       items[i] = items[greatest];
245       items[greatest] = tmp;
246       if (H->update_callback)
247         H->update_callback(items[i].content, i);
248       i = greatest;
249     } else {
250       if (H->update_callback)
251         H->update_callback(items[i].content, i);
252       return;
253     }
254   }
255 }
256
257 /* <<<< private >>>>
258  * \param H the heap we're working on
259  * \param i an item position in the heap
260  *
261  * Moves up an item at position i to its correct position. Works only when called from xbt_heap_push.
262  * Do not use otherwise.
263  */
264 static void xbt_heap_increase_key(xbt_heap_t H, int i)
265 {
266   xbt_heap_item_t items = H->items;
267   int p = PARENT(i);
268   while (i > 0 && items[p].key > items[i].key) {
269     struct xbt_heap_item tmp = items[i];
270     items[i] = items[p];
271     items[p] = tmp;
272     if (H->update_callback)
273       H->update_callback(items[i].content, i);
274     i = p;
275     p = PARENT(i);
276   }
277   if (H->update_callback)
278     H->update_callback(items[i].content, i);
279   return;
280 }