web-dev-qa-db-ja.com

リンクリストを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;
}

これらの再帰呼び出しを使用してリンクがどのように提供されるかわかりません。すなわち)リンクが次の場合、

1 -> 2 -> 3 -> 4 

それからhwは次のように変更されます、

4 -> 3 -> 2 -> 1
14
rampireram

これの一般的な再帰アルゴリズムは次のとおりです。

  1. Divide2部分のリスト-最初のノードとリストの残り。
  2. リンクリストのrestに対して再帰的にreverseを呼び出します。
  3. restfirstにリンクします。
  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.
}

この写真が物事をより明確にすることを願っています:

image
(ソース: geeksforgeeks.org

58
codaddict

代替ソリューション:

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

メインでは、reverse(NULL、head)を呼び出します。

5
/* 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

別の解決策:

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

}

tail-recursiveのアルゴリズムを誰も提案していないように思えます。原則として、末尾再帰アルゴリズムはスタックなしでコンパイルできます(コンパイラーが十分にスマートである場合)。そのため、メモリの消費量が少ないコードが生成されます。

TListは単一リンクリストのカスタムデータ型であり、リスト内の次の要素にアクセスするためのlinkフィールドとしての構造体へのポインターであると想定します。

アルゴリズムは次のとおりです。

`` `

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

リンクリストを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

  • reverse(&1)内では、コードはrev_head = reverse(&2);まで実行されます。 //ここで&1は1のアドレスです。

関数のリストは
1(最初)-> 2(秒)-> 3-> 4

  • rev_head = reverse(&3);まで、reverse(&2)コード内で実行されます。関数のリスト
    2(最初)-> 3(秒)-> 4

  • reverse(&3)コード内では、rev_head = reverse(&4);まで実行されます。関数のリスト
    3(最初)-> 4(秒)

  • reverse(&4)終了条件second == NULLがtrueであるため、returnが実行され、アドレス4が返されます。

関数のリスト

4(first)-> NULL(second)

  • 関数のreverse(&3)リストに戻る
    NULL <-3(最初)4(秒)
    および返されたrev_head =&4の値

second-> next = firstを実行した後;リストは

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

return(rev_head); rev_head =&4であるため&4を渡す

  • rev(&2)に戻る

関数内のリストは

NULL <-2(最初)3(秒)<-4

また、rev_headはrev(&3)によって返された&4です。

second-> next = firstを実行した後、リストは

NULL <-2(最初)<-3(秒)<-4

return(rev_head); &4をrev(&1)に返す実行されます。

  • rev(&1)に戻る

関数内のリストは

NULL <-1(最初)2(秒)<-3 <-4

rev_headの値は、reverse(&3)によって渡された&4です。

現在、second-> next = firstが実行され、リストは

NULL <-1(最初)<-2(秒)<-3 <-4

return(rev_head); // rev_head =&4が実行され、これはreverse(&2)によって返され、rev_headの値がメイン関数に渡されます。

お役に立てれば。これを理解し、この答えを書くのにかなり時間がかかりました。

0
user7441114

これは、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行目)。
0
Amit Upadhyay