簡體   English   中英

如何使用雙指針遞歸反轉鏈表

[英]How to recursively reverse a Linked list with double pointers

目標是將一系列整數 1 2 3 4 5 反轉為 5 4 3 2 1。

這是結構定義:

typedef struct _listnode
{
    int item;
    struct _listnode *next;
} ListNode;         // You should not change the definition of ListNode

typedef struct _linkedlist
{
    int size;
    ListNode *head;
} LinkedList;   

我有一個使用這個RecursiveReverse(&(ll.head));調用的函數RecursiveReverse(&(ll.head));

void RecursiveReverse(ListNode **ptrHead)
{
    ListNode *curr,*q;
    curr = *ptrHead; //same as ll.head

    if(curr == NULL)
    {
        return;
    }

    if(curr->next == NULL)
    {
        *ptrHead = curr;
        return;
    }
    RecursiveReverse(&(curr->next));
    q = curr->next;
    q->next = curr;
    curr->next = NULL;
}

在這一步,如果我的輸入是 1 2 3 ,則輸出僅為 1。感謝任何幫助!

這段代碼正在運行試試吧,我將大小固定為 5

#include <stdio.h>
#include <stdlib.h>

typedef struct _listnode
{
    int item;
    struct _listnode *next;
} ListNode;         // You should not change the definition of ListNode

struct _listnode* RecursiveReverse(struct _listnode* head)
{
    struct _listnode *temp = head;
    struct _listnode *curr = head;
    struct _listnode *prev = NULL;
    struct _listnode *next = NULL;
    int count = 0;

    // Reverses the first k nodes iteratively
    while (curr != NULL && count < 5){
            next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
            count++;
    }

    if (next != NULL) temp->next = RecursiveReverse(next);
    return prev;
}

int main() {
   struct _listnode* head = NULL; 
   struct _listnode* item2 = NULL; 
   struct _listnode* item3 = NULL; 
   struct _listnode* item4 = NULL; 
   struct _listnode* item5 = NULL; 

   struct _listnode* reverse = NULL; 

   head = (struct _listnode*)malloc(sizeof(struct _listnode));
   item2 = (struct _listnode*)malloc(sizeof(struct _listnode));
   item3 = (struct _listnode*)malloc(sizeof(struct _listnode));
   item4 = (struct _listnode*)malloc(sizeof(struct _listnode));
   item5 = (struct _listnode*)malloc(sizeof(struct _listnode));

   item5->item = 5;
   item5->next = NULL;

   item4->item = 4;
   item4->next = item5;

   item3->item = 3;
   item3->next = item4;

   item2->item = 2;
   item2->next = item3;

   head->item = 1;
   head->next = item2;

   reverse = RecursiveReverse(head);

   while (reverse != NULL) { 
      printf(" %d ", reverse->item); 
      reverse = reverse->next; 
   }

   return 0;
}

由於您將LinkedList作為ListNode周圍的包裝結構,您將需要提供一個包裝函數,該函數采用LinkedList*參數,然后調用實際的遞歸函數,該函數執行將prevcurrent節點作為參數傳遞的工作。 這可以通過以下方式完成:

/** recursive reversal of list */
ListNode *revlist (ListNode *cur, ListNode *prev)
{
    if (cur->next != NULL) {
        ListNode *next = cur->next;
        cur->next = prev;
        return revlist (next, cur);
    }
    else {
        cur->next = prev;
        return cur;
    }
}

/** recursive reversal of list (wrapper) */
void rev (LinkedList *l)
{
    l->head = revlist (l->head, NULL);
}

在您的代碼中,您只需調用:

rev (ptr_to_list);

注意:使用包裝LinkedList很好,它還允許您在末尾添加 O(1) 插入的tail指針。

構建和反轉列表的一個簡短示例是:

#include <stdio.h>
#include <stdlib.h>

typedef struct _listnode {
    int item;
    struct _listnode *next;
} ListNode;

typedef struct _linkedlist {
    int size;
    ListNode *head, *tail;
} LinkedList;

/** add node at end of list, update tail to end */
ListNode *add (LinkedList *l, int v)
{
    ListNode *node = malloc (sizeof *node); /* allocate node */
    if (!node) {                            /* validate allocation */
        perror ("malloc-node");
        return NULL;
    }
    node->item = v;                         /* initialize members values */
    node->next = NULL;

    if (!l->head)                   /* if 1st node, node is head/tail */
        l->head = l->tail = node;
    else {                          /* otherwise */
        l->tail->next = node;       /* add at end, update tail pointer */
        l->tail = node;
    }

    return node;    /* return new node */
}

/** print all nodes in list */
void prn (LinkedList *l)
{
    if (!l->head) {
        puts ("list-empty");
        return;
    }
    for (ListNode *n = l->head; n; n = n->next)
        printf (" %d", n->item);
    putchar ('\n');
}

/** delete all nodes in list */
void del (LinkedList *l)
{
    ListNode *n = l->head;
    while (n) {
        ListNode *victim = n;
        n = n->next;
        free (victim);
    }
}

/** recursive reversal of list */
ListNode *revlist (ListNode *cur, ListNode *prev)
{
    if (cur->next != NULL) {
        ListNode *next = cur->next;
        cur->next = prev;
        return revlist (next, cur);
    }
    else {
        cur->next = prev;
        return cur;
    }
}

/** recursive reversal of list (wrapper) */
void rev (LinkedList *l)
{
    l->head = revlist (l->head, NULL);
}

int main (void) {

    LinkedList l = { .size = 0 };

    for (int i = 0; i < 10; i++)
        add (&l, i+1);

    prn (&l);
    rev (&l);
    prn (&l);
    del (&l);
}

示例使用/輸出

$ ./bin/lls_rec_rev
 1 2 3 4 5 6 7 8 9 10
 10 9 8 7 6 5 4 3 2 1

內存使用/錯誤檢查

在你寫的,可動態分配內存的任何代碼,您有任何關於分配的內存任何塊2個職責:(1)始終保持一個指針的起始地址的存儲器中,以便塊,(2),當它是沒有它可以被釋放不再需要。

您必須使用內存錯誤檢查程序來確保您不會嘗試訪問內存或寫入超出/超出分配塊的范圍,嘗試讀取或基於未初始化值的條件跳轉,最后確認你釋放了你分配的所有內存。

對於 Linux valgrind是正常的選擇。 每個平台都有類似的內存檢查器。 它們都易於使用,只需通過它運行您的程序即可。

$ valgrind ./bin/lls_rec_rev
==7081== Memcheck, a memory error detector
==7081== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7081== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==7081== Command: ./bin/lls_rec_rev
==7081==
 1 2 3 4 5 6 7 8 9 10
 10 9 8 7 6 5 4 3 2 1
==7081==
==7081== HEAP SUMMARY:
==7081==     in use at exit: 0 bytes in 0 blocks
==7081==   total heap usage: 11 allocs, 11 frees, 1,184 bytes allocated
==7081==
==7081== All heap blocks were freed -- no leaks are possible
==7081==
==7081== For counts of detected and suppressed errors, rerun with: -v
==7081== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始終確認您已釋放所有分配的內存並且沒有內存錯誤。

暫無
暫無

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

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