Mergesort is more naturally implemented for linked lists, but you can do quicksort very nicely. Below is one of them that I used in several applications.
This is a common myth that you cannot efficiently execute Quicksort with lists. This is simply not true, although careful implementation is required.
To answer your question, the Quicksort algorithm for lists is essentially the same as for arrays. Select the bar (the code below uses the head of the list), split into two lists about the code, then sort these lists recursively and add the results with the center in the middle. What is a little non-obvious is that the add operation can be performed without additional passing over the list if you add an option for the list to be added as-is at the tail of the sorted result. In the basic case, adding this list does not require work.
It turns out that if the comparison is cheap, the merge is usually a little faster, because quicksort spends more time looking for pointers. However, if comparisons are expensive, quicksort often works faster because it requires less.
If NODE *list is the head of the original list, you can sort it using
qs(list, NULL, &list);
Here is the sort code. Note that this is an optimization for already sorted lists. This optimization can be removed if these cases are infrequent.
void qs(NODE * hd, NODE * tl, NODE ** rtn) { int nlo, nhi; NODE *lo, *hi, *q, *p; while (hd != NULL) { nlo = nhi = 0; lo = hi = NULL; q = hd; p = hd->next; while (p != NULL && LEQ(p, hd)) { hd->next = hi; hi = hd; ++nhi; hd = p; p = p->next; } if (p == NULL) { *rtn = hd; hd->next = hi; q->next = tl; return; } 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; } if (nlo < nhi) { qs(lo, hd, rtn); rtn = &hd->next; hd = hi; } else { qs(hi, tl, &hd->next); tl = hd; hd = lo; } } *rtn = tl; }