|
Packit |
e8bc57 |
#include "config.h"
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
#include <stdio.h>
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/*
|
|
Packit |
e8bc57 |
* Demonstration code for sorting a linked list.
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* The algorithm used is Mergesort, because that works really well
|
|
Packit |
e8bc57 |
* on linked lists, without requiring the O(N) extra space it needs
|
|
Packit |
e8bc57 |
* when you do it on arrays.
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* This code can handle singly and doubly linked lists, and
|
|
Packit |
e8bc57 |
* circular and linear lists too. For any serious application,
|
|
Packit |
e8bc57 |
* you'll probably want to remove the conditionals on `is_circular'
|
|
Packit |
e8bc57 |
* and `is_double' to adapt the code to your own purpose.
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
*/
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/*
|
|
Packit |
e8bc57 |
* This file is copyright 2001 Simon Tatham.
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* Permission is hereby granted, free of charge, to any person
|
|
Packit |
e8bc57 |
* obtaining a copy of this software and associated documentation
|
|
Packit |
e8bc57 |
* files (the "Software"), to deal in the Software without
|
|
Packit |
e8bc57 |
* restriction, including without limitation the rights to use,
|
|
Packit |
e8bc57 |
* copy, modify, merge, publish, distribute, sublicense, and/or
|
|
Packit |
e8bc57 |
* sell copies of the Software, and to permit persons to whom the
|
|
Packit |
e8bc57 |
* Software is furnished to do so, subject to the following
|
|
Packit |
e8bc57 |
* conditions:
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* The above copyright notice and this permission notice shall be
|
|
Packit |
e8bc57 |
* included in all copies or substantial portions of the Software.
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
e8bc57 |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
Packit |
e8bc57 |
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
e8bc57 |
* NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
|
|
Packit |
e8bc57 |
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit |
e8bc57 |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
Packit |
e8bc57 |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
Packit |
e8bc57 |
* SOFTWARE.
|
|
Packit |
e8bc57 |
*/
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
#include "listsort.h"
|
|
Packit |
e8bc57 |
typedef unsigned char byte;
|
|
Packit |
e8bc57 |
#include "word.h"
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
#ifdef TEST
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
static int cmp(const element *a, const element *b);
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
static int cmp(const element *a, const element *b) {
|
|
Packit |
e8bc57 |
return a->i - b->i;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
#endif
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/*
|
|
Packit |
e8bc57 |
* This is the actual sort function. Notice that it returns the new
|
|
Packit |
e8bc57 |
* head of the list. (It has to, because the head will not
|
|
Packit |
e8bc57 |
* generally be the same element after the sort.) So unlike sorting
|
|
Packit |
e8bc57 |
* an array, where you can do
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* sort(myarray);
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* you now have to do
|
|
Packit |
e8bc57 |
*
|
|
Packit |
e8bc57 |
* list = listsort(mylist);
|
|
Packit |
e8bc57 |
*/
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
element *listsort(element *list, fcn_compare *compare) {
|
|
Packit |
e8bc57 |
element *p, *q, *e, *tail;
|
|
Packit |
e8bc57 |
int insize, nmerges, psize, qsize, i;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/*
|
|
Packit |
e8bc57 |
* Silly special case: if `list' was passed in as NULL, return
|
|
Packit |
e8bc57 |
* NULL immediately.
|
|
Packit |
e8bc57 |
*/
|
|
Packit |
e8bc57 |
if (!list)
|
|
Packit |
e8bc57 |
return NULL;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
insize = 1;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
while (1) {
|
|
Packit |
e8bc57 |
p = list;
|
|
Packit |
e8bc57 |
list = NULL;
|
|
Packit |
e8bc57 |
tail = NULL;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
nmerges = 0; /* count number of merges we do in this pass */
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
while (p) {
|
|
Packit |
e8bc57 |
nmerges++; /* there exists a merge to be done */
|
|
Packit |
e8bc57 |
/* step `insize' places along from p */
|
|
Packit |
e8bc57 |
q = p;
|
|
Packit |
e8bc57 |
psize = 0;
|
|
Packit |
e8bc57 |
for (i = 0; i < insize; i++) {
|
|
Packit |
e8bc57 |
psize++;
|
|
Packit |
e8bc57 |
q = q->next;
|
|
Packit |
e8bc57 |
if (!q) break;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/* if q hasn't fallen off end, we have two lists to merge */
|
|
Packit |
e8bc57 |
qsize = insize;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/* now we have two lists; merge them */
|
|
Packit |
e8bc57 |
while (psize > 0 || (qsize > 0 && q)) {
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/* decide whether next element of merge comes from p or q */
|
|
Packit |
e8bc57 |
if (psize == 0) {
|
|
Packit |
e8bc57 |
/* p is empty; e must come from q. */
|
|
Packit |
e8bc57 |
e = q; q = q->next; qsize--;
|
|
Packit |
e8bc57 |
} else if (qsize == 0 || !q) {
|
|
Packit |
e8bc57 |
/* q is empty; e must come from p. */
|
|
Packit |
e8bc57 |
e = p; p = p->next; psize--;
|
|
Packit |
e8bc57 |
} else if (compare(p,q) <= 0) {
|
|
Packit |
e8bc57 |
/* First element of p is lower (or same);
|
|
Packit |
e8bc57 |
* e must come from p. */
|
|
Packit |
e8bc57 |
e = p; p = p->next; psize--;
|
|
Packit |
e8bc57 |
} else {
|
|
Packit |
e8bc57 |
/* First element of q is lower; e must come from q. */
|
|
Packit |
e8bc57 |
e = q; q = q->next; qsize--;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/* add the next element to the merged list */
|
|
Packit |
e8bc57 |
if (tail) {
|
|
Packit |
e8bc57 |
tail->next = e;
|
|
Packit |
e8bc57 |
} else {
|
|
Packit |
e8bc57 |
list = e;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
tail = e;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/* now p has stepped `insize' places along, and q has too */
|
|
Packit |
e8bc57 |
p = q;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
tail->next = NULL;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/* If we have done only one merge, we're finished. */
|
|
Packit |
e8bc57 |
if (nmerges <= 1) /* allow for nmerges==0, the empty list case */
|
|
Packit |
e8bc57 |
return list;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/* Otherwise repeat, merging lists twice the size */
|
|
Packit |
e8bc57 |
insize *= 2;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
/*
|
|
Packit |
e8bc57 |
* Small test rig with three test orders. The list length 13 is
|
|
Packit |
e8bc57 |
* chosen because that means some passes will have an extra list at
|
|
Packit |
e8bc57 |
* the end and some will not.
|
|
Packit |
e8bc57 |
*/
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
#ifdef TEST
|
|
Packit |
e8bc57 |
int main(void) {
|
|
Packit |
e8bc57 |
#define n 13
|
|
Packit |
e8bc57 |
element k[n], *head, *p;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
int order[][n] = {
|
|
Packit |
e8bc57 |
{ 0,1,2,3,4,5,6,7,8,9,10,11,12 },
|
|
Packit |
e8bc57 |
{ 6,2,8,4,11,1,12,7,3,9,5,0,10 },
|
|
Packit |
e8bc57 |
{ 12,11,10,9,8,7,6,5,4,3,2,1,0 },
|
|
Packit |
e8bc57 |
};
|
|
Packit |
e8bc57 |
unsigned int i, j;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
for (j = 0; j < n; j++)
|
|
Packit |
e8bc57 |
k[j].i = j;
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
listsort(NULL, cmp, 0, 0);
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
for (i = 0; i < sizeof(order)/sizeof(*order); i++) {
|
|
Packit |
e8bc57 |
int *ord = order[i];
|
|
Packit |
e8bc57 |
head = &k[ord[0]];
|
|
Packit |
e8bc57 |
for (j = 0; j < n; j++) {
|
|
Packit |
e8bc57 |
if (j == n-1)
|
|
Packit |
e8bc57 |
k[ord[j]].next = NULL;
|
|
Packit |
e8bc57 |
else
|
|
Packit |
e8bc57 |
k[ord[j]].next = &k[ord[j+1]];
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
printf("before:");
|
|
Packit |
e8bc57 |
p = head;
|
|
Packit |
e8bc57 |
do {
|
|
Packit |
e8bc57 |
printf(" %d", p->i);
|
|
Packit |
e8bc57 |
p = p->next;
|
|
Packit |
e8bc57 |
} while (p != NULL);
|
|
Packit |
e8bc57 |
printf("\t");
|
|
Packit |
e8bc57 |
head = listsort(head, cmp);
|
|
Packit |
e8bc57 |
printf(" after:");
|
|
Packit |
e8bc57 |
p = head;
|
|
Packit |
e8bc57 |
do {
|
|
Packit |
e8bc57 |
printf(" %d", p->i);
|
|
Packit |
e8bc57 |
p = p->next;
|
|
Packit |
e8bc57 |
} while (p != NULL);
|
|
Packit |
e8bc57 |
printf("\n");
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
printf("\n");
|
|
Packit |
e8bc57 |
|
|
Packit |
e8bc57 |
return 0;
|
|
Packit |
e8bc57 |
}
|
|
Packit |
e8bc57 |
#endif
|