gattrib

listsort.c

Go to the documentation of this file.
00001 
00002 /*----------------------------------------------------------------*/
00010 /*
00011  * Demonstration code for sorting a linked list.
00012  * 
00013  * The algorithm used is Mergesort, because that works really well
00014  * on linked lists, without requiring the O(N) extra space it needs
00015  * when you do it on arrays.
00016  * 
00017  * This code can handle singly and doubly linked lists, and
00018  * circular and linear lists too. For any serious application,
00019  * you'll probably want to remove the conditionals on `is_circular'
00020  * and `is_double' to adapt the code to your own purpose. 
00021  * 
00022  */
00023 
00024 /*
00025  * This file is copyright 2001 Simon Tatham.
00026  * 
00027  * Permission is hereby granted, free of charge, to any person
00028  * obtaining a copy of this software and associated documentation
00029  * files (the "Software"), to deal in the Software without
00030  * restriction, including without limitation the rights to use,
00031  * copy, modify, merge, publish, distribute, sublicense, and/or
00032  * sell copies of the Software, and to permit persons to whom the
00033  * Software is furnished to do so, subject to the following
00034  * conditions:
00035  * 
00036  * The above copyright notice and this permission notice shall be
00037  * included in all copies or substantial portions of the Software.
00038  * 
00039  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00040  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00041  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00042  * NONINFRINGEMENT.  IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
00043  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00044  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00045  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00046  * SOFTWARE.
00047  */
00048 
00049 /* ---  We don't need these 'cause they are already defined elsewhere --- 
00050  * #define FALSE 0 
00051  * #define TRUE 1
00052  */
00053 
00054 #ifdef HAVE_CONFIG_H
00055 #include "config.h"
00056 #endif
00057 
00058 #include <stdio.h>
00059 #include <ctype.h>
00060 
00061 #ifdef HAVE_STRING_H
00062 #include <string.h>
00063 #endif
00064 
00065 /*------------------------------------------------------------------
00066  * Gattrib specific includes
00067  *------------------------------------------------------------------*/
00068 #include <libgeda/libgeda.h>       /* geda library fcns  */
00069 #include "../include/struct.h"     /* typdef and struct declarations */
00070 #include "../include/prototype.h"  /* function prototypes */
00071 #include "../include/globals.h"
00072 
00073 #ifdef HAVE_LIBDMALLOC
00074 #include <dmalloc.h>
00075 #endif
00076 
00077 
00078 /*----------------------------------------------------------------*/
00086 /*----------------------------------------------------------------*/
00087 int cmp(STRING_LIST *al, STRING_LIST *bl) {
00088   char *a = al->data;
00089   char *b = bl->data;
00090 
00091   if (al->pos != bl->pos)
00092     return al->pos - bl->pos;
00093 
00094   while (*a && *b)
00095     {
00096       if (isdigit ((int) *a) && isdigit ((int) *b))
00097     {
00098       int ia = atoi (a);
00099       int ib = atoi (b);
00100       if (ia != ib)
00101         return ia - ib;
00102       while (isdigit ((int) *a))
00103         a++;
00104       while (isdigit ((int) *b))
00105         b++;
00106     }
00107       else if (tolower ((int) *a) != tolower ((int) *b))
00108     return tolower ((int) *a) - tolower ((int) *b);
00109       a++;
00110       b++;
00111     }
00112   if (*a)
00113     return 1;
00114   if (*b)
00115     return -1;
00116   return 0;
00117 }
00118 
00119 /*----------------------------------------------------------------*/
00138 /*----------------------------------------------------------------*/
00139 STRING_LIST *listsort(STRING_LIST *list, int is_circular, int is_double) {
00140     STRING_LIST *p, *q, *e, *tail, *oldhead;
00141     int insize, nmerges, psize, qsize, i;
00142 
00143     /*
00144      * Silly special case: if `list' was passed in as NULL, return
00145      * NULL immediately.
00146      */
00147     if (!list)
00148     return NULL;
00149 
00150     insize = 1;
00151 
00152     while (1) {
00153         p = list;
00154     oldhead = list;            /* only used for circular linkage */
00155         list = NULL;
00156         tail = NULL;
00157 
00158         nmerges = 0;  /* count number of merges we do in this pass */
00159 
00160         while (p) {
00161             nmerges++;  /* there exists a merge to be done */
00162             /* step `insize' places along from p */
00163             q = p;
00164             psize = 0;
00165             for (i = 0; i < insize; i++) {
00166                 psize++;
00167         if (is_circular)
00168             q = (q->next == oldhead ? NULL : q->next);
00169         else
00170             q = q->next;
00171                 if (!q) break;
00172             }
00173 
00174             /* if q hasn't fallen off end, we have two lists to merge */
00175             qsize = insize;
00176 
00177             /* now we have two lists; merge them */
00178             while (psize > 0 || (qsize > 0 && q)) {
00179 
00180                 /* decide whether next element of merge comes from p or q */
00181                 if (psize == 0) {
00182             /* p is empty; e must come from q. */
00183             e = q; q = q->next; qsize--;
00184             if (is_circular && q == oldhead) q = NULL;
00185         } else if (qsize == 0 || !q) {
00186             /* q is empty; e must come from p. */
00187             e = p; p = p->next; psize--;
00188             if (is_circular && p == oldhead) p = NULL;
00189         } else if (cmp(p,q) <= 0) {
00190             /* First element of p is lower (or same);
00191              * e must come from p. */
00192             e = p; p = p->next; psize--;
00193             if (is_circular && p == oldhead) p = NULL;
00194         } else {
00195             /* First element of q is lower; e must come from q. */
00196             e = q; q = q->next; qsize--;
00197             if (is_circular && q == oldhead) q = NULL;
00198         }
00199 
00200                 /* add the next element to the merged list */
00201         if (tail) {
00202             tail->next = e;
00203         } else {
00204             list = e;
00205         }
00206         if (is_double) {
00207             /* Maintain reverse pointers in a doubly linked list. */
00208             e->prev = tail;
00209         }
00210         tail = e;
00211             }
00212 
00213             /* now p has stepped `insize' places along, and q has too */
00214             p = q;
00215         }
00216     if (is_circular) {
00217         tail->next = list;
00218         if (is_double)
00219         list->prev = tail;
00220     } else
00221         tail->next = NULL;
00222 
00223         /* If we have done only one merge, we're finished. */
00224         if (nmerges <= 1)   /* allow for nmerges==0, the empty list case */
00225             return list;
00226 
00227         /* Otherwise repeat, merging lists twice the size */
00228         insize *= 2;
00229     }
00230 }
00231 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines