[comp.lang.c] sorting doubly linked list

olson@aaet.csc.ti.com (Doug Olson) (05/14/91)

I have a number of doubly linked lists of the type s_double_list,
which is defined as:

typedef struct double_list
{
  void *next;
  void *prev;
  char *key;
} s_double_list;


I need an efficient method of sorting these lists based on the key
field. Any help would be greatly appreciated.


Thanks in advance,
--
===========================================================
Doug Olson			| Austin, Texas, 78714-9149
Texas Instruments		| olson@aaet.csc.ti.com
12501 Research Blvd		| MSGID = OLSN
P.O. Box 149149, M/S 2227	|
===========================================================

wirzeniu@kruuna.Helsinki.FI (Lars Wirzenius) (05/14/91)

In article <OLSON.91May13142102@sol.aaet.csc.ti.com> olson@aaet.csc.ti.com (Doug Olson) writes:
>I need an efficient method of sorting these lists based on the key
>field. Any help would be greatly appreciated.

How about using a quicksort, ie. (in pseudocode):

	list quicsort(list) {
		if (list is not empty) {
			divide list into three sublists (less, equal,
				and greater than first element);
			quicksort(less);
			quicksort(greater);
			list = less + equal + greater;
			fix_the_other_links;
		}
		return list;
	}

While sorting, you should ignore the other link, and fix it afterwards
(left as an exercise :-).

I don't know if this is efficient enough, but it might very well be.
-- 
Lars Wirzenius  wirzenius@cc.helsinki.fi

jim@uvmark.uucp (Jim Todhunter) (05/14/91)

In article <OLSON.91May13142102@sol.aaet.csc.ti.com> olson@aaet.csc.ti.com (Doug Olson) writes:
>I have a number of doubly linked lists of the type s_double_list,
>which is defined as:
>
>typedef struct double_list
>{
>  void *next;
>  void *prev;
>  char *key;
>} s_double_list;
>
>
>I need an efficient method of sorting these lists based on the key
>field. Any help would be greatly appreciated.

Not to sound trite, but building your list in sorted order in the first place
would allow you disperse the cost ( O(n2) ) of sorting over the run cycle of
your program.  However, if you must sort this pre-built structure:

  For small lists (less than 100-200 elements), simply pulling each node off the
  list and inserting into a new list should be fast enough ( O(n2) with a small
  overhead cost).

  For larger lists, you might try pulling each node off the list, and building a
  binary tree using next and prev as child pointers.  After the tree has been
  built, you can generate the newly sorted linked list by traversing the tree.
  This technique will provide O(n log n) performance at a modest overhead cost.

The implementation of either of the above methods is fairly simple.
-- 
 James W. Todhunter    |  ..uunet!merk!uvmark!jim
 Vmark Software, Inc.  |  Phone: 508-655-3700
 5 Strathmore Road     |  Fax:   508-655-8395
 Natick, MA  01760     |  Telex: 5101011619 VMARKUNIVERS

shu@acsu.buffalo.edu (Wennie Shu) (05/14/91)

This message is empty.

gwyn@smoke.brl.mil (Doug Gwyn) (05/15/91)

In article <OLSON.91May13142102@sol.aaet.csc.ti.com> olson@aaet.csc.ti.com (Doug Olson) writes:
>I need an efficient method of sorting these lists based on the key
>field. Any help would be greatly appreciated.

Convert the doubly-linked list to a binary search tree (you already
have the link fields needed for that), then (if there is any need to
do so) traverse the tree in inorder, moving the nodes as they are
processed onto the tail of a doubly-linked list.

ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (05/15/91)

In article <1991May14.112315.496@klaava.Helsinki.FI>, wirzeniu@kruuna.Helsinki.FI (Lars Wirzenius) writes:
> In article <OLSON.91May13142102@sol.aaet.csc.ti.com> olson@aaet.csc.ti.com (Doug Olson) writes:
> >I need an efficient method of sorting these lists based on the key
> >field. Any help would be greatly appreciated.
> 
> How about using a quicksort, ie. (in pseudocode):

There are several ways of approaching this problem.
The one which will get you off the ground fastest is
    -- determine the length of the list
    -- allocate a scratch array holding that many pointers
    -- for (i = 0, p = list; p != NULL; i++, p = p->next)
	a[i] = p;	/* i.e. copy the list pointers into the array */
    -- USE THE STANDARD LIBRARY FUNCTION qsort to sort the array
    -- rebuild the list from the array.
    -- release the scratch array
All of this is trivial.

If for some reason you do not want to allocate a scratch array,
or if you need a really efficient sorting algorithm,

	USE MERGE SORT.

Do *not* use quicksort.  The only advantage of quicksort is that it
doesn't need additional workspace, and when you _have_ a linked list
you already have all the workspace you need.  What is more, quicksort
pays for its space saving by being quite noticably *SLOWER* than
merge sort.

Look in any respected algorithms text (Sedgewick, Rivest et al, ...)
to find out how merge sort works.  Merge sort on one way linked lists
is very very simple and rather fast.  To merge sort two way linked lists,
ignore the back links, then rebuild them after you have finished sorting.

Doubly linked lists are seldom needed; what is the task the original
poster is _really_ interested in?
-- 
There is no such thing as a balanced ecology; ecosystems are chaotic.

boyd@prl.dec.com (Boyd Roberts) (05/15/91)

Just add an extra pointer and turn the list into a binary tree and
do an `infix' traversal.  This is the Doug Gwyn prefered method posted
some months ago to a similar request.


Boyd Roberts			boyd@prl.dec.com

``When the going gets wierd, the weird turn pro...''