Reputation: 3945
I still struggle with the recursion technique to solve the problem. I know there are nicer ways to solve my problem below of reversing a linked list. Most of the ways that I have seen, start to reverse the pointers by going from the head to the tail, either by using iteration or recursion.
I am trying for interest to reverse the list by first finding the last node in the list recursively and then changing the pointers everytime the function returns.
What am I doing wrong below exactly? Or will this method even work , without the need to pass more parameters to the recursive function? Thanks in advance for your help.
struct Node
{
int data;
struct Node *next;
};
Node* Reverse(Node *head)
{
static Node* firstNode = head;
// if no list return head
if (head == NULL)
{
return head;
}
Node* prev = NULL;
Node* cur = head;
// reached last node in the list, return head
if (cur->next == NULL)
{
head = cur;
return head;
}
prev = cur;
cur = cur->next;
Reverse(cur)->next = prev;
if (cur == firstNode)
{
cur->next = NULL;
return head;
}
return cur;
}
EDIT : Another attempt
Node* ReverseFromTail(Node* prev, Node* cur, Node** head);
Node* ReverseInit(Node** head)
{
Node* newHead = ReverseFromTail(*head, *head, head);
return newHead;
}
Node* ReverseFromTail(Node* prev, Node* cur, Node** head)
{
static int counter = 0;
counter++;
// If not a valid list, return head
if (head == NULL)
{
return *head;
}
// Reached end of list, start reversing pointers
if (cur->next == NULL)
{
*head = cur;
return cur;
}
Node* retNode = ReverseFromTail(cur, cur->next, head);
retNode->next = cur;
// Just to force termination of recursion when it should. Not a permanent solution
if (counter == 3)
{
cur->next = NULL;
return *head;
}
return retNode;
}
Finally Solved it :
Node* NewestReverseInit(Node* head)
{
// Invalid List, return
if (!head)
{
return head;
}
Node* headNode = NewestReverse(head, head, &head);
return headNode;
}
Node* NewestReverse(Node *cur, Node* prev, Node** head)
{
// reached last node in the list, set new head and return
if (cur->next == NULL)
{
*head = cur;
return cur;
}
NewestReverse(cur->next, cur, head)->next = cur;
// Returned to the first node where cur = prev from initial call
if (cur == prev)
{
cur->next = NULL;
return *head;
}
return cur;
}
Upvotes: 1
Views: 1425
Reputation: 5222
It can be done. The key in understanding recursion is What is the starting point?
Usually I create a "starting" function which prepares the first call. Sometimes it is a separate function (like in non OO implemnatation at bottom). Sometimes it's just a special first call (like in example below).
Also the key is in remembering variables before they change and what is the new head
.
The new head
is the last element of the list. So You have to get it up from the bottom of the list.
The next
element is always your parent.
Then the trick is to do everything in the correct order.
Node* Reverse( Node* parent) // Member function of Node.
{
Node* new_head = next ? next->Reverse( this )
: this;
next = parent;
return new_head;
}
You call the function with: var.Reverse( nullptr);
Example:
int main()
{
Node d{ 4, nullptr };
Node c{ 3, &d };
Node b{ 2, &c };
Node a{ 1, &b };
Node* reversed = a.Reverse( nullptr );
}
So what is happening here?
First we create a linked list:
a->b->c->d->nullptr
Then the function calls:
a.Reverse(nullptr)
is called.Reverse
on the next node b.Reverse
with parent a
.Reverse
on the next node c.Reverse
with parent b
.Reverse
on the next node d.Reverse
with parent c
.d
doesn't have next
node so it says that the new head is itself.d
's next
is now it's parent c
d
returns itself as the new_head
.c
: new_head
returned from d
is d
c
's next
is now it's parent b
c
returns the new_head
it recieved from d
b
: new_head
returned from c
is d
b
's next
is now it's parent a
b
returns the new_head
it recieved from c
a
: new_head
returned from b
is d
a
's next
is now it's parent nullptr
a
returns the new_head
it recieved from b
d
is returnedNon object oriented implementation;
Node* reverse_impl(Node* parent)
{
Node* curr = parent->next;
Node* next = curr->next;
Node* new_head = next ? reverse_impl( curr )
: curr;
curr->next = parent;
return new_head;
}
Node* reverse(Node* start)
{
if ( !start )
return nullptr;
Node* new_head = reverse_impl( start );
start->next = nullptr;
return new_head;
}
Upvotes: 3
Reputation: 56
Here's a full implementation I wrote in 5 minutes:
#include <stdio.h>
struct Node
{
int data;
struct Node *next;
};
struct Node* Reverse(struct Node *n)
{
static struct Node *first = NULL;
if(first == NULL)
first = n;
// reached last node in the list
if (n->next == NULL)
return n;
Reverse(n->next)->next = n;
if(n == first)
{
n->next = NULL;
first = NULL;
}
return n;
}
void linked_list_walk(struct Node* n)
{
printf("%d", n->data);
if(n->next)
linked_list_walk(n->next);
else
printf("\n");
}
int main()
{
struct Node n[10];
int i;
for(i=0;i<10;i++)
{
n[i].data = i;
n[i].next = n + i + 1;
}
n[9].next = NULL;
linked_list_walk(n);
Reverse(n);
linked_list_walk(n+9);
}
Output:
0123456789
9876543210
Upvotes: 0
Reputation: 62563
I will not give you the code, I will give you the idea. You can implement the idea in the code.
The key to all recursion problems is to figure out two cases: repetition step and end case. Once you do this, it works almost as if magically.
Applying this principle to reversing a linked list:
head
), and than adding the head as the last element of the list. Return value would be the same as a return value of the recursive call you just made.Upvotes: 4