LALPulsar  6.1.0.1-89842e6
HeapToplist.c
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2007 Bernd Machenschalk
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with with program; see the file COPYING. If not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 */
19 
20 /* This module keeps a "toplist", i.e. a list of the top n elements (accoding to an externally
21  supplied comparison function) in a standard heap structure.
22 
23  A Heap is a partially sorted structure that is typically represented as a (binary) tree.
24  A tree is a heap if for all nodes the value of the node is smaller than that of all its
25  successors according to a given comparison function.
26  Footnote: in most other implementation of a heap the order is different from here, i.e.
27  replace "smaller" with "greater" in the above.
28 
29  The nice thing about such a heap for our application (and others) is that this heap property
30  doesn't imply any special relation between two nodes in different branches of the tree, so no
31  effort is necessary to keep such a relation. This allows to perform all operations on the heap
32  (including removal and insertion of elements) with O(log n), i.e. at most the depth of the tree.
33 
34  Here the tree is a binary tree and stored in an array where the successors succ(n) of a node
35  with index n have indices 2*n+1 and 2*n+2:
36 
37  0
38  1 2
39  3 4 5 6
40  7 8 9 10 11 12 13 14
41 
42  There's nothing special about that - look for "Heapsort" in the WWW or an algorithms book.
43 
44  Bernd Machenschalk
45 */
46 
47 
48 #include <stdlib.h>
49 #include <string.h>
50 #include "HeapToplist.h"
51 
52 /* this function gets a "partial heap", i.e. a heap where only the top
53  element (potentially) violates the heap property. It "bubbles
54  down" this element so that the heap property is restored */
55 static void down_heap( toplist_t *list )
56 {
57  size_t node = 0;
58  size_t succ;
59  char *exch;
60  while ( ( succ = node + node + 1 ) < list->elems ) {
61  if ( succ + 1 < list->elems )
62  if ( ( list->smaller )( ( list->heap )[succ + 1], ( list->heap )[succ] ) > 0 ) {
63  succ++;
64  }
65  if ( ( list->smaller )( ( list->heap )[succ], ( list->heap )[node] ) > 0 ) {
66  exch = ( list->heap )[node];
67  ( list->heap )[node] = ( list->heap )[succ];
68  ( list->heap )[succ] = exch;
69  node = succ;
70  } else {
71  break;
72  }
73  }
74 }
75 
76 
77 /* this function gets a "partial heap", i.e. a heap where only an element on
78  the lowest level (potentially) violates the heap property. "node" is the
79  index of this element. The function "bubbles up" this element so that the
80  heap property is restored */
81 static void up_heap( toplist_t *list, size_t node )
82 {
83  size_t pred;
84  char *exch;
85  while ( node > 0 ) {
86  pred = ( node - 1 ) / 2;
87  if ( ( list->smaller )( ( list->heap )[node], ( list->heap )[pred] ) > 0 ) {
88  exch = ( list->heap )[node];
89  ( list->heap )[node] = ( list->heap )[pred];
90  ( list->heap )[pred] = exch;
91  node = pred;
92  } else {
93  break;
94  }
95  }
96 }
97 
98 
99 /* creates a toplist with length elements,
100  returns -1 on error (out of memory), else 0 */
102  size_t length,
103  size_t size,
104  int ( *smaller )( const void *, const void * ) )
105 {
106  toplist_t *listp;
107 
108  if ( !( listp = malloc( sizeof( toplist_t ) ) ) ) {
109  return ( -1 );
110  }
111  if ( !( listp->data = malloc( size * length ) ) ) {
112  free( listp );
113  return ( -1 );
114  }
115  if ( !( listp->heap = malloc( sizeof( char * ) * length ) ) ) {
116  free( listp->data );
117  free( listp );
118  return ( -1 );
119  }
120 
121  listp->length = length;
122  listp->elems = 0;
123  listp->size = size;
124  listp->smaller = smaller;
125 
126  *list = listp;
127  return ( 0 );
128 }
129 
130 
131 /* clears an existing toplist of all elements inserted so far */
133 {
134  list->elems = 0;
135 }
136 
137 
138 /* frees the space occupied by the toplist */
139 void free_toplist( toplist_t **list )
140 {
141  free( ( *list )->heap );
142  free( ( *list )->data );
143  free( *list );
144 }
145 
146 
147 /* Inserts an element in to the toplist either if there is space left
148  or the element is larger than the smallest element in the toplist.
149  In the latter case, remove the smallest element from the toplist.
150  Returns 1 if the element was actually inserted, 0 if not. */
151 int insert_into_toplist( toplist_t *list, void *element )
152 {
153 
154  /* if there is room left, add it at the end (and update the heap) */
155  if ( list->elems < list->length ) {
156  list->heap[list->elems] = list->data + list->elems * list->size;
157  memcpy( list->heap[list->elems], element, list->size );
158  list->elems++;
159  up_heap( list, list->elems - 1 );
160  return ( 1 );
161 
162  /* if it is smaller than the smallest element, simply drop it.
163  if it is bigger, replace the smallest element (root of the heap)
164  and update the heap */
165  } else if ( ( list->smaller )( element, ( list->heap )[0] ) < 0 ) {
166  memcpy( list->heap[0], element, list->size );
167  down_heap( list );
168  return ( 1 );
169 
170  } else {
171  return ( 0 );
172  }
173 }
174 
175 
176 /* apply the function "handle" to all elements of the list in the current order */
177 void go_through_toplist( toplist_t *list, void ( *handle )( void * ) )
178 {
179  size_t i;
180  for ( i = 0; i < list->elems; i++ ) {
181  handle( list->heap[i] );
182  }
183 }
184 
185 void *toplist_elem( toplist_t *list, size_t ind )
186 {
187  if ( list == NULL ) {
188  return ( NULL );
189  }
190  if ( ind >= list->elems ) {
191  return ( NULL );
192  }
193  return ( list->heap[ind] );
194 }
195 
196 int compare_toplists( toplist_t *list1, toplist_t *list2 )
197 {
198  size_t i = 0;
199  int res = 0;
200  if ( ( list1 == NULL ) || ( list2 == NULL ) ) {
201  return ( 2 );
202  }
203  if ( ( list1->smaller != list2->smaller ) ||
204  ( list1->size != list2->size ) ) {
205  return ( 2 );
206  }
207  while ( ( i < list1->elems ) &&
208  ( i < list2->elems ) &&
209  ( res == 0 ) ) {
210  res = list1->smaller( toplist_elem( list1, i ), toplist_elem( list2, i ) );
211  i++;
212  }
213  if ( res == 0 ) {
214  if ( list1->elems < list2->elems ) {
215  return ( 1 );
216  } else if ( list1->elems > list2->elems ) {
217  return ( -1 );
218  }
219  }
220  return ( res );
221 }
222 
223 
224 /* using qsort requires some "global" help */
225 
226 /* global function pointer for qsort */
227 static int ( *_qsort_compare1 )( const void *, const void * );
228 /* wrapper function for qsort */
229 static int _qsort_compare2( const void *a, const void *b )
230 {
231  return ( _qsort_compare1( *( void *const * )a, *( void *const * )b ) );
232 }
233 /* inverse wrapper */
234 static int _qsort_compare3( const void *b, const void *a )
235 {
236  return ( _qsort_compare1( *( void *const * )a, *( void *const * )b ) );
237 }
238 
239 /* sorts the toplist with an arbitrary sorting function
240  (potentially) destroying the heap property */
241 void qsort_toplist( toplist_t *list, int ( *compare )( const void *, const void * ) )
242 {
243  /* point the global function pointer to compare, then call qsort with the wrapper */
244  _qsort_compare1 = compare;
245  qsort( list->heap, list->elems, sizeof( char * ), _qsort_compare2 );
246 }
247 
248 /* qsort function that gives the reverse ordering of the previous */
249 void qsort_toplist_r( toplist_t *list, int ( *compare )( const void *, const void * ) )
250 {
251  /* point the global function pointer to compare, then call qsort with the wrapper */
252  _qsort_compare1 = compare;
253  qsort( list->heap, list->elems, sizeof( char * ), _qsort_compare3 );
254 }
static int _qsort_compare2(const void *a, const void *b)
Definition: HeapToplist.c:229
int create_toplist(toplist_t **list, size_t length, size_t size, int(*smaller)(const void *, const void *))
Definition: HeapToplist.c:101
void free_toplist(toplist_t **list)
Definition: HeapToplist.c:139
void qsort_toplist(toplist_t *list, int(*compare)(const void *, const void *))
Definition: HeapToplist.c:241
static void down_heap(toplist_t *list)
Definition: HeapToplist.c:55
void * toplist_elem(toplist_t *list, size_t ind)
Definition: HeapToplist.c:185
static int(* _qsort_compare1)(const void *, const void *)
Definition: HeapToplist.c:227
void qsort_toplist_r(toplist_t *list, int(*compare)(const void *, const void *))
Definition: HeapToplist.c:249
int insert_into_toplist(toplist_t *list, void *element)
Definition: HeapToplist.c:151
static void up_heap(toplist_t *list, size_t node)
Definition: HeapToplist.c:81
int compare_toplists(toplist_t *list1, toplist_t *list2)
Definition: HeapToplist.c:196
void go_through_toplist(toplist_t *list, void(*handle)(void *))
Definition: HeapToplist.c:177
void clear_toplist(toplist_t *list)
Definition: HeapToplist.c:132
static int _qsort_compare3(const void *b, const void *a)
Definition: HeapToplist.c:234
static int smaller(const void *a, const void *b)
static const INT4 a
size
char ** heap
Definition: HeapToplist.h:40
size_t length
Definition: HeapToplist.h:36
size_t elems
Definition: HeapToplist.h:37
int(* smaller)(const void *, const void *)
Definition: HeapToplist.h:41
size_t size
Definition: HeapToplist.h:38
char * data
Definition: HeapToplist.h:39