Sorting Double Linked List in place

Paul N. Hilfinger hilfingr at rama.cs.cornell.edu
Sat Nov 10 18:33:30 AEST 1990


I found that the following code (which uses O(lg(N)) extra space, but
so what) works pretty well.  On my DECSTATION 3100 using gcc -O, it
runs about 2.5 times faster than another posted mergesort on one set
of 24000 integers, but what's a constant factor among colleagues?

The algorithm uses a binomial comb to collect merged sublists.

Paul Hilfinger

------------------------cut here----------------------------------------------

#include <stdlib.h>
#include <stdio.h>

/*
** An entry in a doubly linked list (from D. Richard Hipp)
*/
typedef struct s_dbllink {
  int key;
  struct s_dbllink *prev, *next;
} dblink;

#define NEXT(L) ((L) -> next)
#define PREV(L) ((L) -> prev)
#define KEY(L)  ((L) -> key)


#define LG_MAX_LIST 48

static dblink *merge(dblink *L0, dblink *L1);

void dblSort1(dblink **LP)
    /* Assumptions:							*/
    /*     The list *LP has no more than 2**LG_MAX_LIST elements.	*/
    /* Effect:								*/
    /*     Destructively sorts the list pointed to by *LP in		*/
    /*     increasing lexicographic order by key, setting *LP to point 	*/
    /*     to the head of the resulting list.  			        */
{
    dblink *BIN[LG_MAX_LIST]; /* List headers */
    dblink *L;
    int i;

    for (i = 0; i < LG_MAX_LIST; i += 1)
	BIN[i] = NULL;

    L = *LP;
    while (L != NULL) {
	dblink *M = L;

	L = NEXT(L);
	NEXT(M) = NULL;
	
	for (i = 0; BIN[i] != NULL; i += 1) {
	    M = merge(BIN[i], M);
	    BIN[i] = NULL;
	}
	BIN[i] = M;
    }

    for (L = BIN[0], i = 1; i < LG_MAX_LIST; i += 1)
	L = merge(BIN[i], L);

	/* Re-establish back links. */
    if (L != NULL) {
	dblink *P;

	L -> prev = NULL;
	for (P = L; NEXT(P) != NULL; P = NEXT(P))
	    PREV(NEXT(P)) = P;
    }

    *LP = L;
}

static dblink *merge(dblink *L0, dblink *L1)
    /* Assumptions:							*/
    /*     L0, L1 are sorted in increasing order by key.		*/
    /* Effects:								*/
    /*     Destructively merges L0 and L1 into increasing order.	*/
    /*     Equal elements in L0 are placed before ones in L1.		*/
    /*     Returns a pointer to the header of the list.			*/
    /*     PREV values are unreferenced (and hence, invalid).           */
{
    dblink **last;
    dblink *head;

    last = &head;

    while (L0 != NULL && L1 != NULL) {
	if (KEY(L0) <= KEY(L1)) {
	    *last = L0;
	    L0 = NEXT(L0);
	}
	else {
	    *last = L1;
	    L1 = NEXT(L1);
	}

	last = &NEXT(*last);
    }

    if (L0 == NULL)
	*last = L1;
    else
	*last = L0;

    return head;
}



More information about the Comp.lang.c mailing list