简体   繁体   中英

Reversing a linkedlist recursively in c

The following code works fine when head is sent as a parameter to it. As I am new to C, I couldn't understand how it works. Help me out please.

struct node *recursiveReverseLL(struct node *list)
{
    struct node *revHead;
    if (list == NULL || list->link == NULL)
    {
        return list;
    }

    revHead = recursiveReverseLL(list->link);
    list->link->link = list;
    list->link = NULL; 

    return revHead;
}

I dont know how the links are provided using those recursive calls. ie) if the links are as,

1 -> 2 -> 3 -> 4 

then hw is it changed as,

4 -> 3 -> 2 -> 1

The general recursive algorithm for this is:

  1. Divide the list in 2 parts - first node and rest of the list.
  2. Recursively call reverse for the rest of the linked list.
  3. Link rest to first .
  4. Fix head pointer

Here is the code with inline comments:

struct node* recursiveReverseLL(struct node* first){

   if(first == NULL) return NULL; // list does not exist.

   if(first->link == NULL) return first; // list with only one node.

   struct node* rest = recursiveReverseLL(first->link); // recursive call on rest.

   first->link->link = first; // make first; link to the last node in the reversed rest.

   first->link = NULL; // since first is the new last, make its link NULL.

   return rest; // rest now points to the head of the reversed list.
}

I hope this picture will make things clearer:

图像
(source: geeksforgeeks.org )
.

Alternate solution :

struct node *head;
void reverse(struct node *prev, struct node *cur)
{
   if(cur){
      reverse(cur,cur->link);
      cur->link = prev;
    }
    else{
      head = prev;
    }
}

In main, call reverse(NULL,head);

/* Reverses a linked list, returns head of reversed list
*/
NodePtr reverseList(NodePtr curr) {
    if (curr == NULL || curr->next == NULL) return curr; // empty or single element case

    NodePtr nextElement = curr->next;
    curr->next = NULL;
    NodePtr head = reverseList(nextElement);
    nextElement->next = curr;
    return head;
}

Another solution:

struct node *reverse_recur(struct node *temp)
{
    if(temp->link==NULL)
    {
        return temp;
    }

    struct node *temp1=temp->link;

    temp->link=NULL;

    return (reverse_recur(temp1)->link=temp);

}

Let the linked list be 1-> 2 -> 3 ->4

the function in c is--

struct linked_node * reverse_recursive(struct linked_node * head)
{
struct linked_node * first;/*stores the address of first node of the linked
list passed to function*/
struct linked_node * second;/* stores the address of second node of the
linked list passed to function*/
struct linked_node * rev_head;/*stores the address of last node of initial 
linked list. It also becomes the head of the reversed linked list.*/
//initalizing first and second
first=head;
second=head->next;
//if the linked list is empty then returns null
if(first=NULL)
   return(NULL);
/* if the linked list passed to function contains just 1 element, then pass
address of that element*/
if(second==NULL)
   return(first);
/*In the linked list passed to function, make the next of first element 
 NULL. It will eventually (after all the recursive calls ) make the
 next of first element of the initial linked list NULL.*/
first->next=NULL;
/* storing the address of the reverse head which will be passed to it by the
 condition if(second==NULL) hence it will store the address of last element
 when this statement is executed for the last time. Also here we assume that 
the reverse function will yield the reverse of the rest of the linked 
list.*/
rev_head=reverse(second);
/*making the rest of the linked list point to the first element. i.e. 
 reversing the list.*/
second->next=first;

/*returning the reverse head (address of last element of initial linked 
list) . This condition executes only if the initial list is 1- not empty 
2- contains more than one element. So it just relays the value of last 
element to higher recursive calls.  */
return(rev_head);
}

now running the function for the linked list 1-> 2-> 3 -> 4

  • inside reverse(&1) the code runs until rev_head=reverse(&2); // here &1 is address of 1.

list of function is
1(first)->2(second) -> 3 -> 4

  • inside reverse(&2) code runs until rev_head=reverse(&3); list of function
    2(first)->3 (second)-> 4

  • inside reverse(&3) code runs until rev_head=reverse (&4); list if function
    3(first)-> 4 (second)

  • inside reverse(&4) terminating condition second==NULL is true so return is executed and address of 4 is returned.

list of function

4(first)-> NULL(second)

  • back to reverse(&3) list of function is
    NULL<-3(first) 4 (second)
    and the value of rev_head=&4 which was returned

after executing second->next=first; list becomes

NULL<- 3(first) <-4 (second)

return (rev_head ); is executed which passes &4 because rev_head=&4

  • back to rev(&2)

list in function is

NULL<-2(first) 3(second)<-4

and rev_head is &4 which was returned by rev(&3)

after executing second->next=first , list becomes

NULL<-2(first)<-3(second)<-4

return(rev_head); is executed which returns &4 to rev(&1);

  • back to rev(&1)

list in function is

NULL<-1(first) 2(second)<-3<-4

and value of rev_head is &4 which was passed by reverse(&3)

now second->next =first is executed and list becomes

NULL<-1(first) <- 2(second)<-3<-4

return(rev_head); is executed // rev_head=&4 which was returned by reverse(&2) and the value of rev_head is passesd to the main function.

hope this helps. It took me quite a lot of time to understand this and also to write this answer.

    To fix head also:

void reverse_list_recursive_internal (struct list **head, struct list *node)
{
    /* last node, fix the head */
    if (node->next == NULL) {
        *head = node;
        return; 
    }
    reverse_list_recursive_internal(head, node->next);
    node->next->next = node;
    node->next = NULL;
}

void reverse_list_recursive (struct list **head)
{
    if (*head == NULL) {
        return;
    }
    reverse_list_recursive_internal(head, *head);
}

This is a beautiful approach one can follow to reverse SLL recursively:

1.    struct node* head; // global head
2.    void rec_reverse(struct node* prev, struct node* cur)
3.    {
4.        if (cur)
5.        {
6.            rec_reverse(cur, cur->next);
7.            cur->next = prev;
8.        }
9.        else
10.            head = prev;
11.    }

Call the function this way:

rec_reverse(NULL, head);

Approach:

  • Calling the function recursively (line 6) we go to the last node of linked list.
  • Then we update head with the address of the last node (line 10).
  • Finally, we point link of each node to its previous node (line 7).

It seems to me that nobody has suggested an algorithm that is tail-recursive . In principle, a tail-recursive algorithm can be compiled without a stack (provided that the compiler is smart enough), thus producing code that consumes less memory.

Assume TList is a custom data-type for single-linked list, it is a pointer to a structure that as a link field for accessing the next element in the list.

The algorithm is the following:

```

TList reverse_aux(TList l, TList solution) {
    if (l == NULL) {
        return solution;
    } else {
        TList tmp = l->link;
        l->link = solution;
        return reverse_aux(tmp, l);
    }
}

TList reverse(TList l) {
    return reverse_aux(l, NULL);
}

```

ll *rev_list(ll *prev, ll *cur)
{
    if (!cur) {
        return prev;
    }

    ll *tmp = cur;
    cur = cur->next;
    tmp->next = prev;
    prev = tmp;
    return rev_list(prev, cur);
}

Find complete code : https://github.com/vijaythreadtemp/Data-Structures-And-Algorithms/blob/master/rev_link_list_rec.cxx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM