Sorting Double Linked List in place

D. Richard Hipp drh at duke.cs.duke.edu
Sat Nov 10 00:42:11 AEST 1990


Efficient code for in-place sorting a doubly linked list is attached.
------------------------------ cut here -------------------------------------

/*
** An entry in a doubly linked list
*/
typedef struct s_dbllink {
  int key;
  struct s_dbllink *prev, *next;
} dblink;

/*
** Merge sort on a linked list.  Only the "next" links are used -- the
** list is treated as if it were singly linked.
*/
void mergesort(dblink **topptr){
  dblink *left, *right, *top;

  top = *topptr;

  /* Only do the sort if there are 2 or more elements in the list. */
  if( top && top->next ){

    /* Step 1: Break the list into two roughly-equal sized parts. "right"
    ** and "left" will point to the head of each part */
    left = right = 0;
    while( top ){
      dblink *next;
      next = top->next;
      top->next = left;
      left = top;
      top = next;
      if( top ){
        next = top->next;
        top->next = right;
        right = top;
        top = next;
      }
    }
  
    /* Step 2: Recursively call mergesort to sort each half of the list */
    mergesort(&left);
    mergesort(&right);

    /* Step 3: Merge the two halves of the list back together */
    if( left->key<right->key ){  
      *topptr = top = left;
      left = left->next;
    }else{
      *topptr = top = right;
      right = right->next;
    }
    while( left && right ){
      if( left->key<right->key ){
        top->next = left;
        left = left->next;
      }else{
        top->next = right;
        right = right->next;
      }
      top = top->next;
    }
    top->next = left ? left : right;
  }
}

/*
** Sort a doubly linked list
*/
void dblsort(dblink **topptr){
  dblink *p, *x;

  /* Call mergesort to sort the list.  The "prev" links are ignored */
  mergesort(topptr);

  /* Reconnect the "prev" links */
  for(x=*topptr, p=0; x; x=x->next){
    x->prev = p;
    p = x;
  }
}

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

void main(void){
  char line[1000];
  dblink *x, *y;

  x = 0;
  printf("Enter numbers.  ^D to stop input.\n");
  while( fgets(line,1000,stdin) ){
    y = malloc( sizeof(dblink) );
    if( !y ) break;
    y->next = x;
    y->prev = 0;
    y->key = atoi(line);
    if( x ) x->prev = y;
    x = y;
  }
  dblsort(&x);
  printf("---------- forward -------------\n");
  for(y=x; y; y=y->next) printf("%d\n",y->key);
  printf("---------- backward ------------\n");
  for(y=x; y->next; y=y->next);
  for(; y; y=y->prev) printf("%d\n",y->key);
}
#endif



More information about the Comp.lang.c mailing list