Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

skiplist.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 McConnell Brain Imaging Centre, 00005 Montreal Neurological Institute, McGill University. 00006 Permission to use, copy, modify, and distribute this 00007 software and its documentation for any purpose and without 00008 fee is hereby granted, provided that the above copyright 00009 notice appear in all copies. The author and McGill University 00010 make no representations about the suitability of this 00011 software for any purpose. It is provided "as is" without 00012 express or implied warranty. 00013 ---------------------------------------------------------------------------- */ 00014 00015 #include <volume_io/internal_volume_io.h> 00016 #include <bicpl/data_structures.h> 00017 #include <bicpl/prog_utils.h> 00018 00019 #ifndef lint 00020 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Data_structures/skiplist.c,v 1.12 2000/02/06 15:30:12 stever Exp $"; 00021 #endif 00022 00023 private int get_random_level( void ); 00024 00025 /* ----------------------------- MNI Header ----------------------------------- 00026 @NAME : skip_list.c 00027 @INPUT : 00028 @OUTPUT : 00029 @RETURNS : 00030 @DESCRIPTION: Routines for managing an ordered list, using the skiplist 00031 : technique. 00032 @METHOD : 00033 @GLOBALS : 00034 @CALLS : 00035 @CREATED : David MacDonald 00036 @MODIFIED : 00037 ---------------------------------------------------------------------------- */ 00038 00039 #define MAX_SKIP_LEVELS 50 00040 #define SKIP_P 0.5 00041 00042 typedef struct 00043 { 00044 skip_struct *update[MAX_SKIP_LEVELS]; 00045 } update_struct; 00046 00047 #define ALLOC_SKIP_STRUCT( ptr, n_level ) \ 00048 ALLOC_VAR_SIZED_STRUCT( ptr, skip_struct *, n_level ) 00049 00050 /* ----------------------------- MNI Header ----------------------------------- 00051 @NAME : initialize_skiplist 00052 @INPUT : skiplist 00053 @OUTPUT : 00054 @RETURNS : 00055 @DESCRIPTION: Initializes the skiplist to empty. 00056 @METHOD : 00057 @GLOBALS : 00058 @CALLS : 00059 @CREATED : David MacDonald 00060 @MODIFIED : 00061 ---------------------------------------------------------------------------- */ 00062 00063 public void initialize_skiplist( 00064 skiplist_struct *skiplist ) 00065 { 00066 int i; 00067 00068 skiplist->level = 1; 00069 00070 ALLOC_SKIP_STRUCT( skiplist->header, MAX_SKIP_LEVELS ); 00071 00072 for_less( i, 0, MAX_SKIP_LEVELS ) 00073 skiplist->header->forward[i] = NULL; 00074 } 00075 00076 /* ----------------------------- MNI Header ----------------------------------- 00077 @NAME : find_data_position 00078 @INPUT : skiplist 00079 : key 00080 @OUTPUT : update 00081 @RETURNS : TRUE if found 00082 @DESCRIPTION: Searches the skiplist for the given key, and sets the update 00083 : struct so that it can provide an insert. 00084 @METHOD : 00085 @GLOBALS : 00086 @CALLS : 00087 @CREATED : David MacDonald 00088 @MODIFIED : 00089 ---------------------------------------------------------------------------- */ 00090 00091 private BOOLEAN find_data_position( 00092 skiplist_struct *skiplist, 00093 float key, 00094 update_struct *update ) 00095 { 00096 int i; 00097 skip_struct *x; 00098 BOOLEAN found; 00099 00100 x = skiplist->header; 00101 00102 for( i = skiplist->level-1; i >= 0; --i ) 00103 { 00104 while( x->forward[i] != NULL && x->forward[i]->key < key ) 00105 x = x->forward[i]; 00106 00107 update->update[i] = x; 00108 } 00109 00110 x = update->update[0]->forward[0]; 00111 00112 found = x != NULL && x->key == key; 00113 00114 return( found ); 00115 } 00116 00117 /* ----------------------------- MNI Header ----------------------------------- 00118 @NAME : insert_data_in_skiplist 00119 @INPUT : skiplist 00120 : update - the set of pointers indicating where to insert 00121 : key - search key 00122 : data_ptr - the data to insert 00123 @OUTPUT : 00124 @RETURNS : 00125 @DESCRIPTION: Inserts the data ptr in the skiplist. 00126 @METHOD : 00127 @GLOBALS : 00128 @CALLS : 00129 @CREATED : David MacDonald 00130 @MODIFIED : 00131 ---------------------------------------------------------------------------- */ 00132 00133 private void insert_data_in_skiplist( 00134 skiplist_struct *skiplist, 00135 update_struct *update, 00136 float key, 00137 void *data_ptr ) 00138 { 00139 int i, new_level; 00140 skip_struct *x; 00141 #ifdef DEBUG 00142 int prev_size = -1; 00143 void test_skiplist_integrity(); 00144 #endif 00145 00146 new_level = get_random_level(); 00147 00148 if( new_level > skiplist->level ) 00149 { 00150 for( i = skiplist->level; i < new_level; ++i ) 00151 update->update[i] = skiplist->header; 00152 00153 #ifdef DEBUG 00154 prev_size = skiplist->level; 00155 #endif 00156 skiplist->level = new_level; 00157 } 00158 00159 ALLOC_SKIP_STRUCT( x, new_level ); 00160 00161 x->data_ptr = data_ptr; 00162 x->key = key; 00163 00164 for( i = 0; i < new_level; ++i ) 00165 { 00166 x->forward[i] = update->update[i]->forward[i]; 00167 update->update[i]->forward[i] = x; 00168 } 00169 00170 #ifdef DEBUG 00171 test_skiplist_integrity( skiplist ); 00172 #endif 00173 } 00174 00175 /* ----------------------------- MNI Header ----------------------------------- 00176 @NAME : delete_entry_from_skiplist 00177 @INPUT : skiplist 00178 : update 00179 @OUTPUT : 00180 @RETURNS : TRUE if it existed 00181 @DESCRIPTION: Deletes the entry in the skip list pointed to by update. 00182 @METHOD : 00183 @GLOBALS : 00184 @CALLS : 00185 @CREATED : David MacDonald 00186 @MODIFIED : 00187 ---------------------------------------------------------------------------- */ 00188 00189 private void delete_entry_from_skiplist( 00190 skiplist_struct *skiplist, 00191 update_struct *update ) 00192 { 00193 int i; 00194 skip_struct *x; 00195 00196 x = update->update[0]->forward[0]; 00197 00198 for( i = 0; i < skiplist->level; ++i ) 00199 { 00200 if( update->update[i]->forward[i] != x ) 00201 break; 00202 update->update[i]->forward[i] = x->forward[i]; 00203 } 00204 00205 FREE( x ); 00206 00207 while( skiplist->level > 1 && 00208 skiplist->header->forward[skiplist->level-1] == NULL ) 00209 { 00210 --skiplist->level; 00211 } 00212 } 00213 00214 /* ----------------------------- MNI Header ----------------------------------- 00215 @NAME : get_random_level 00216 @INPUT : 00217 @OUTPUT : 00218 @RETURNS : a random level between 1 and MAX_LEVELS 00219 @DESCRIPTION: Determines a random level with exponential probability of higher 00220 : levels. 00221 @METHOD : 00222 @GLOBALS : 00223 @CALLS : 00224 @CREATED : David MacDonald 00225 @MODIFIED : 00226 ---------------------------------------------------------------------------- */ 00227 00228 private int get_random_level( void ) 00229 { 00230 int level; 00231 00232 level = 1; 00233 00234 while( get_random_0_to_1() < SKIP_P && level < MAX_SKIP_LEVELS-1 ) 00235 ++level; 00236 00237 return( level ); 00238 } 00239 00240 /* ----------------------------- MNI Header ----------------------------------- 00241 @NAME : delete_skiplist 00242 @INPUT : skiplist 00243 @OUTPUT : 00244 @RETURNS : Status 00245 @DESCRIPTION: Deletes the memory associated with the skiplist. 00246 @METHOD : 00247 @GLOBALS : 00248 @CALLS : 00249 @CREATED : David MacDonald 00250 @MODIFIED : 00251 ---------------------------------------------------------------------------- */ 00252 00253 public void delete_skiplist( 00254 skiplist_struct *skiplist ) 00255 { 00256 skip_struct *ptr, *deleting; 00257 00258 ptr = skiplist->header; 00259 00260 while( ptr != NULL ) 00261 { 00262 deleting = ptr; 00263 ptr = ptr->forward[0]; 00264 FREE( deleting ); 00265 } 00266 } 00267 00268 /* ----------------------------- MNI Header ----------------------------------- 00269 @NAME : search_skiplist 00270 @INPUT : skiplist 00271 : key 00272 @OUTPUT : data_ptr 00273 @RETURNS : TRUE if found, FALSE if not 00274 @DESCRIPTION: Searches the skiplist for a data record that matches the 00275 : key. This function will find the matching record, 00276 : and return it. 00277 @METHOD : 00278 @GLOBALS : 00279 @CALLS : 00280 @CREATED : David MacDonald 00281 @MODIFIED : 00282 ---------------------------------------------------------------------------- */ 00283 00284 public BOOLEAN search_skiplist( 00285 skiplist_struct *skiplist, 00286 float key, 00287 void **data_ptr ) 00288 { 00289 BOOLEAN found; 00290 update_struct update_ptrs; 00291 00292 found = find_data_position( skiplist, key, &update_ptrs ); 00293 00294 if( found ) 00295 *data_ptr = update_ptrs.update[0]->forward[0]->data_ptr; 00296 00297 return( found ); 00298 } 00299 00300 public BOOLEAN search_skiplist_and_return_pointer( 00301 skiplist_struct *skiplist, 00302 float key, 00303 skip_struct **entry_ptr, 00304 void **data_ptr ) 00305 { 00306 BOOLEAN found; 00307 update_struct update_ptrs; 00308 00309 found = find_data_position( skiplist, key, &update_ptrs ); 00310 00311 if( found ) 00312 { 00313 *entry_ptr = update_ptrs.update[0]->forward[0]; 00314 *data_ptr = (*entry_ptr)->data_ptr; 00315 } 00316 00317 return( found ); 00318 } 00319 00320 /* ----------------------------- MNI Header ----------------------------------- 00321 @NAME : insert_in_skiplist 00322 @INPUT : skiplist 00323 : key 00324 : data_ptr 00325 @OUTPUT : 00326 @RETURNS : TRUE if inserted, FALSE if already there 00327 @DESCRIPTION: Inserts an entry into a skiplist. 00328 @METHOD : 00329 @GLOBALS : 00330 @CALLS : 00331 @CREATED : David MacDonald 00332 @MODIFIED : 00333 ---------------------------------------------------------------------------- */ 00334 00335 public BOOLEAN insert_in_skiplist( 00336 skiplist_struct *skiplist, 00337 float key, 00338 void *data_ptr ) 00339 { 00340 BOOLEAN already_there; 00341 update_struct update_ptrs; 00342 00343 already_there = find_data_position( skiplist, key, &update_ptrs ); 00344 00345 if( !already_there ) 00346 insert_data_in_skiplist( skiplist, &update_ptrs, key, data_ptr ); 00347 00348 return( !already_there ); 00349 } 00350 00351 /* ----------------------------- MNI Header ----------------------------------- 00352 @NAME : delete_from_skiplist 00353 @INPUT : skiplist 00354 : key 00355 @OUTPUT : data_ptr 00356 @RETURNS : TRUE if key was in list and successfully deleted. 00357 @DESCRIPTION: Deletes the entry for the given data_ptr from the skiplist, 00358 : passing back the pointer that was stored. 00359 @METHOD : 00360 @GLOBALS : 00361 @CALLS : 00362 @CREATED : David MacDonald 00363 @MODIFIED : 00364 ---------------------------------------------------------------------------- */ 00365 00366 public BOOLEAN delete_from_skiplist( 00367 skiplist_struct *skiplist, 00368 float key, 00369 void **data_ptr ) 00370 { 00371 BOOLEAN in_skiplist; 00372 update_struct update_ptrs; 00373 00374 in_skiplist = find_data_position( skiplist, key, &update_ptrs ); 00375 00376 if( in_skiplist ) 00377 { 00378 *data_ptr = update_ptrs.update[0]->forward[0]->data_ptr; 00379 00380 delete_entry_from_skiplist( skiplist, &update_ptrs ); 00381 } 00382 00383 return( in_skiplist ); 00384 } 00385 00386 /* ----------------------------- MNI Header ----------------------------------- 00387 @NAME : get_first_skiplist_entry 00388 @INPUT : skiplist 00389 @OUTPUT : entry_ptr 00390 : key 00391 : data_ptr 00392 @RETURNS : True if an entry exists in the skiplist. 00393 @DESCRIPTION: Initializes the entry_ptr to point to the first entry, 00394 : and the key and data_ptr to the data for the first entry. 00395 : This function is used to traverse the list sequentially. 00396 @METHOD : 00397 @GLOBALS : 00398 @CALLS : 00399 @CREATED : David MacDonald 00400 @MODIFIED : 00401 ---------------------------------------------------------------------------- */ 00402 00403 public BOOLEAN get_first_skiplist_entry( 00404 skiplist_struct *skiplist, 00405 skip_struct **entry_ptr, 00406 float *key, 00407 void **data_ptr ) 00408 { 00409 *entry_ptr = skiplist->header->forward[0]; 00410 00411 if( *entry_ptr != NULL ) 00412 { 00413 *key = (*entry_ptr)->key; 00414 *data_ptr = (*entry_ptr)->data_ptr; 00415 } 00416 00417 return( *entry_ptr != NULL ); 00418 } 00419 00420 /* ----------------------------- MNI Header ----------------------------------- 00421 @NAME : get_next_skiplist_entry 00422 @INPUT : entry_ptr 00423 @OUTPUT : key 00424 : data_ptr 00425 @RETURNS : True if another entry is found. 00426 @DESCRIPTION: Advances the entry_ptr to the next entry, and copies that entry's 00427 : key and data ptr to the function arguments. 00428 @METHOD : 00429 @GLOBALS : 00430 @CALLS : 00431 @CREATED : David MacDonald 00432 @MODIFIED : 00433 ---------------------------------------------------------------------------- */ 00434 00435 public BOOLEAN get_next_skiplist_entry( 00436 skip_struct **entry_ptr, 00437 float *key, 00438 void **data_ptr ) 00439 { 00440 *entry_ptr = (*entry_ptr)->forward[0]; 00441 00442 if( *entry_ptr != NULL ) 00443 { 00444 *key = (*entry_ptr)->key; 00445 *data_ptr = (*entry_ptr)->data_ptr; 00446 } 00447 00448 return( *entry_ptr != NULL ); 00449 } 00450 00451 #ifdef DEBUG 00452 00453 private BOOLEAN test_skiplist_integrity( 00454 skiplist_struct *skiplist ) 00455 { 00456 int i; 00457 update_struct update; 00458 BOOLEAN okay; 00459 00460 for_less( i, 0, skiplist->level ) 00461 update.update[i] = skiplist->header->forward[i]; 00462 00463 while( update.update[0] != NULL ) 00464 { 00465 i = 1; 00466 while( i < skiplist->level && update.update[0] == update.update[i] ) 00467 { 00468 update.update[i] = update.update[i]->forward[i]; 00469 ++i; 00470 } 00471 update.update[0] = update.update[0]->forward[0]; 00472 } 00473 00474 okay = TRUE; 00475 00476 for_less( i, 0, skiplist->level ) 00477 if( update.update[i] != NULL ) 00478 okay = FALSE; 00479 00480 if( !okay ) 00481 handle_internal_error( "Skiplist integrity" ); 00482 00483 return( okay ); 00484 } 00485 #endif

Generated on Wed Jul 28 09:10:58 2004 for BICPL by doxygen 1.3.7