1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
|
/*
------------------------------------------------------------------------------
A license is hereby granted to reproduce this software source code and
to create executable versions from this source code for personal,
non-commercial use. The copyright notice included with the software
must be maintained in all copies produced.
THIS PROGRAM IS PROVIDED "AS IS". THE AUTHOR PROVIDES NO WARRANTIES
WHATSOEVER, EXPRESSED OR IMPLIED, INCLUDING WARRANTIES OF
MERCHANTABILITY, TITLE, OR FITNESS FOR ANY PARTICULAR PURPOSE. THE
AUTHOR DOES NOT WARRANT THAT USE OF THIS PROGRAM DOES NOT INFRINGE THE
INTELLECTUAL PROPERTY RIGHTS OF ANY THIRD PARTY IN ANY COUNTRY.
Copyright (c) 1995, John Conover, All Rights Reserved.
Comments and/or bug reports should be addressed to:
john@johncon.com (John Conover)
------------------------------------------------------------------------------
qsortlist.c, quick sort a linked list
a stable quick sort for linked lists
Tail recursion is used to limit recursion to ln (n) levels, which cuts
the number of recursive calls by a factor of 2. Sorting time will be
proportional to n ln (n).
Note: this algorithm uses double level indirection-modifications must
be made with meticulous care.
The algorithm is as follows (the pivot is the dividing line between
high and low sub lists in a sub list):
append each item in the beginning of a sub list to the high or low
sub list, (at the completion of this loop, the low sub list has
already been linked into the calling context at the beginning of
the sub list)
the pivot element is appended after the low sub list, and the end
of the high sublist is then linked into the calling context sub
list
the beginning of the high sub list is finally appended after the
pivot
Note: although the re linking must be done in this order, the order of
sorting the sub lists is not critical.
Usage is to typedef LIST as the structure element to be sorted, and
the token "list" as a reference to a LIST type of element, for
example:
typedef struct my_struct
{
.
.
.
int count;
struct my_struct *next;
} MYSTRUCT;
typedef MYSTRUCT LIST;
typedef LIST *list;
where the tokens "LIST" and "list" are used internal to qsortlist
module.
Additionally, the structure element must have an integer element,
"count," (in this example case, which is the sort key-but could
conceivably be any type, or token name,) and a reference element to
the next structure in the list, with a token name of "next," which is
used internal to the qsortlist module.
It is also necessary to include a comparison utility, either by
#define or function, that can compare the key elements in two list
elements. For example:
#define element_comp(x,y) (x)->count - (y)->count
The comparison utility must have the token name "element_comp," which
is used internal to the qsortlist module, and has the same return
value operations as strcmp(2), ie., if the first argument is lexically
larger, the return should be positive, and if it is smaller, it should
be negative, and if equal, zero is returned. Reverse the scenario for
a reverse sort on lexical order.
For a detailed description of quicksorting linked lists, see
"Quicksorting Linked Lists," Jeff Taylor, "C Gazette," Volume 5,
Number 6, October/November, 1991, ISSN 0897-4055, P.O. Box 70167,
Eugene, OR 97401-0110. Published by Oakley Publishing Company, 150
N. 4th Street, Springfield, OR 97477-5454.
The first argument references the first element in the linked list,
the second argument is null for linear linked lists, or references the
final element in a circularly linked list. The sort is stable, meaning
that elements with the same key value will remain in the same relative
order after the sorting process.
Returns nothing, but the linked list's next elements are rearranged
such that the list elements are in sorted order on the key.
To test this module, compile the module source with -DTEST_QSORTLIST
$Revision: 1.0 $
$Date: 1995/04/22 05:13:18 $
$Id: qsortlist.c,v 1.0 1995/04/22 05:13:18 john Exp $
$Log: qsortlist.c,v $
* Revision 1.0 1995/04/22 05:13:18 john
* Initial revision
*
*/
#include "rel.h"
#ifndef LINT /* include rcsid only if not running lint */
static char rcsid[] = "$Id: qsortlist.c,v 1.0 1995/04/22 05:13:18 john Exp $"; /* module version */
static char rcsid_h[] = QSORTLIST_H_ID; /* module include version */
#endif
#ifdef __STDC__
void qsortlist (list *top, list bottom)
#else
void qsortlist (top, bottom)
list *top;
list bottom;
#endif
{
int n; /* sub list's length, greater than 0 means high sub list is larger, less than 0 means lower sub list is larger */
list *high, /* reference to top of sub list */
high_list, /* reference to top of list */
*low, /* reference to bottom of sub list */
pivot, /* reference to pivot element for list sub division */
previous; /* reference to previous element to pivot element */
while (*top != bottom) /* starting at the top of the list, when the end of the list is reached, this recursion is finished */
{
previous = pivot = *top; /* save the top of the list */
low = top; /* save the reference to the top of the list */
high = &high_list; /* reference the high list */
n = 0; /* sub list has no length */
while ((previous = previous->next) != bottom) /* scan the list to find the partition-this is the pivot value */
{
if (element_comp (previous, pivot) <= 0) /* compare this element's value with the value in the pivot */
{
*low = previous; /* if it less than or equal, the low value references this element */
low = &previous->next; /* and the low value references the next element in the list */
n--; /* decrement the sub list's length */
}
else
{
*high = previous; /* if it is higher, the high value references this element */
high = &previous->next; /* and the high value references the next element in the list */
n++; /* increment the sub list's length */
}
}
*low = pivot; /* reassemble with pivot between parts, reference the pivot element */
*high = bottom; /* reference the end of the list */
pivot->next = high_list; /* the pivot element's list references the top of the list */
if (n > 0) /* sort sublists-always sort the larger sub list: is the high part is larger? */
{
qsortlist (top, pivot); /* yes, recurse on lower part */
top = &pivot->next; /* and the top of the list references the element past the pivot element */
}
else
{
qsortlist (&pivot->next, bottom); /* no, recurse on high part */
bottom = pivot; /* and the end of the list references the pivot */
}
}
}
#ifdef TEST_QSORTLIST
/*
simple exerciser for testing qsortlist (); sort the numbers listed on
the command line, and print the sorted numbers to stdout; ignore the:
declared global, could be static
qsortlist qsortlist.c(xxx)
from lint
*/
#ifdef __STDC__
int main (int argc, char *argv[])
#else
int main (argc, argv)
int argc;
char *argv[];
#endif
{
list mylist, /* the list to be sorted */
ref; /* temporary reference to list element */
if (argc < 2) /* enough arguments? */
{
(void) printf ("usage: arg arg arg ...\n"); /* no, print the usage */
exit (1); /* and exit */
}
mylist = (list) 0; /* null the list reference */
for (argc--; argc > 0; argc--) /* for each argument on the command line */
{
if ((ref = (LIST *) malloc (sizeof (LIST))) == (LIST *) 0) /* allocate a list element */
{
(void) fprintf (stderr, "error allocating memory\n"); /* couldn't allocate the list element, print the error */
exit (1); /* and exit */
}
ref->count = atoi (argv[argc]); /* store the key element value */
ref->next = mylist; /* add the element to the list */
mylist = ref; /* new list head */
}
qsortlist (&mylist, (list) 0); /* sort the list */
for (ref = mylist; ref; ref = ref->next) /* for each element on the list */
{
(void) printf ("%d\n", ref->count); /* print the element's key value */
}
exit (0); /* success */
#ifdef LINT /* include only if running lint */
return (0); /* for LINT formality */
#endif
}
#endif
|