/* * dfib.c * * This file is part of SOAPdenovo. * */ /*- * Copyright 1997-2003 John-Mark Gurney. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: dfib.c,v 1.12 2007/10/19 13:09:26 zerbino Exp $ * */ #include #include #include "dfib.h" #include "dfibpriv.h" #include "extfunc2.h" #define HEAPBLOCKSIZE 1000 static int dfh_comparedata ( DFibHeap *h, Time key, unsigned int data, DFibHeapNode *b ); static DFibHeapNode *allocateDFibHeapNode ( DFibHeap *heap ) { return ( DFibHeapNode * ) getItem ( heap->nodeMemory ); }; static void deallocateDFibHeapNode ( DFibHeapNode *a, DFibHeap *heap ) { returnItem ( heap->nodeMemory, a ); } IDnum dfibheap_getSize ( DFibHeap *heap ) { return heap->dfh_n; } #define swap(type, a, b) \ do { \ type c; \ c = a; \ a = b; \ b = c; \ } while (0) \ #define INT_BITS (sizeof(IDnum) * 8) static inline IDnum ceillog2 ( IDnum a ) { IDnum oa; IDnum i; IDnum b; IDnum cons; oa = a; b = INT_BITS / 2; i = 0; while ( b ) { i = ( i << 1 ); cons = ( ( IDnum ) 1 ) << b; if ( a >= cons ) { a /= cons; i = i | 1; } else { a &= cons - 1; } b /= 2; } if ( ( ( ( IDnum ) 1 << i ) ) == oa ) { return i; } else { return i + 1; } } /* * Public Heap Functions */ DFibHeap *dfh_makekeyheap () { DFibHeap *n; if ( ( n = malloc ( sizeof * n ) ) == NULL ) { return NULL; } n->nodeMemory = createMem_manager ( HEAPBLOCKSIZE, sizeof ( DFibHeapNode ) ); n->dfh_n = 0; n->dfh_Dl = -1; n->dfh_cons = NULL; n->dfh_min = NULL; n->dfh_root = NULL; return n; } void dfh_deleteheap ( DFibHeap *h ) { fprintf ( stderr, "DFibHeap: %lld node(s) allocated.\n", h->nodeMemory->counter ); freeMem_manager ( h->nodeMemory ); h->nodeMemory = NULL; if ( h->dfh_cons != NULL ) { free ( h->dfh_cons ); } free ( h ); } /* * Public Key Heap Functions */ DFibHeapNode *dfh_insertkey ( DFibHeap *h, Time key, unsigned int data ) { DFibHeapNode *x; if ( ( x = dfhe_newelem ( h ) ) == NULL ) { return NULL; } /* just insert on root list, and make sure it's not the new min */ x->dfhe_data = data; x->dfhe_key = key; dfh_insertel ( h, x ); return x; } Time dfh_replacekey ( DFibHeap *h, DFibHeapNode *x, Time key ) { Time ret; ret = x->dfhe_key; ( void ) dfh_replacekeydata ( h, x, key, x->dfhe_data ); return ret; } unsigned int minInDHeap ( DFibHeap *h ) { if ( h->dfh_min ) { return h->dfh_min->dfhe_data; } else { return 0; } } boolean HasMin ( DFibHeap *h ) { if ( h->dfh_min ) { return 1; } else { return 0; } } unsigned int dfh_replacekeydata ( DFibHeap *h, DFibHeapNode *x, Time key, unsigned int data ) { unsigned int odata; Time okey; DFibHeapNode *y; int r; odata = x->dfhe_data; okey = x->dfhe_key; /* * we can increase a key by deleting and reinserting, that * requires O(lgn) time. */ if ( ( r = dfh_comparedata ( h, key, data, x ) ) > 0 ) { /* XXX - bad code! */ abort (); } x->dfhe_data = data; x->dfhe_key = key; /* because they are equal, we don't have to do anything */ if ( r == 0 ) { return odata; } y = x->dfhe_p; if ( okey == key ) { return odata; } if ( y != NULL && dfh_compare ( h, x, y ) <= 0 ) { dfh_cut ( h, x, y ); dfh_cascading_cut ( h, y ); } /* * the = is so that the call from dfh_delete will delete the proper * element. */ if ( dfh_compare ( h, x, h->dfh_min ) <= 0 ) { h->dfh_min = x; } return odata; } /* * Public void * Heap Functions */ /* * this will return these values: * NULL failed for some reason * ptr token to use for manipulation of data */ unsigned int dfh_extractmin ( DFibHeap *h ) { DFibHeapNode *z; unsigned int ret; ret = 0; if ( h->dfh_min != NULL ) { z = dfh_extractminel ( h ); ret = z->dfhe_data; deallocateDFibHeapNode ( z, h ); } return ret; } unsigned int dfh_replacedata ( DFibHeapNode *x, unsigned int data ) { unsigned int odata = x->dfhe_data; //printf("replace node value %d with %d\n",x->dfhe_data,data); x->dfhe_data = data; return odata; } unsigned int dfh_delete ( DFibHeap *h, DFibHeapNode *x ) { unsigned int k; //printf("destroy node %d in dheap\n",x->dfhe_data); k = x->dfhe_data; dfh_replacekey ( h, x, INT_MIN ); dfh_extractmin ( h ); return k; } /* * begin of private element fuctions */ static DFibHeapNode *dfh_extractminel ( DFibHeap *h ) { DFibHeapNode *ret; DFibHeapNode *x, *y, *orig; ret = h->dfh_min; orig = NULL; /* put all the children on the root list */ /* for true consistancy, we should use dfhe_remove */ for ( x = ret->dfhe_child; x != orig && x != NULL; ) { if ( orig == NULL ) { orig = x; } y = x->dfhe_right; x->dfhe_p = NULL; dfh_insertrootlist ( h, x ); x = y; } /* remove minimum from root list */ dfh_removerootlist ( h, ret ); h->dfh_n--; /* if we aren't empty, consolidate the heap */ if ( h->dfh_n == 0 ) { h->dfh_min = NULL; } else { h->dfh_min = ret->dfhe_right; dfh_consolidate ( h ); } return ret; } static void dfh_insertrootlist ( DFibHeap *h, DFibHeapNode *x ) { if ( h->dfh_root == NULL ) { h->dfh_root = x; x->dfhe_left = x; x->dfhe_right = x; return; } dfhe_insertafter ( h->dfh_root, x ); } static void dfh_removerootlist ( DFibHeap *h, DFibHeapNode *x ) { if ( x->dfhe_left == x ) { h->dfh_root = NULL; } else { h->dfh_root = dfhe_remove ( x ); } } static void dfh_consolidate ( DFibHeap *h ) { DFibHeapNode **a; DFibHeapNode *w; DFibHeapNode *y; DFibHeapNode *x; IDnum i; IDnum d; IDnum D; dfh_checkcons ( h ); /* assign a the value of h->dfh_cons so I don't have to rewrite code */ D = h->dfh_Dl + 1; a = h->dfh_cons; for ( i = 0; i < D; i++ ) { a[i] = NULL; } while ( ( w = h->dfh_root ) != NULL ) { x = w; dfh_removerootlist ( h, w ); d = x->dfhe_degree; /* XXX - assert that d < D */ while ( a[d] != NULL ) { y = a[d]; if ( dfh_compare ( h, x, y ) > 0 ) { swap ( DFibHeapNode *, x, y ); } dfh_heaplink ( h, y, x ); a[d] = NULL; d++; } a[d] = x; } h->dfh_min = NULL; for ( i = 0; i < D; i++ ) if ( a[i] != NULL ) { dfh_insertrootlist ( h, a[i] ); if ( h->dfh_min == NULL || dfh_compare ( h, a[i], h->dfh_min ) < 0 ) { h->dfh_min = a[i]; } } } static void dfh_heaplink ( DFibHeap *h, DFibHeapNode *y, DFibHeapNode *x ) { /* make y a child of x */ if ( x->dfhe_child == NULL ) { x->dfhe_child = y; } else { dfhe_insertbefore ( x->dfhe_child, y ); } y->dfhe_p = x; x->dfhe_degree++; y->dfhe_mark = 0; } static void dfh_cut ( DFibHeap *h, DFibHeapNode *x, DFibHeapNode *y ) { dfhe_remove ( x ); y->dfhe_degree--; dfh_insertrootlist ( h, x ); x->dfhe_p = NULL; x->dfhe_mark = 0; } static void dfh_cascading_cut ( DFibHeap *h, DFibHeapNode *y ) { DFibHeapNode *z; while ( ( z = y->dfhe_p ) != NULL ) { if ( y->dfhe_mark == 0 ) { y->dfhe_mark = 1; return; } else { dfh_cut ( h, y, z ); y = z; } } } /* * begining of handling elements of dfibheap */ static DFibHeapNode *dfhe_newelem ( DFibHeap *h ) { DFibHeapNode *e; if ( ( e = allocateDFibHeapNode ( h ) ) == NULL ) { return NULL; } e->dfhe_degree = 0; e->dfhe_mark = 0; e->dfhe_p = NULL; e->dfhe_child = NULL; e->dfhe_left = e; e->dfhe_right = e; e->dfhe_data = 0; return e; } static void dfhe_insertafter ( DFibHeapNode *a, DFibHeapNode *b ) { if ( a == a->dfhe_right ) { a->dfhe_right = b; a->dfhe_left = b; b->dfhe_right = a; b->dfhe_left = a; } else { b->dfhe_right = a->dfhe_right; a->dfhe_right->dfhe_left = b; a->dfhe_right = b; b->dfhe_left = a; } } static inline void dfhe_insertbefore ( DFibHeapNode *a, DFibHeapNode *b ) { dfhe_insertafter ( a->dfhe_left, b ); } static DFibHeapNode *dfhe_remove ( DFibHeapNode *x ) { DFibHeapNode *ret; if ( x == x->dfhe_left ) { ret = NULL; } else { ret = x->dfhe_left; } /* fix the parent pointer */ if ( x->dfhe_p != NULL && x->dfhe_p->dfhe_child == x ) { x->dfhe_p->dfhe_child = ret; } x->dfhe_right->dfhe_left = x->dfhe_left; x->dfhe_left->dfhe_right = x->dfhe_right; /* clear out hanging pointers */ x->dfhe_p = NULL; x->dfhe_left = x; x->dfhe_right = x; return ret; } static void dfh_checkcons ( DFibHeap *h ) { IDnum oDl; /* make sure we have enough memory allocated to "reorganize" */ if ( h->dfh_Dl == -1 || h->dfh_n > ( 1 << h->dfh_Dl ) ) { oDl = h->dfh_Dl; if ( ( h->dfh_Dl = ceillog2 ( h->dfh_n ) + 1 ) < 8 ) { h->dfh_Dl = 8; } if ( oDl != h->dfh_Dl ) { h->dfh_cons = ( DFibHeapNode ** ) realloc ( h->dfh_cons, sizeof * h->dfh_cons * ( h->dfh_Dl + 1 ) ); } if ( h->dfh_cons == NULL ) { abort (); } } } static int dfh_compare ( DFibHeap *h, DFibHeapNode *a, DFibHeapNode *b ) { if ( a->dfhe_key < b->dfhe_key ) { return -1; } if ( a->dfhe_key == b->dfhe_key ) { return 0; } return 1; } static int dfh_comparedata ( DFibHeap *h, Time key, unsigned int data, DFibHeapNode *b ) { DFibHeapNode a; a.dfhe_key = key; a.dfhe_data = data; return dfh_compare ( h, &a, b ); } static void dfh_insertel ( DFibHeap *h, DFibHeapNode *x ) { dfh_insertrootlist ( h, x ); if ( h->dfh_min == NULL || x->dfhe_key < h->dfh_min->dfhe_key ) { h->dfh_min = x; } h->dfh_n++; } Time dfibheap_el_getKey ( DFibHeapNode *node ) { return node->dfhe_key; }