home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1987 / 06 / holublst.jun < prev    next >
Text File  |  1987-05-05  |  20KB  |  561 lines

  1.                          Listing 1 -- pq.c
  2.     _____________________________________________________________
  3.   1| #include <stdio.h>
  4.   2| 
  5.   3| /* PQ.C         General-purpose priority-queue routines.
  6.   4|  *              (C) 1987 Allen I. Holub. All Rights Reserved.
  7.   5|  *
  8.   6|  * typedef char *PQ;    Dummy typedef for priority queue.
  9.   7|  *
  10.   8|  * PQ   *pq_create( numele, elesize, cmp, swap, initheap )
  11.   9|  * int  numele;         Max # of elements in the queue
  12.  10|  * int  elesize;        Size of one element in bytes
  13.  11|  * int  (*cmp)();       Pointer to comparison function
  14.  12|  * int  (*swap)();      Pointer to swap function
  15.  13|  * char *initheap;      Inital heap or NULL to allocate
  16.  14|  * 
  17.  15|  * pq_ins( p, item )    Insert Item into queue
  18.  16|  * PQ   *p;             Pointer to priority queue
  19.  17|  * char *item;          Pointer to item to insert
  20.  18|  *                      Return number of empty slots
  21.  19|  *                      before insertion (0 if none).
  22.  20|  * 
  23.  21|  * int  pq_del( p, target ) Delete item from queue
  24.  22|  * PQ   *p;                 Pointer to priority queue
  25.  23|  * char *target;            Pointer to place to put deleted
  26.  24|  *                          item.
  27.  25|  *                          Return # of items in queue before
  28.  26|  *                          delete (0 if nothing deleted).
  29.  27|  * 
  30.  28|  * char *pq_look( queue )   Look at (don't delete) top element
  31.  29|  * PQ   *queue;             Pointer to queue.
  32.  30|  * 
  33.  31|  * int  pq_numele( queue )  Return # of elements in queue.
  34.  32|  * PQ   *queue;             Pointer to queue.
  35.  33|  *
  36.  34|  *-----------------------------------------------------------
  37.  35|  */
  38.  36| 
  39.  37| typedef struct
  40.  38| {
  41.  39|     int   (*cmp)();     /* compares two objects              */
  42.  40|     int   (*swap)();    /* swap two objects                  */
  43.  41|     int   itemsize;     /* size of one element in heap       */
  44.  42|     int   nitems;       /* Number of items in the heap       */
  45.  43|     int   maxitem;      /* Maximum number of items in heap   */
  46.  44|     char  *bottom;      /* Ptr. to most-recently added item  */
  47.  45|     char  *heap;        /* pointer to the heap itself        */
  48.  46| }
  49.  47| PQ;
  50.  48| 
  51.  49| /*-----------------------------------------------------------*/
  52.  50| 
  53.  51| static  void    reheap_down( p )
  54.  52| PQ      *p;
  55.  53| {
  56.  54|     /*  Reheap the Heap, starting at the top and working
  57.  55|      *  down;
  58.  56|      */
  59.  57| 
  60.  58|     int    parent;      /* index of parent              */
  61.  59|     int    child;       /* index of child               */
  62.  60|     char   *pparent;    /* pointer to parent            */
  63.  61|     char   *pchild;     /* pointer to child             */
  64.  62|     char   *psibling;   /* pointer to child's sibling   */
  65.  63|     char   *heap;       /* pointer to heap              */
  66.  64| 
  67.  65|     heap = p->heap;
  68.  66| 
  69.  67|     for( parent = 0, child = 1;  child < p->nitems ;)
  70.  68|     {
  71.  69|         pparent = heap + (parent * p->itemsize);
  72.  70|         pchild  = heap + (child  * p->itemsize);
  73.  71| 
  74.  72|         if( child+1 < p->nitems )
  75.  73|         {
  76.  74|             psibling = pchild + p->itemsize ;
  77.  75| 
  78.  76|             if( (*p->cmp)(pchild, psibling)  < 0 )
  79.  77|             {
  80.  78|                 pchild = psibling;
  81.  79|                 ++child;
  82.  80|             }
  83.  81|         }
  84.  82| 
  85.  83|         if( (*p->cmp)( pparent, pchild ) >= 0)
  86.  84|                 break;
  87.  85| 
  88.  86|         (*p->swap)( pparent, pchild );
  89.  87| 
  90.  88|         parent = child;
  91.  89|         child  = (parent * 2) + 1;
  92.  90|     }
  93.  91| }
  94.  92| 
  95.  93| /*-----------------------------------------------------------*/
  96.  94| 
  97.  95| static void     reheap_up( p )
  98.  96| PQ      *p;
  99.  97| {
  100.  98|     /* Reheap the Heap, starting at the bottom and working up.
  101.  99|      * Note that we must use a divide-by-2 rather than a
  102. 100|      * shift-right in the while loop because -1/2 == 0 but
  103. 101|      * -1 >> 1 == -1.
  104. 102|      */
  105. 103| 
  106. 104|     int    parent;      /* index of parent              */
  107. 105|     int    child;       /* index of child               */
  108. 106|     char   *pparent;    /* pointer to parent            */
  109. 107|     char   *pchild;     /* pointer to child             */
  110. 108|     char   *heap;       /* pointer to heap              */
  111. 109| 
  112. 110|     child = p->nitems - 1;
  113. 111|     heap  = p->heap;
  114. 112| 
  115. 113|     while( (parent = (child-1) / 2)  >= 0 )
  116. 114|     {
  117. 115|         pchild  = heap + (child  * p->itemsize);
  118. 116|         pparent = heap + (parent * p->itemsize);
  119. 117| 
  120. 118|         if( (*p->cmp)( pparent, pchild ) >= 0)
  121. 119|                 break;
  122. 120| 
  123. 121|         (*p->swap)( pparent, pchild );
  124. 122|         child = parent;
  125. 123|     }
  126. 124| }
  127. 125| 
  128. 126| /*-----------------------------------------------------------*/
  129. 127| 
  130. 128| PQ      *pq_create( numele, elesize, cmp, swap, initheap )
  131. 129| 
  132. 130| int     numele;         /* max # of elements in the queue */
  133. 131| int     elesize;        /* size of one element in byte    */
  134. 132| int     (*cmp)();       /* pointer to comparison function */
  135. 133| int     (*swap)();      /* pointer to swap function       */
  136. 134| char    *initheap;      /* inital heap, NULL to allocate  */
  137. 135| {
  138. 136|     /* Create a priority queue that can hold at most
  139. 137|      * "numele" elements, each of size "elesize". The
  140. 138|      * cmp function is passed two pointers to queue
  141. 139|      * elements and it should behave as follows:
  142. 140|      *
  143. 141|      *      (*cmp)(p1, p2)
  144. 142|      *
  145. 143|      * For descending priority queues [pq_get() returns the
  146. 144|      *                                      largest item].
  147. 145|      *      *p1 <  *p2      return <  0
  148. 146|      *      *p1 == *p2      return == 0
  149. 147|      *      *p1 >  *p2      return >  0
  150. 148|      *
  151. 149|      * For ascending priority queues [pq_get() returns the
  152. 150|      *                                      smallest item].
  153. 151|      *      *p1 <  *p2      return >  0
  154. 152|      *      *p1 == *p2      return == 0
  155. 153|      *      *p1 >  *p2      return <  0
  156. 154|      *
  157. 155|      * If the initheap argument is NULL, an empty heap is
  158. 156|      * created automatically, otherwise initheap must point
  159. 157|      * at an initialized numele-element-long heap.
  160. 158|      */
  161. 159|
  162. 160|     PQ      *p, *malloc() ;
  163. 161|     int     heapsize;
  164. 162|
  165. 163|     heapsize = numele * elesize ;   /* heap size in bytes */
  166. 164| 
  167. 165|     if( initheap )
  168. 166|     {
  169. 167|         if( !(p = malloc(sizeof(PQ))) )
  170. 168|             return 0;
  171. 169| 
  172. 170|         p->heap   = initheap;
  173. 171|         p->bottom = initheap + ((numele - 1) * elesize);
  174. 172|         p->nitems = numele;
  175. 173|     }
  176. 174|     else
  177. 175|     {
  178. 176|         if( !(p = malloc(sizeof(PQ) + heapsize)) )
  179. 177|             return 0;
  180. 178| 
  181. 179|         p->heap   = (char *)(p + 1);
  182. 180|         p->nitems = 0;
  183. 181|         p->bottom = p->heap - elesize ;
  184. 182|     }
  185. 183| 
  186. 184|     p->cmp      = cmp;
  187. 185|     p->swap     = swap;
  188. 186|     p->itemsize = elesize;
  189. 187|     p->maxitem  = numele ;
  190. 188|     return p;
  191. 189| }
  192. 190| 
  193. 191| /*-----------------------------------------------------------*/
  194. 192| 
  195. 193| pq_ins( p, item )
  196. 194| PQ      *p;             /* Pointer to priority queue    */
  197. 195| char    *item;          /* Pointer to item to insert    */
  198. 196| {
  199. 197|     /* Insert a new item into the priority queue (provided
  200. 198|      * that space is available.
  201. 199|      *
  202. 200|      * Return the number of empty slots in the queue before
  203. 201|      * the insertion. This number is 0 if the queue is
  204. 202|      * full and nothing is inserted. Algorithm is:
  205. 203|      *
  206. 204|      *  if( space is available in the queue )
  207. 205|      *          increase queue size
  208. 206|      *          copy new item into bottom of queue
  209. 207|      *          reheap from the bottom up.
  210. 208|      */
  211. 209| 
  212. 210|     int space_avail = p->maxitem - p->nitems;
  213. 211| 
  214. 212|     if( space_avail > 0 )
  215. 213|     {
  216. 214|         ++( p->nitems );
  217. 215|         memcpy( p->bottom += p->itemsize, &item, p->itemsize );
  218. 216|         reheap_up( p );
  219. 217|     }
  220. 218| 
  221. 219|     return space_avail ;
  222. 220| }
  223. 221| 
  224. 222| /*-----------------------------------------------------------*/
  225. 223| 
  226. 224| int     pq_del( p, target )
  227. 225| 
  228. 226| PQ      *p;           /* pointer to priority queue          */
  229. 227| char    *target;      /* place to copy current largest item */
  230. 228| {
  231. 229|      /* Copy the largest item in the priority queue to
  232. 230|       * the address held in target, then delete the item.
  233. 231|       *
  234. 232|       * Return the number of items in the queue before the
  235. 233|       * delete. If this number is 0, then nothing was
  236. 234|       * in the queue and *target will not have been
  237. 235|       * modified. Algorithm is:
  238. 236|       * 
  239. 237|       *  if( there's something in the queue )         [1]
  240. 238|       *      remember pointer to former first item    [2]
  241. 239|       *      replace the first item with the last one [3]
  242. 240|       *      shrink the heap by one element           [4]
  243. 241|       *      reheap from the top down                 [5]
  244. 242|       */
  245. 243| 
  246. 244|      int     slots_in_use;
  247. 245| 
  248. 246|      if( slots_in_use = p->nitems )                  /* 1 */
  249. 247|      {
  250. 248|          memcpy( target,  p->heap,   p->itemsize );  /* 2 */
  251. 249|          memcpy( p->heap, p->bottom, p->itemsize );  /* 3 */
  252. 250| 
  253. 251|          --(p->nitems) ;                             /* 4 */
  254. 252|          p->bottom -= p->itemsize;
  255. 253| 
  256. 254|          reheap_down( p );                           /* 5 */
  257. 255|      }
  258. 256| 
  259. 257|      return slots_in_use ;
  260. 258| }
  261. 259| 
  262. 260| /*-----------------------------------------------------------*/
  263. 261| 
  264. 262| char    *pq_look( queue )
  265. 263| PQ      *queue;
  266. 264| {
  267. 265|         /* Return a pointer to the largest/smallest element
  268. 266|          * in the priority queue but don't dequeue it.
  269. 267|          */
  270. 268| 
  271. 269|         return queue->heap;
  272. 270| }
  273. 271| 
  274. 272| /*-----------------------------------------------------------*/
  275. 273| 
  276. 274| int     pq_numele( queue )
  277. 275| PQ      *queue;
  278. 276| {
  279. 277|         /* Return number of items in queue
  280. 278|         */
  281. 279| 
  282. 280|         return queue->nitems;
  283. 281| }
  284. 282| 
  285. 283| /*===========================================================*/
  286. 284| #ifdef MAIN
  287. 285| 
  288. 286| int Descending = 1;     /* Change these in Codeview     */
  289. 287| int Makequeue  = 1;     /* to change the tests.         */
  290. 288| 
  291. 289| cmp( s1, s2 )
  292. 290| char    **s1, **s2;
  293. 291| {
  294. 292|         int rval;
  295. 293|         rval = strcmp( *s1, *s2 );
  296. 294| 
  297. 295|         if( Descending )
  298. 296|             return rval;
  299. 297|         else
  300. 298|             return   ( rval <  0 )  ?  1 :
  301. 299|                      ( rval >  0 )  ? -1 :
  302. 300|                     /* rval == 0 */    0 ;
  303. 301| }
  304. 302| 
  305. 303| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  306. 304| 
  307. 305| swap( s1, s2 )
  308. 306| char    **s1, **s2;
  309. 307| {
  310. 308|         char    *tmp;
  311. 309| 
  312. 310|         tmp = *s1;
  313. 311|         *s1 = *s2;
  314. 312|         *s2 = tmp;
  315. 313| }
  316. 314| 
  317. 315| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  318. 316| 
  319. 317| printq( p )
  320. 318| PQ      *p;
  321. 319| {
  322. 320|     int i;
  323. 321|     
  324. 322|     printf("Queue is:\n");
  325. 323| 
  326. 324|     printf( "\tcmp............. 0x%04x\t", p->cmp      );
  327. 325|     printf( "\tswap............ 0x%04x\n", p->swap     );
  328. 326|     printf( "\titemsize........ %d\t",     p->itemsize );
  329. 327|     printf( "\tnitems.......... %d\n",     p->nitems   );
  330. 328|     printf( "\tmaxitem......... %d\t",     p->maxitem  );
  331. 329|     printf( "\tbottom.......... 0x%04x\n", p->bottom   );
  332. 330|     printf( "\theap............ 0x%04x\t", p->heap     );
  333. 331|     printf( "\tbottom - heap... %d\n\n",   (char **)p->bottom -
  334. 332|                                            (char **)p->heap );
  335. 333|     if( p->nitems <= 0 )
  336. 334|         printf("\tqueue is empty\n");
  337. 335| 
  338. 336|     else for( i = 0 ; i < p->nitems ; i++ )
  339. 337|     {
  340. 338|        printf("\t%-2d: %10.10s (0x%04x) (children: %2d, %2d)\n",
  341. 339|              i, ((char **)p->heap)[i], ((char **)p->heap)[i],
  342. 340|                 (2*i)+1,               (2*i)+2                );
  343. 341|     }
  344. 342| }
  345. 343| 
  346. 344| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  347. 345| 
  348. 346| main()
  349. 347| {
  350. 348|     PQ    *queue;
  351. 349|     char  buf[80];
  352. 350|     int   i;
  353. 351|     char  *p;
  354. 352| 
  355. 353|     static char  *testq[] =
  356. 354|     {
  357. 355|         "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
  358. 356|     };
  359. 357| 
  360. 358|     if( Makequeue )
  361. 359|         queue = pq_create( 10, sizeof(char*), cmp, swap, 0    );
  362. 360|     else
  363. 361|         queue = pq_create( 10, sizeof(char*), cmp, swap, testq);
  364. 362| 
  365. 363|     if( !queue )
  366. 364|     {
  367. 365|         printf("pq_create failed\n");
  368. 366|         exit( 1 );
  369. 367|     }
  370. 368| 
  371. 369|     printf("+-------------------------------------------+\n");
  372. 370|     printf("| Enter i<string><CR> to add string to      |\n");
  373. 371|     printf("| queue, d<CR> to dequeue top element, q to |\n");
  374. 372|     printf("| exit the program.                         |\n");
  375. 373|     printf("+-------------------------------------------+\n");
  376. 374| 
  377. 375|     while( 1 )
  378. 376|     {
  379. 377|         printq( queue                   );
  380. 378|         printf( "\n[i|d|q][string] :"   );
  381. 379|         gets  ( buf                     );
  382. 380| 
  383. 381|         if( *buf == 'q' )
  384. 382|                 exit( 1 );
  385. 383| 
  386. 384|         else if( *buf == 'i' )
  387. 385|         {
  388. 386|             i = pq_ins( queue, strsave(buf + 1) );
  389. 387| 
  390. 388|             if( i )
  391. 389|               printf("%d slots avail. before insert\n", i);
  392. 390|             else
  393. 391|               printf("Queue was full, did nothing\n\n");
  394. 392|         }
  395. 393|         else
  396. 394|         {
  397. 395|             i = pq_del( queue, (char*) &p );
  398. 396|             printf("%d slots used before delete, got <%s>\n",
  399. 397|                                                        i, p);
  400. 398|             if( i )
  401. 399|             {
  402. 400|                 free( p );
  403. 401|                 p = "nothing";
  404. 402|             }
  405. 403|         }
  406. 404|     }
  407. 405| }
  408. 406| 
  409. 407| #endif
  410.                      Listing 2 -- strsave.c
  411.    ____________________________________________________________
  412.   1| char    *strsave( str )
  413.   2| char    *str;
  414.   3| {
  415.   4|     /*  Save the indicated string in a malloc()ed section
  416.   5|      *  of static memory. Return a pointer to the copy or
  417.   6|      *  0 if malloc failed.
  418.   7|      */
  419.   8| 
  420.   9|     register char *rptr;
  421.  10|     extern   char *malloc();
  422.  11| 
  423.  12|     if( rptr = malloc( strlen(str) +1 ))
  424.  13|     {
  425.  14|             strcpy( rptr, str );
  426.  15|             return rptr;
  427.  16|     }
  428.  17| 
  429.  18|     return (char *)0;
  430.  19| }
  431.                       Listing 3 -- freq.c
  432.    _______________________________________________________________
  433.   1| #include <stdio.h>
  434.   2| 
  435.   3| /*      FREQ.C          Print a list of the frequency
  436.   4|  *                      of occurance of all bytes
  437.   5|  *      in a list of files given on the command line.
  438.   6|  *      Frequencies are printed as a probability x 100.
  439.   7|  *      For example, if we read a total of 20 characters,
  440.   8|  *      5 of which are 'e', the probability of an 'e'
  441.   9|  *      occuring in the input is 5/20 (.25) and freq will
  442.  10|  *      output (.25 * 100) or 25.
  443.  11|  */
  444.  12| 
  445.  13| typedef struct
  446.  14| {
  447.  15|         int     val;
  448.  16|         double  count;
  449.  17| } ITEM;
  450.  18| 
  451.  19| #define TABSIZE 256
  452.  20| ITEM    Tab[ TABSIZE ];   /* I'm counting on this being    */
  453.  21|                           /* initialized to zero.          */
  454.  22| 
  455.  23| /*----------------------------------------------------------*/
  456.  24| 
  457.  25| cmp( item1, item2 )
  458.  26| ITEM    *item1, *item2;
  459.  27| {
  460.  28|     /* Comparison function used by ssort(), below.
  461.  29|      * Count is the primary sort field and val is
  462.  30|      * the secondary field.
  463.  31|      */
  464.  32| 
  465.  33|     int rval;
  466.  34| 
  467.  35|     return   ( item1->count <  item2->count )   ? -1 :
  468.  36|              ( item1->count >  item2->count )   ?  1 :
  469.  37|             /* item1->count == item2->count */
  470.  38|                                    item1->val - item2->val ;
  471.  39| }
  472.  40| 
  473.  41| /*----------------------------------------------------------*/
  474.  42| 
  475.  43| main( argc, argv )
  476.  44| char    **argv;
  477.  45| {
  478.  46|     char          *bin_to_ascii();      /* in pchar.c */
  479.  47|     FILE          *fp;
  480.  48|     int           i;
  481.  49|     double        smallest;
  482.  50|     double        largest;
  483.  51|     double        numchars    = 0.0 ;
  484.  52|     double        sum         = 0.0 ;
  485.  53|     double        probability = 0.0 ;
  486.  54| 
  487.  55|     reargv( &argc, &argv );     /* Needed only for      */
  488.  56|                                 /* On Command! shell    */
  489.  57| 
  490.  58|     for( --argc, ++argv ; --argc >= 0 ; argv++ )
  491.  59|     {
  492.  60|         if( !(fp = fopen( *argv, "rb")) )
  493.  61|             perror( *argv );
  494.  62|         else
  495.  63|         {
  496.  64|             fprintf( stderr, "%s\n", *argv );
  497.  65| 
  498.  66|             while( (i = getc(fp)) != EOF )
  499.  67|             {
  500.  68|                 ++ numchars;
  501.  69|                 ++ Tab[ i & 0xff ].count ;
  502.  70|             }
  503.  71| 
  504.  72|             fclose( fp );
  505.  73|         }
  506.  74|     }
  507.  75| 
  508.  76|     /* Find largest and smallest elements and at the same
  509.  77|      * time initialize the val fields of the Tab entries.
  510.  78|      */
  511.  79| 
  512.  80|     largest  = 0.0;
  513.  81|     smallest = numchars ;
  514.  82| 
  515.  83|     for( i = 0 ; i <= 0xff ; i++ )
  516.  84|     {
  517.  85|         Tab[i].val = i;
  518.  86| 
  519.  87|         if( Tab[i].count > 0.00000001 
  520.  88|         &&  Tab[i].count < smallest )
  521.  89|                 smallest = Tab[i].count;
  522.  90| 
  523.  91|         if( Tab[i].count > largest )
  524.  92|                 largest = Tab[i].count;
  525.  93|     }
  526.  94| 
  527.  95|     /* Sort the list by probability. A shell sort is used.
  528.  96|      * You can replace the ssort call below with a call to
  529.  97|      * the qsort() subroutine, available with many compilers.
  530.  98|      * Qsort() takes the same arguments as ssort().
  531.  99|      * A version of qsort appeared in the in the C Chest,
  532. 100|      * DDJ #102 (April, 1985; also Bound Volume 10, p.316).
  533. 101|      * The ssort() subroutine appeared in DDJ #113, C Chest
  534. 102|      * (March, 1986) p. 70.
  535. 103|      */
  536. 104| 
  537. 105|     ssort( Tab, TABSIZE, sizeof(ITEM), cmp );
  538. 106| 
  539. 107|     /*
  540. 108|      * Print the list. Each element is printed as three
  541. 109|      * numbers: the value of the charcter (in hex), the
  542. 110|      * probability of that character apearing in the input,
  543. 111|      * and the probabability normalized so that the least-
  544. 112|      * frequently occuring probability has the value 1.
  545. 113|      */
  546. 114| 
  547. 115|     for( i = 0 ; i < TABSIZE ; i++ )
  548. 116|     {
  549. 117|             probability =  Tab[i].count / numchars ;
  550. 118|             sum         += probability;
  551. 119| 
  552. 120|             printf( "0x%02x\t%7.6f\t%1.0f\n",
  553. 121|                         Tab[i].val,
  554. 122|                         probability,
  555. 123|                         Tab[i].count / smallest  );
  556. 124|     }
  557. 125| 
  558. 126|     fprintf( stderr, "Total = %8.6f  (N = %8.2f)\n",
  559. 127|                                         sum, numchars );
  560. 128| }
  561.