From 32649d6af01092580411bb14a0484b02594a8eea Mon Sep 17 00:00:00 2001 From: Dominik Friedrich <D.Friedrich@bull.de> Date: Mon, 17 Jun 2013 16:28:24 -0700 Subject: [PATCH] Make the list_sort use a merge sort with is n log n instead of the n^2 algo we have previously used. --- src/common/list.c | 101 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 31 deletions(-) diff --git a/src/common/list.c b/src/common/list.c index a016c414db9..e40b37e53c9 100644 --- a/src/common/list.c +++ b/src/common/list.c @@ -529,51 +529,90 @@ list_flush (List l) return(n); } - void list_sort (List l, ListCmpF f) { -/* Note: Time complexity O(n^2). - */ - ListNode *pp, *ppPrev, *ppPos, pTmp; - ListIterator i; + ListIterator it; + + ListNode p, q, e, tail, head; + int insize, nmerges, psize, qsize, i; assert(l != NULL); assert(f != NULL); list_mutex_lock(&l->mutex); assert(l->magic == LIST_MAGIC); + head = l->head; if (l->count > 1) { - ppPrev = &l->head; - pp = &(*ppPrev)->next; - while (*pp) { - if (f((*pp)->data, (*ppPrev)->data) < 0) { - ppPos = &l->head; - while (f((*pp)->data, (*ppPos)->data) >= 0) - ppPos = &(*ppPos)->next; - pTmp = (*pp)->next; - (*pp)->next = *ppPos; - *ppPos = *pp; - *pp = pTmp; - if (ppPrev == ppPos) - ppPrev = &(*ppPrev)->next; - } - else { - ppPrev = pp; - pp = &(*pp)->next; - } - } - l->tail = pp; - - for (i=l->iNext; i; i=i->iNext) { - assert(i->magic == LIST_MAGIC); - i->pos = i->list->head; - i->prev = &i->list->head; - } + insize=1; + while(1) { + p = head; + head = NULL; + tail = NULL; + + + nmerges = 0; + while(p) { + nmerges++; + q = p; + + psize=0; + for (i = 0; i < insize; i++) { + psize++; + q = q->next; + + if (!q) break; + } + qsize = insize; + while (psize > 0 || (qsize > 0 && q)) { + if (psize == 0) { + e = q; + q = q->next; + qsize--; + } else if (qsize == 0 || !q ) { + e = p; + p = p->next; + psize--; + } else if (f(p->data,q->data) < 0) { + e = p; + p = p->next; + psize--; + } else { + e = q; + q = q->next; + qsize--; + } + if (tail) { + tail->next = e; + } else { + head = e; + } + tail = e; + } + p = q; + + } + tail->next = NULL; + if(nmerges <= 1) { + l->head = head; + l->tail = &tail; + for (it=l->iNext; it; it=it->iNext) { + assert(it->magic == LIST_MAGIC); + it->pos = it->list->head; + it->prev = &it->list->head; + } + + list_mutex_unlock(&l->mutex); + return; + } + insize *=2; + } } + list_mutex_unlock(&l->mutex); return; } + void * list_push (List l, void *x) { -- GitLab