Mergesort is more natural to implement for linked lists, but you can do quicksort very nicely. Below is one in C I've used in several applications.
It's a common myth that you can't do Quicksort efficiently with lists. This just isn't true, although careful implementation is required.
To answer your question, the Quicksort algorithm for lists is essentially the same as for arrays. Pick a pivot (the code below uses the head of the list), partition into two lists about the pivot, then recursively sort those lists and append the results with pivot in the middle. What is a bit non-obvious is that the append operation can be done with no extra pass over the list if you add a parameter for a list to be appended as-is at the tail of the sorted result. In the base case, appending this list requires no work.
It turns out that if comparisons are cheap, mergesort tends to run a little faster because quicksort spends more time fiddling with pointers. However if comparisons are expensive, then quicksort often runs faster because it needs fewer of them.
If NODE *list
is the head of the initial list, then you can sort it with
qs(list, NULL, &list);
Here is the sort code. Note a chunk of it is an optimization for already-sorted lists. This optimization can be deleted if these cases are infrequent.
void qs(NODE * hd, NODE * tl, NODE ** rtn)
{
int nlo, nhi;
NODE *lo, *hi, *q, *p;
/* Invariant: Return head sorted with `tl' appended. */
while (hd != NULL) {
nlo = nhi = 0;
lo = hi = NULL;
q = hd;
p = hd->next;
/* Start optimization for O(n) behavior on sorted and reverse-of-sorted lists */
while (p != NULL && LEQ(p, hd)) {
hd->next = hi;
hi = hd;
++nhi;
hd = p;
p = p->next;
}
/* If entire list was ascending, we're done. */
if (p == NULL) {
*rtn = hd;
hd->next = hi;
q->next = tl;
return;
}
/* End optimization. Can be deleted if desired. */
/* Partition and count sizes. */
while (p != NULL) {
q = p->next;
if (LEQ(p, hd)) {
p->next = lo;
lo = p;
++nlo;
} else {
p->next = hi;
hi = p;
++nhi;
}
p = q;
}
/* Recur to establish invariant for sublists of hd,
choosing shortest list first to limit stack. */
if (nlo < nhi) {
qs(lo, hd, rtn);
rtn = &hd->next;
hd = hi; /* Eliminated tail-recursive call. */
} else {
qs(hi, tl, &hd->next);
tl = hd;
hd = lo; /* Eliminated tail-recursive call. */
}
}
/* Base case of recurrence. Invariant is easy here. */
*rtn = tl;
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…