web-dev-qa-db-fra.com

Inversion récursive d'une liste chaînée dans c

Le code suivant fonctionne bien lorsque head est envoyé en tant que paramètre. Comme je suis nouveau en C, je ne comprenais pas comment cela fonctionnait. Aidez-moi s'il vous plaît.

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

Je ne sais pas comment les liens sont fournis en utilisant ces appels récursifs. c'est à dire) si les liens sont en tant que,

1 -> 2 -> 3 -> 4 

alors hw est-il changé comme,

4 -> 3 -> 2 -> 1
12
rampireram

L'algorithme récursif général pour cela est:

  1. Divide la liste en 2 parties - premier nœud .__ et reste de la liste.
  2. Appel récursivement inverse pour la variable rest de la liste chaînée
  3. Lien rest à first.
  4. Correction du pointeur head

Voici le code avec les commentaires en ligne:

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

J'espère que cette image rendra les choses plus claires:

image http://geeksforgeeks.org/wp-content/uploads/2009/07/Linked-List-Rverse.gif .

53
codaddict

Solution alternative:

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

En mode principal, appel inversé (NULL, tête);

5
Aakash Arayambeth
/* 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;
}
3
n3wb

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

}
1

Il me semble que personne n’a suggéré un algorithme qui est tail-récursif . En principe, un algorithme de type récursif peut être compilé sans pile (à condition que le compilateur soit suffisamment intelligent), produisant ainsi un code qui consomme moins de mémoire.

Supposons que TList soit un type de données personnalisé pour une liste à lien unique, il s'agit d'un pointeur sur une structure constituant un champ link permettant d'accéder à l'élément suivant de la liste.

L'algorithme est le suivant:

`` `

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

`` `

0
FSp
    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);
}
0
Krishna Durgam

Que la liste chaînée soit 1-> 2 -> 3 -> 4

la fonction en 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);
}

lance maintenant la fonction pour la liste chaînée 1-> 2-> 3 -> 4

  • inside reverse (& 1) le code s’exécute jusqu’à rev_head = reverse (& 2); // here & 1 est l'adresse de 1.

liste de fonction est
1 (premier) -> 2 (deuxième) -> 3 -> 4

  • À l'intérieur de reverse (& 2) le code s'exécute jusqu'à ce que rev_head = reverse (& 3); liste de fonctions
    2 (premier) -> 3 (deuxième) -> 4

  • À l'intérieur de reverse (& 3) le code s'exécute jusqu'à ce que rev_head = reverse (& 4); list si function
    3 (premier) -> 4 (deuxième)

  • inside reverse (& 4) condition de fin seconde == NULL est vrai, le retour est exécuté et l'adresse de 4 est renvoyée.

liste de fonction 

4(first)-> NULL(second)

  • back to reverse (& 3) liste de fonctions est
    NULL <-3 (premier) 4 (deuxième)
    et la valeur de rev_head = & 4 qui a été renvoyée

après avoir exécuté second-> next = first; la liste devient

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

return (rev_head); est exécuté ce qui passe & 4 car rev_head = & 4

  • retour au rev ​​(& 2)

la liste en fonction est 

NULL <-2 (premier) 3 (seconde) <- 4 

et rev_head est & 4 qui a été retourné par rev (& 3)

après avoir exécuté second-> next = first, la liste devient

NULL <-2 (premier) <- 3 (seconde) <- 4

return (rev_head); est exécuté ce qui retourne & 4 to rev (& 1);

  • retour au rev ​​(& 1)

la liste en fonction est 

NULL <-1 (premier) 2 (seconde) <- 3 <-4 

et la valeur de rev_head est & 4 qui a été passé par reverse (& 3)

maintenant second-> next = le premier est exécuté et la liste devient

NULL <-1 (premier) <- 2 (seconde) <- 3 <-4

return (rev_head); est exécuté // rev_head = & 4 qui a été renvoyé par reverse (& 2) et la valeur de rev_head est transmise à la fonction principale.

j'espère que cela t'aides. Il m'a fallu beaucoup de temps pour comprendre cela et aussi pour écrire cette réponse. 

0
user7441114

C'est une belle approche que l'on peut suivre pour inverser SLL de manière récursive:

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

Appelez la fonction de cette façon:

rec_reverse(NULL, head);

Approche:

  • En appelant la fonction de manière récursive (ligne 6), nous allons au dernier nœud de la liste chaînée
  • Puis nous mettons à jour head avec l'adresse du dernier nœud .__ (ligne 10).
  • Enfin, nous pointons le lien de chaque nœud vers son nœud précédent (ligne 7).
0
Amit Upadhyay