Реверсирование linkedlist рекурсивно в c

следующий код отлично работает, когда head отправляется ему в качестве параметра. Как я новичок в C, я не мог понять, как это работает. Помогите мне пожалуйста.

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;
}

Я не знаю, как ссылки предоставляются с использованием этих рекурсивных вызовов. ie) если ссылки таковы,

1 -> 2 -> 3 -> 4 

тогда hw изменяется как,

4 -> 3 -> 2 -> 1

8 ответов


общий рекурсивный алгоритм для этого:

  1. Divide список 2 запасные части - первая узел и остальная часть списка.
  2. рекурсивно обратный вызов для rest из связанный список.
  3. ссылке rest to first.
  4. исправить head указатель

вот код со встроенными комментариями:

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.
}

Я надеюсь, что эта картина сделает вещи яснее:

изображения http://geeksforgeeks.org/wp-content/uploads/2009/07/Linked-List-Rverse.gif.


альтернативное решение :

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

в main, обратный вызов (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;
}

другое решение:

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);

}

пусть связанный список будет 1-> 2 -> 3 ->4

функция в c--

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);
}

теперь работает функция для связанного списка 1-> 2-> 3 -> 4

  • внутренний реверс (&1) код выполняется до тех пор, пока rev_head=reverse(&2); // здесь &1-Адрес 1.

список функция
1 (первый) - >2 (второй) -> 3 -> 4

  • внутренний реверс (&2) код выполняется до rev_head=reverse(&3); список функция
    2 (Первый) - >3 (второй)-> 4

  • внутренний реверс (&3) код выполняется до rev_head=reverse (&4); список если функция
    3 (Первый) - > 4 (второй)

  • внутренний реверс (&4) завершающее условие second==NULL имеет значение true, поэтому return выполняется и адрес 4 возвращается.

список функция

4 (первый) - > NULL (второй)

  • назад к обратному(&3) список функций is
    NULL и значение rev_head=&4, которое было возвращено

после выполнения second - >next=first; список становится

NULL

return (rev_head); выполняется, который проходит &4, потому что rev_head=&4

  • вернуться к rev (&2)

список в функции

NULL

и rev_head и 4, которая была возвращена rev (&3)

после выполнения second - >next=first, list становится

NULL

return (rev_head); выполняется, который возвращает &4 в rev(&1);

  • вернуться к rev (&1)

список в функции

NULL

и значение rev_head - &4, которое было передано обратным (&3)

теперь второй - >next =первый выполняется и список становится

NULL

return (rev_head); выполняется / / rev_head=&4, который был возвращен reverse(&2) и значение rev_head-это passesd для основной функции.

надеюсь, что это помогает. Мне потребовалось много времени, чтобы понять это и написать этот ответ.


это красивый подход, который можно использовать для рекурсивного обратного SLL:

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.    }

вызовите функцию следующим образом:

rec_reverse(NULL, head);

подход:

  • вызов функции рекурсивно (строка 6) переходим к последнему узлу связанный список.
  • затем мы обновляем head с адресом последнего узла (линия 10).
  • наконец, мы указываем ссылку каждого узла на его предыдущий узел (строка 7).

    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);
}

мне кажется, что никто не предложил алгоритм, который хвост-рекурсивный. В принципе, хвостовой рекурсивный алгоритм может быть скомпилирован без стека (при условии, что компилятор достаточно умен), тем самым создавая код, который потребляет меньше памяти.

предположим TList - это пользовательский тип данных для односвязного списка, это указатель на структуру, которая как