Today at work, I continued to return to this issue, trying to figure it out. I found that your limitations are somewhat confusing, so "have you tried magic?" comment. In the end, I got over the block ...
This can help visualize the problem. Let's start with the ideas in the Julio Moreno code, which are somewhat simplified: go through the list and swap each node with tail data.
ABCDE EBCDA EACDB EABDC EABCD EDBCA EDACB EDABC EDCBA
(At work, I came to the conclusion that the process will not work, but now I have more time, I see that it is). If we then examine its function in more detail, we will see that, in addition to this, it also works recursively. I do not want to visualize the recursive function called from the for loop. This process is clearly not going to win prizes for efficiency.
So, let's see what we can do if we don’t want to limit ourselves to not changing the positions of the node:
ABCDE BCDEA CDEBA DECBA EDCBA
Here we take the tail of node E and remember it. Now take node A and insert it after E, then B and insert it again after E, but before A, going through the whole list, pasting right after E until E becomes the first node (head) of the list. It works, but we are not allowed to do this.
Let's take it one step further and pretend it is a doubly linked list, we support two pointers: one at the beginning of the list and one at the end, and we exchange the data of both, and then increase one and decrement the other, respectively.
ABCDE EBCDA EDCBA
Done already!
So how can we do this with a singly linked list? What do we need to know? How can we step back while moving forward?
Let's start with how we could get the last node by going through the whole list.
ABCDEFGH
And replace them:
HBCDEFGA
and then, if we remember both nodes that we exchanged for data , we can start with B and step until node → points to node, now containing data A.
BCDEFG
and replace them:
GCDEFB FDEC ED
However, I’m still embarrassed with the idea of ​​repeatedly navigating through the list - even if the range of steps is reduced at each iteration of the process. What if we had a LIFO (last in the first) or a stack, as it was known?
ABCDEFGH BCDEFGH ... A CDEFGH ... B DEFGH ... C EFGH ... D FGH ... E GH ... F H ... G...F...E...D...C...B...A
But this is an auxiliary data warehouse, and we do not allow this, but it is not too difficult to understand how LIFO can be implemented using recursive function calls and a linked list. So, how could we move back and forth with a recursive function call and linked list? Do we need an additional parameter? When we get to the end of the list, we still need to know how it starts.
ABCDEFGH A,B ^ return 0 A,C ^ return 0 A,D ^ return 0 A,E ^ swap DE done, return 0 A,F ^ swap CF return D A,G ^ swap BG return C A,H ^ swap AH return B
I have not tested this to prove it, so this may be wrong. I'll check it now and publish the code if necessary. I hope I do not have to edit this post to say that it does not work; -)
EDIT: can confirm that it works.
static lnode* list_private_reverse(lnode* list, lnode* node) { lnode* next = node->next; if (next) { lnode* swap = list_private_reverse(list, next); if (swap) { int c = swap->c; swap->c = node->c; node->c = c; if (swap->next == node || swap->next->next == node) return 0; return swap->next; } return 0; } else { int c = node->c; node->c = list->c; list->c = c; } return list->next; } lnode* list_reverse(lnode* list) { list_private_reverse(list, list); return list; }
list_private_reverse is only called as many times as there are items in the list.