簡體   English   中英

反向鏈表

[英]reversing linked list

我正在嘗試使用遞歸反轉鏈接列表並為其編寫以下代碼。 列表的開頭是列表的開始。

 node *reverse_list_recursive(node *list)
 {
      node *parent = list;
      node *current = list->next;

      if(current == NULL)
       return parent;

      else
       {
           current = reverse_list_recursive(current);
           current->next = parent;
           printf("\n %d  %d \n",current->value,parent->value);
           return parent;
       }

  }

我可以看到所有鏈接都被顛倒了。 然而,當我嘗試顯示時,我得到了無限的數字打印。 當我嘗試反轉列表中最初的第一個數字的鏈接時,我懷疑出現錯誤。

我做錯了什么?

假設我有一個鏈表:

 ----------      ----------      ----------      ---------- 
|  1  |    |--->|  2  |    |--->|  3  |    |--->|  4  |    |--->NULL
 ----------      ----------      ----------      ---------- 

您的代碼將其轉換為:

   ----------------------          ----------------------
   |                    |          |                    |
   v                    |          v                    |
 ----------      ----------      ----------      ----------
|  1  |    |--->|  2  |    |    |  3  |    |    |  4  |    | 
 ----------      ----------      ----------      ---------- 
                   ^                    |
                   |                    |
                   ----------------------

請注意,第一個元素仍然指向 2。

如果在前兩個之后添加一行parent->next = NULL ,您將得到:

           ----------------------          ----------------------
           |                    |          |                    |
           v                    |          v                    |
         ----------      ----------      ----------      ----------
NULL<---|  1  |    |    |  2  |    |    |  3  |    |    |  4  |    | 
         ----------      ----------      ----------      ---------- 
                           ^                    |
                           |                    |
                           ----------------------

這實際上是正確的結構。

完整代碼為:(每次遞歸調用只需打印當前值)

node *reverse_list_recursive(node *list)
  {
      node *parent = list;
      node *current = list->next;

      if(current == NULL)
       return parent;

      else
       {
           current = reverse_list_recursive(current);
           parent->next = NULL;
           current->next = parent;
           printf("\n %d \n",current->value);
           return parent;
       }

  }

您需要將新尾部(即舊頭部)的下一個指針設置為 NULL

編輯:這是一個遞歸版本

node *reverse_list_recursive(node *list)
  {
      node *parent = list;
      node *child = list->next;
      node *new_head;


    if (child == NULL)
          return parent ;  /* new head */

    new_head = reverse_list_recursive(child)
    child->next = parent; /* Old parent is the new child of the old child when reversed */
    parent->next = NULL; /* might be tail, will be overwritten after we return if we're not at the top level */
    return new_head;
}

當您到達列表的末尾時,您將返回最后一個節點。 然后將最后一個節點的下一個值分配給它自己,因此會造成不一致。 如果當前為 NULL,則返回 NULL,如果返回為 NULL,則簡單地忽略其余代碼。

您忘記更新鏈表上第一項的next成員。 添加parent->next = NULL; 在遞歸調用之前。

我在這里看不到遞歸的好處,迭代也能正常工作。 自從我寫 C 以來已經很久了(並且沒有簡單的方法來測試以下語法錯誤......或者畏縮核心轉儲,但你明白了)。

node *reversed_list(node *list) {
    node *fwd=list;//Purely for readability
    node *last=null;
    node *next=null;
    node *rev=null;
    do {
        //Cache next
        next=fwd->next;
        //Set current
        rev=fwd;
        //Reset next to point back
        rev->next=last;
        //Update last
        last=fwd;
        //Forward ptr;
        fwd=next;
    } while (fwd!=null);
    return rev;
}

很確定你的*list在你調用它之后沒用,因為它現在指向列表的最后一個元素->next=null ,可以只更新它而不是返回指針。

更新(用於遞歸解決方案)

正如其他人所說,你的新尾部搞砸了(指向最后一個元素,但應該指向空)......並且你沒有返回正確的頭部,而是返回第二個元素。 考慮列表a->b->null與您的算法:

 p=a, c=b; c= p=b c=null return b; //b->null c=b c->next=a //b->a return a; //a->b, b->a, a returned //But what you wanted is a->null, b->a, and b returned

以下更新的代碼將修復:

node *reverse_list_recursive(node *list)
  {
      node *parent = list;
      node *current = list->next;

      if(current == NULL)
       return parent;

      else
       {
           current = reverse_list_recursive(current);
           current->next = parent;
           parent->next=null; //Fix tail
           printf("\n %d  %d \n",current->value,parent->value);
           return current; //Fix head
       }

  }

使用列表a->b->null

 p=a, c=b; c= p=b c=null return b; //b->null c=b c->next=a //b->a p->next=null //a->null return b; // b->a->null

current = reverse_list_recursive(current); 您將新的列表頭存儲在 current 中,因此current->next = parent; 是錯誤的。 New current是新的鏈表頭,但是你需要訪問新的鏈表尾,即 OLD current

node* newhead = reverse_list_recursive(current);
current->next = parent;
printf("\n %d  %d \n",current->value,parent->value);
return newhead;

我可以看到的一些問題:

  • 您需要將新的最后一個節點的下一個指針設為 NULL。
  • 如果我最初將 NULL 傳遞給它,那么您現有的函數將會失敗。

這是用於反轉鏈表的遞歸代碼。

list * reverse(list * head)
{
    if( head == NULL || head -> link == NULL )
        return head;
    list *node = reverse( head- > link );
    head -> link -> link = head;
    head -> link = NULL;
    return node;
}

不同的代碼如下:

'

#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)

struct Node {
    int data;
    struct Node* next;
};
typedef struct Node node;

node* dogrusıralama(node* r)
{
    for (int i = 0; i < 6; i++)
    {
        printf("%d", r->data);
        r = r->next;
        printf("\n");
    }
}
node *terssıralama(node* r)
{
        node* iter;
        iter = r;
        node* temp;
        temp = r;
        node* temp2;
        temp2 = r;
        int a = 4;
        for (int k = 0; k < 5; k++)
        {        
            temp2 = temp2->next;
        }
        for (int j = 0; j < 5; j++)
        {
            int i = a;
            for (; i > 0; i--)
            {
                temp = temp->next;
        
            }
            a--;
            iter = temp;
            iter->next->next = iter  ;
            temp = r;
        }
        temp->next = NULL;
        return temp2;
}
int main() {
    node* dugum;
    node* dugum2;
    node* dugum3;
    node* dugum4;
    dugum = (node*)malloc(sizeof(node*));
    dugum2 = dugum;
    for (int i = 0; i < 5; i++)
    {
        dugum2->next = NULL;
        dugum2->next = (node*)malloc(sizeof(node*));
        dugum2->data = i;
        dugum2 = dugum2->next;
    }
    dugum4 = dugum;
    dogrusıralama(dugum);
    dugum3 = terssıralama(dugum);

    for (int i = 0; i < 6; i++)
    {
        printf("\n");
        printf("%d", dugum3->data);
        dugum3 = dugum3->next;
    }
     
} '

上面的 Severl 版本不能像 OP 那樣工作,所以這里是我的遞歸版本測試良好:

node * reverseRecursive(node *p,node **head)
{
     if(p->next == NULL)
     {
         *head = p;
          return p;
     }
     node *before;
     before = reverseRecursive(p->next,head);
     before->next = p;
     p->next = NULL;
     return p;
}

//call from main
node*head; 
//adding value
//assuming now head is now 1->2->3->4->NULL
node* newHead;
reverseRecursive(head,&newHead);
//now now newHead is now 4->3->2->1->NULL

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM