dikbm.c

来自「17个最短路径源代码。代码效率高」· C语言 代码 · 共 267 行

C
267
字号
int dikbm ( n, nodes, source, maxlen )

long n;                          /* number of nodes */
node *nodes,                    /* pointer to the first node */
     *source;                   /* pointer to the source     */
long maxlen;                    /* maximal arc length */ 
{


/*******************   definitions for heap  *****************/


typedef /* bucket-heap */
   struct bucket_st
{
   long              size;          /* the number of buckets 0..size */
   long              base;          /* distance from the source to 0-bucket */
   long              curr;          /* the current number of active bucket */
   node            **first;         /* first node in the bucket */ 
} 
   bheap;

long  k, pos, bound;

node *entry, *node_next, *last_m, *first_m;

#define BUCKETS_MAX 50000
#define BUCKETS_MIN 1
#define BUCKETS_DIV 3
#define NNULL          (node*)NULL
#define NOT_ENOUGH_MEM 2

/* status of node regarding to heap */ 
#define IN_BHEAP     0
#define OUT_OF_BHEAP 1

#define INIT_BHEAP( source, maxlen )\
{\
/* bh.size may depend on maxlen */\
bh.size = maxlen / BUCKETS_DIV;\
if ( bh.size < BUCKETS_MIN ) bh.size = BUCKETS_MIN;\
if ( bh.size > n ) bh.size = n;\
if ( bh.size > BUCKETS_MAX ) bh.size = BUCKETS_MAX;\
\
if (\
( bh.first = (node**) calloc ( ( bh.size + 1 ), sizeof(node*) ) )\
  ==\
  (node**)NULL\
   )\
   return (NOT_ENOUGH_MEM);\
\
source -> status = IN_BHEAP;\
bh.first[0] = source -> next = source -> prev = source;\
\
bh.base = bh.curr = 0;\
\
for ( k = 1; k <= bh.size; k ++ ) bh.first[k] = NNULL;\
}

#define NODE_IN_BHEAP( node ) ( node -> status == IN_BHEAP )

#define DIST_TO_POS( distance, pos )\
{\
  if (\
    ( pos = distance - bh.base )\
       >\
      bh.size\
     )\
       pos = bh.size;\
  else\
    if ( pos < bh.curr ) pos = bh.curr;\
}
        

#define REMOVE_FROM_BHEAP( node, pos )\
{\
  if ( node -> next == node )\
      bh.first[pos] = NULL;\
  else\
    { ( ( node -> prev ) -> next ) = ( node -> next );\
      ( ( node -> next ) -> prev ) = ( node -> prev );\
      if ( bh.first[pos] == node )\
        bh.first[pos] = node -> next;\
    }\
}

#define INSERT_TO_BHEAP( node, pos )\
{\
  if ( bh.first[pos] == NNULL )\
    bh.first[pos] = node -> next = node -> prev = node;\
  else\
    { entry = bh.first[pos];\
      ( entry -> prev ) -> next = node;\
      node  -> prev             = entry -> prev;\
      node  -> next             = entry;\
      entry -> prev             = node;\
    }\
\
  node -> status = IN_BHEAP;\
\
}

#define EXTRACT_MIN( node ) \
{\
repeat:\
for ( ; bh.curr < bh.size &&  bh.first[bh.curr] == NNULL ; bh.curr ++ )\
 ;\
if ( bh.curr == bh.size )\
  if ( bh.first[bh.size] != NNULL )\
    {\
      node = bh.first[bh.size];\
      ( ( node -> prev ) -> next ) = NNULL;\
\
      for ( bh.base = VERY_FAR;\
            node != NNULL;\
	    node = node -> next\
	  )\
	    {\
           if ( (node -> dist) < bh.base )\
             bh.base = node -> dist;\
	     }\
\
      bound = bh.base + bh.size;\
      bh.curr = 0;\
      last_m = first_m = NNULL;\
\
      for ( node = bh.first[bh.size];\
            node != NNULL;\
	    node = node_next\
	  )\
	    {\
	       node_next = node -> next;\
\
	       if ( ( dist_new = (node -> dist) ) < bound )\
		 {\
		   DIST_TO_POS ( dist_new, pos_new )\
		   INSERT_TO_BHEAP ( node, pos_new )\
		 }\
	       else\
		 {\
		    if ( last_m != NNULL )\
		      {\
		        last_m -> next = node;\
		        node   -> prev = last_m;\
              	      }\
                    else\
		        first_m = node;\
\
                    last_m = node;\
		 }\
	     }\
\
      if ( last_m != NNULL )\
	{\
	   last_m  -> next = first_m;\
	   first_m -> prev = last_m;\
	}\
      bh.first[bh.size] = first_m;\
      goto repeat;\
    }\
  else\
    node = NNULL;\
else\
  {\
    node = bh.first[bh.curr];\
    node -> status = OUT_OF_BHEAP;\
\
    if ( node -> next == node )\
        bh.first[bh.curr] = NNULL;\
    else\
      { ( ( node -> prev ) -> next ) = ( node -> next );\
        ( ( node -> next ) -> prev ) = ( node -> prev );\
	bh.first[bh.curr] = node -> next;\
      }\
  }\
}

/**************   end of heap definitions   ****************/

#define VERY_FAR 1073741823

long dist_new,
     dist_old,
     dist_from;

long pos_new,
     pos_old;

node *node_from,
     *node_to,
     *node_last,
     *i;

arc  *arc_ij,
     *arc_last;

long  num_scans = 0;

bheap bh;

int in=0;

int   ins;
/* initialization */

node_last = nodes + n ;
 
for ( i = nodes; i < node_last; i ++ )
   { 
      i -> parent   = NNULL;
      i -> dist     = VERY_FAR;
      i -> status   = OUT_OF_BHEAP;
   }

source -> parent = source;
source -> dist   = 0;


INIT_BHEAP ( source, maxlen )

/* main loop */

while ( 1 )
 {
   EXTRACT_MIN ( node_from )

   if ( node_from == NNULL ) break;

   num_scans ++;
/* printf ("from: %d\n",node_from-nodes+1); */

      arc_last = ( node_from + 1 ) -> first;
      dist_from = node_from -> dist;
   
   for ( arc_ij = node_from -> first; arc_ij != arc_last; arc_ij ++ )
     {
       node_to  = arc_ij -> head;
       dist_new = dist_from + ( arc_ij -> len );

       if ( dist_new <  node_to -> dist )
	   { 
	       DIST_TO_POS ( dist_new, pos_new )
               if ( NODE_IN_BHEAP ( node_to ) )
		 { 
		   dist_old = node_to -> dist;
		   DIST_TO_POS ( dist_old, pos_old )

		   if ( ins = ( pos_old != pos_new ) )
	              REMOVE_FROM_BHEAP ( node_to, pos_old )
		 }
               else
		 ins = 1;

             if ( ins )
	       INSERT_TO_BHEAP ( node_to, pos_new )

             node_to -> dist   = dist_new;
             node_to -> parent = node_from;
n_impr ++;
	   }
     }
 }
n_scans = num_scans;
return (0);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?