Logo AND Algorithmique Numérique Distribuée

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