You're close, but with some silly errors. Check the append operations in the merge step. They're not doing what you think they are. And of course you meant temp = temp->next;
in the splitting loop.
If gdb is overwhelming, adding printf's is a perfectly fine way to go about debugging code like this. Actually you want to write a list printing function and print the sublists at each level of recursion plus the results of the merge step. It's fun to watch. Just be neat and delete all that when you're done.
Here's code that works for reference:
struct listnode *sort(struct listnode *lst) {
if (!lst || !lst->next) return lst;
struct listnode *q = lst, *p = lst->next->next;
while (p && p->next) {
q = q->next;
p = p->next->next;
}
struct listnode *mid = q->next;
q->next = NULL;
struct listnode *fst = sort(lst), *snd = sort(mid);
struct listnode rtn[1], *tail = rtn;
while (fst && snd) {
if (fst->key < snd->key) {
tail->next = fst;
tail = fst;
fst = fst->next;
} else {
tail->next = snd;
tail = snd;
snd = snd->next;
}
}
while (fst) {
tail->next = fst;
tail = fst;
fst = fst->next;
}
while (snd) {
tail->next = snd;
tail = snd;
snd = snd->next;
}
tail->next = NULL;
return rtn->next;
}
On my old MacBook this sorts 10 million random integers in a bit over 4 seconds, which doesn't seem too bad.
You can also put the append operation in a macro and make this quite concise:
struct listnode *sort(struct listnode *lst) {
if (!lst || !lst->next) return lst;
struct listnode *q = lst, *p = lst->next->next;
while (p && p->next) {
q = q->next;
p = p->next->next;
}
struct listnode *mid = q->next;
q->next = NULL;
struct listnode *fst = sort(lst), *snd = sort(mid);
struct listnode rtn[1], *tail = rtn;
#define APPEND(X) do { tail->next = X; tail = X; X = X->next; } while (0)
while (fst && snd) if (fst->key < snd->key) APPEND(fst); else APPEND(snd);
while (fst) APPEND(fst);
while (snd) APPEND(snd);
tail->next = NULL;
return rtn->next;
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…