recorder/listsort.c
2016-02-24 07:52:19 +01:00

232 lines
5.5 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include "listsort.h"
/* from http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c */
/*
* This file is copyright 2001 Simon Tatham.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
static double cmp(JsonNode * a, JsonNode * b)
{
JsonNode *ta = json_find_member(a, "tst");
JsonNode *tb = json_find_member(b, "tst");
//printf("a=%lf, b=%lf\n", ta->number_, tb->number_);
/* user may have chosen fields without tst */
if (!ta || !tb)
return (0.0);
return ta->number_ - tb->number_;
}
/*
* This is the actual sort function. Notice that it returns the new head of
* the list. (It has to, because the head will not generally be the same
* element after the sort.) So unlike sorting an array, where you can do
*
* sort(myarray);
*
* you now have to do
*
* list = listsort(mylist);
*/
JsonNode *listsort(JsonNode * list, int is_circular, int is_double)
{
JsonNode *p, *q, *e, *tail, *oldhead;
int insize, nmerges, psize, qsize, i;
/*
* Silly special case: if `list' was passed in as NULL, return NULL
* immediately.
*/
if (!list)
return NULL;
insize = 1;
while (1) {
p = list;
oldhead = list; /* only used for circular linkage */
list = NULL;
tail = NULL;
nmerges = 0; /* count number of merges we do in this pass */
while (p) {
nmerges++; /* there exists a merge to be done */
/* step `insize' places along from p */
q = p;
psize = 0;
for (i = 0; i < insize; i++) {
psize++;
if (is_circular)
q = (q->next == oldhead ? NULL : q->next);
else
q = q->next;
if (!q)
break;
}
/*
* if q hasn't fallen off end, we have two lists to
* merge
*/
qsize = insize;
/* now we have two lists; merge them */
while (psize > 0 || (qsize > 0 && q)) {
/*
* decide whether next element of merge comes
* from p or q
*/
if (psize == 0) {
/* p is empty; e must come from q. */
e = q;
q = q->next;
qsize--;
if (is_circular && q == oldhead)
q = NULL;
} else if (qsize == 0 || !q) {
/* q is empty; e must come from p. */
e = p;
p = p->next;
psize--;
if (is_circular && p == oldhead)
p = NULL;
} else if (cmp(p, q) <= 0) {
/*
* First element of p is lower (or
* same); e must come from p.
*/
e = p;
p = p->next;
psize--;
if (is_circular && p == oldhead)
p = NULL;
} else {
/*
* First element of q is lower; e
* must come from q.
*/
e = q;
q = q->next;
qsize--;
if (is_circular && q == oldhead)
q = NULL;
}
/* add the next element to the merged list */
if (tail) {
tail->next = e;
} else {
list = e;
}
if (is_double) {
/*
* Maintain reverse pointers in a
* doubly linked list.
*/
e->prev = tail;
}
tail = e;
}
/*
* now p has stepped `insize' places along, and q has
* too
*/
p = q;
}
if (is_circular) {
tail->next = list;
if (is_double)
list->prev = tail;
} else
tail->next = NULL;
/* If we have done only one merge, we're finished. */
if (nmerges <= 1) /* allow for nmerges==0, the empty
* list case */
return list;
/* Otherwise repeat, merging lists twice the size */
insize *= 2;
}
}
#ifdef TESTING
int main()
{
JsonNode *n, *sorted, *arr = json_mkarray();
JsonNode *o;
o = json_mkobject();
json_append_member(o, "tst", json_mknumber(2));
json_append_member(o, "desc", json_mkstring("dos"));
json_append_element(arr, o);
o = json_mkobject();
json_append_member(o, "tst", json_mknumber(69));
json_append_member(o, "desc", json_mkstring("sixtynine"));
json_append_element(arr, o);
o = json_mkobject();
json_append_member(o, "tst", json_mknumber(14));
json_append_member(o, "desc", json_mkstring("fourteen"));
json_append_element(arr, o);
o = json_mkobject();
json_append_member(o, "tst", json_mknumber(7));
json_append_member(o, "desc", json_mkstring("seven"));
json_append_element(arr, o);
json_foreach(n, arr) {
JsonNode *e = json_find_member(n, "tst");
JsonNode *d = json_find_member(n, "desc");
printf("%lf - %s\n", e->number_, d->string_);
}
listsort(NULL, 0, 0);
sorted = listsort(json_first_child(arr), 0, 0);
sorted = sorted->parent;
printf("------- %s\n", (sorted == arr) ? "SAME" : "different");
json_foreach(n, sorted) {
JsonNode *e = json_find_member(n, "tst");
JsonNode *d = json_find_member(n, "desc");
printf("%lf - %s\n", e->number_, d->string_);
}
json_delete(arr);
return 0;
}
#endif