listcoll.c

Go to the documentation of this file.
00001 /* Copyright (c) 2005 by John M. Boyer, All Rights Reserved.  Please see
00002  * License.txt for use and redistribution license. */
00003 /* Copyright (c) 1997-2003 by John M. Boyer, All Rights Reserved.
00004         This code may not be reproduced in whole or in part without
00005         the written permission of the author. */
00006 
00007 #define _LISTCOLL_C
00008 
00009 #include "appconst.h"
00010 #include "listcoll.h"
00011 #include <stdlib.h>
00012 
00013 /*****************************************************************************
00014  The data structure defined by this module manages a set of N objects
00015  arranged as a collection of circular lists, each containing distinct
00016  elements from the set.
00017 
00018  On construction, LCNew() creates an array of N nodes, each containing a
00019  prev and next pointer.  The identity of the node is given by its array index.
00020  Each node's prev and next pointers are set to NIL, indicating that the node
00021  is not currently part of a list.  LCReset() can be called to reset all 
00022  pointers to NIL.
00023 
00024  The function LCFree() deallocates the collection of lists and clears the
00025  pointer variable used to pass the collection.
00026 
00027  An empty list is indicated by NIL.  To begin a list with node I, call
00028  LCPrepend() or LCAppend() with the NIL list and with I as the node.  The prev
00029  and next pointers in node I are set to I and I is returned as the head of
00030  the list.
00031 
00032  Future calls to LCPrepend() add a node J as the new first element of the list,
00033  so the list given as input is pointed to by J's next, and J is returned as
00034  the head of the list.
00035 
00036  Future calls to LCAppend() add a node J as the new last element, so the prev
00037  pointer of the list given as input will indicate node J, and the input list
00038  is returned as the head of the list.
00039 
00040  The function LCDelete() removes a node I from a list L.  If node I is in the
00041  list alone, then its pointers are set to NIL, and NIL is returned as the list.
00042  If node I is not alone in the list, but it is the head of the list (in other
00043  words, I is equal to L), then L's sucessor is returned as the new head of the
00044  list. Whether or not I equals L, node I is deleted by joining its predecessor
00045  and successor nodes.
00046 
00047  LCCopy() copies the contents of one collection to another if both are of
00048  equal size.
00049 
00050  LCGetNext() is used for forward iteration through a list in the collection.
00051  The expected iteration pattern is to process the node one has then call
00052  LCGetNext() to get the next node, so if the result of LCGetNext() would be the
00053  head of the list, then NIL is returned instead.  This simplifies most
00054  coding operations involving LCGetNext().
00055 
00056  LCGetPrev() is used for backward iteration through a list in the collection.
00057  The expected iteration pattern is that the last list element will be obtained
00058  by an initial call to LCGetPrev() with theNode equal to NIL.  This call
00059  should appear outside of the iteration loop.  The iteration loop then
00060  proceeds while the current node is not NIL.  The loop body processes the
00061  current node, then LCGetPrev() is called with theNode equal to the current
00062  node.  LCGetPrev() returns NIL if theNode is equal to theList.  Otherwise,
00063  the predecessor of theNode is returned.
00064 
00065  *****************************************************************************/
00066 
00067 /*****************************************************************************
00068  LCNew()
00069  *****************************************************************************/
00070 listCollectionP LCNew (int N)
00071 {
00072   listCollectionP theListColl = NULL;
00073   if (N <= 0)
00074     return theListColl;
00075   theListColl = (listCollectionP) malloc (sizeof (listCollectionRec));
00076   if (theListColl != NULL)
00077 
00078   {
00079     theListColl->List = (lcnode *) malloc (N * sizeof (lcnode));
00080     if (theListColl->List == NULL)
00081 
00082     {
00083       free (theListColl);
00084       theListColl = NULL;
00085     }
00086 
00087     else
00088 
00089     {
00090       theListColl->N = N;
00091       LCReset (theListColl);
00092     }
00093   }
00094   return theListColl;
00095 }
00096 
00097 
00098 /*****************************************************************************
00099  LCFree()
00100  *****************************************************************************/
00101 void LCFree (listCollectionP * pListColl)
00102 {
00103   if (pListColl == NULL || *pListColl == NULL)
00104     return;
00105   if ((*pListColl)->List != NULL)
00106     free ((*pListColl)->List);
00107   free (*pListColl);
00108   *pListColl = NULL;
00109 }
00110 
00111 
00112 #ifndef SPEED_MACROS
00113 
00114 /*****************************************************************************
00115  LCReset()
00116  *****************************************************************************/
00117 void LCReset (listCollectionP listColl)
00118 {
00119   int I;
00120   for (I = 0; I < listColl->N; I++)
00121     listColl->List[I].prev = listColl->List[I].next = NIL;
00122 }
00123 
00124 
00125 /*****************************************************************************
00126  LCCopy()
00127  *****************************************************************************/
00128 void LCCopy (listCollectionP dst,
00129              listCollectionP src)
00130 {
00131   int I;
00132   if (dst == NULL || src == NULL || dst->N != src->N)
00133     return;
00134   for (I = 0; I < dst->N; I++)
00135     dst->List[I] = src->List[I];
00136 }
00137 
00138 
00139 /*****************************************************************************
00140  LCGetNext()
00141  *****************************************************************************/
00142 int LCGetNext (listCollectionP listColl,
00143                int theList,
00144                int theNode)
00145 {
00146   int next;
00147   if (listColl == NULL || theList == NIL || theNode == NIL)
00148     return NIL;
00149   next = listColl->List[theNode].next;
00150   return next == theList ? NIL : next;
00151 }
00152 
00153 
00154 /*****************************************************************************
00155  LCGetPrev()
00156  *****************************************************************************/
00157 int LCGetPrev (listCollectionP listColl,
00158                int theList,
00159                int theNode)
00160 {
00161   if (listColl == NULL || theList == NIL)
00162     return NIL;
00163   if (theNode == NIL)
00164     return listColl->List[theList].prev;
00165   if (theNode == theList)
00166     return NIL;
00167   return listColl->List[theNode].prev;
00168 }
00169 
00170 
00171 /*****************************************************************************
00172  LCPrepend()
00173  *****************************************************************************/
00174 int LCPrepend (listCollectionP listColl,
00175                int theList,
00176                int theNode)
00177 {
00178   int newList = LCAppend (listColl, theList, theNode);
00179 
00180   /* If the append worked, then theNode is last, which in a circular
00181    * list is the direct predecessor of the list head node, so we
00182    * just back up one. For singletons, the result is unchanged. */
00183   if (newList != NOTOK)
00184     newList = listColl->List[newList].prev;
00185   return newList;
00186 }
00187 
00188 
00189 /*****************************************************************************
00190  LCAppend()
00191  *****************************************************************************/
00192 int LCAppend (listCollectionP listColl,
00193               int theList,
00194               int theNode)
00195 {
00196 
00197   /* If the given list is empty, then the given node becomes the
00198    * singleton list output */
00199   if (theList == NIL)
00200 
00201   {
00202     listColl->List[theNode].prev = listColl->List[theNode].next = theNode;
00203     theList = theNode;
00204   }
00205 
00206   /* Otherwise, make theNode the predecessor of head node of theList,
00207    * which is where the last node goes in a circular list. */
00208 
00209   else
00210 
00211   {
00212     int pred = listColl->List[theList].prev;
00213     listColl->List[theList].prev = theNode;
00214     listColl->List[theNode].next = theList;
00215     listColl->List[theNode].prev = pred;
00216     listColl->List[pred].next = theNode;
00217   }
00218 
00219   /* Return the list (only really important if it was NIL) */
00220   return theList;
00221 }
00222 
00223 
00224 /*****************************************************************************
00225  LCDelete()
00226  *****************************************************************************/
00227 int LCDelete (listCollectionP listColl,
00228               int theList,
00229               int theNode)
00230 {
00231 
00232   /* If the list is a singleton, then NIL its pointers and
00233    * return NIL for theList */
00234   if (listColl->List[theList].next == theList)
00235 
00236   {
00237     listColl->List[theList].prev = listColl->List[theList].next = NIL;
00238     theList = NIL;
00239   }
00240 
00241   /* Join predecessor and successor, dropping theNode from the list.
00242    * If theNode is the head of the list, then return the successor as
00243    * the new head node. */
00244 
00245   else
00246 
00247   {
00248     int pred = listColl->List[theNode].prev,
00249       succ = listColl->List[theNode].next;
00250     listColl->List[pred].next = succ;
00251     listColl->List[succ].prev = pred;
00252     listColl->List[theNode].prev = listColl->List[theNode].next = NIL;
00253     if (theList == theNode)
00254       theList = succ;
00255   }
00256   return theList;
00257 }
00258 
00259 
00260 #endif // SPEED_MACROS

Generated on Thu Oct 20 14:58:42 2005 for DominoParitySeparator by  doxygen 1.4.5