關於遞迴刪除鏈表節點為什麼不會斷鏈問題解釋,遞迴節點
問題的由來: 當你第一次實現用遞迴實現鏈表刪除功能的時候,是否有一絲絲的考慮過。這個問題呢?為什麼對於非遞迴版本的刪除必須要知道當前要刪除節點的前驅,而需要對其前驅節點的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 條件滿足為止,然後開始遞迴返回值。最後終止。
而這個過程是傳址的。所以,這回影響最終的結果。
好了。兩個問題都完美解決了。雖然,問題不是什麼難題。但是,如果對語言和遞迴沒有深刻的掌握還是一時難以理解的。