關於遞迴刪除鏈表節點為什麼不會斷鏈問題解釋,遞迴節點

來源:互聯網
上載者:User

關於遞迴刪除鏈表節點為什麼不會斷鏈問題解釋,遞迴節點
問題的由來:   當你第一次實現用遞迴實現鏈表刪除功能的時候,是否有一絲絲的考慮過。這個問題呢?為什麼對於非遞迴版本的刪除必須要知道當前要刪除節點的前驅,而需要對其前驅節點的next域指標進行修改。而遞迴刪除卻不需要呢?難道這樣不會造成鏈表的斷鏈嗎?   好了。我們開始抽象出我們今天要解決的問題。問題一:

   遞迴實現鏈表節點的刪除和非遞迴刪除的區別是什嗎?

問題二:   為什麼在使用遞迴刪除的時候鏈表不會斷鏈?


先給個代碼,好根據代碼類比,不會空想。


函數的遞迴模型:

終止條件: f(L,x) = 不做任何事                         若L為空白表

遞迴主體:  f(L,x) = 刪除*L結點;f(L->next,x);           若L->data == x

           f(L,x) = f(L->next,x);                      其他情況


/*    用遞迴實現對沒有頭結點的鏈表實現刪除給定數字    輸出最終結果*/#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cstdlib>using namespace std;typedef int ElemType;const int MaxSize = 100;typedef struct LNode{     ElemType data;     struct LNode *next;}LNode,*LinkList;//遞迴刪除鏈表節點函數void Del_X_3(LinkList &L,ElemType x) {     LNode *p;     if(L == NULL) {          return;     }     if(L->data == x) {        p = L;        L = L->next;        free(p);        Del_X_3(L,x);        //printf("if2--> %d\n",L->data);     } else {         Del_X_3(L->next,x);         //printf("else--> %d\n",L->data);     }     //printf("--->%d\n",L->data);}int main(int argc,char **agrv) {    int n;    while(~scanf("%d",&n)) {         int x;         LinkList L = NULL;         LNode *s, *r = L;         for(int i = 0;i < n;++i) {             scanf("%d",&x);             s = (LNode *)malloc(sizeof(LNode));             s->data = x;             if(L == NULL) L = s;             else r->next = s;             r = s;             //printf("-->%u\n",r);         }         r->next = NULL;         printf("Please enter you want to delete number: ");         scanf("%d",&x);         LNode *p = L;         while(p) {             printf("%ox ",p);             p = p->next;         }         puts("");         Del_X_3(L,x);//         //test         p = L;         while(p) {             printf("%ox %d\n",p,p->data);             p = p->next;         }         puts("");    }    return 0;}

先解決問題一:

   對於非遞迴版本的刪除鏈表結點,必須要知道其前驅結點。假設當前要刪除的結點為p,前驅結點為q。修改代碼如下:q->next = p->next;而從上面的代碼可以看出,對於遞迴版本的程式並不需要特別的知道其前驅結點。


再解決問題二:

   首先,我們要先明確一個問題。就是上面給出的程式是用引用的。這說明了函數是傳址調用。這就是當刪除一個結點時候,不用需要知道前驅結點也可以的根本所在。

   給個例子類比一下你就知道了: 

   3 //輸入三個數

   3 4 5  

   4 //刪除4


類比函數調用過程:

初始鏈表邏輯關係:3  --> 4 --> 5  

1、從3結點開始: f(&L,4) ----> 這時候明顯不是要刪除的數。

                               所以調用else部分。

                               L1->next引用傳址。(當前的L表示的是結點3)


2、4結點開始: f(&L,4) -----> 這時候發現4就是要刪除的數。

                               調用if2部分

                               處理代碼為:L2 = L2->next(發現問題嗎?)

                       (L1和L2同表示L,為了好說明特別加以區別加了下標。)

                        其實,L2 == L1->next(即L1->next為結點3的next域)

                         而執行L2= L2->next現在就相當於把3的next域指向了5                          的指標域。(L1->next = L2->next。所以,我們在這個                          刪除的過程中還是隱含的知道了要刪除結點的前驅結點)

                         即,現在的邏輯關係變為:3->5 

                         後面的就都一樣了,就不在詳說了。程式一直執行到if1                          條件滿足為止,然後開始遞迴返回值。最後終止。

                         而這個過程是傳址的。所以,這回影響最終的結果。


好了。兩個問題都完美解決了。雖然,問題不是什麼難題。但是,如果對語言和遞迴沒有深刻的掌握還是一時難以理解的。

                               

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.