算法之遞歸(2)- 鏈表遍歷


算法之遞歸(2)- 鏈表遍歷

在遞歸(1)中,簡單的介紹了遞歸的思想,並且通過一個例子簡單闡述了遞歸是如何工作的,並且遞歸的實現是以線性結構來表示的。之所以用線性的,是因為其易於理解;如果使用樹結構,將加大對問題的難度,不利於初學者理解遞歸的思想。

為什么用遞歸

關於為什么用遞歸,我個人的理解是遞歸不要違背算法的初衷,即期待傳入xxx值,加工后返回xxx值。不要為了遞歸而遞歸,容易造成對函數語義的奇異。另外,通過遞歸,可以讓代碼更加整潔,短小,精湛,優美。當然,還會存在一定程度的性能損耗;不過,合理的使用,對於那部分的損耗可以忽略不計。

 

讓我們以單鏈表為例,理解一下遞歸是如何工作的。

1. 遍歷單鏈表

循環

遞歸

    

 private void TraveserL(LNode head)
 {
     if (head == null)
         return;

     while (head != null)
     {
         Console.WriteLine(p.data);
         p = p.next;
     }
 }


private
void TraveserR(LNode head) { if (head == null) return; Console.WriteLine(head.data); TraveserR(head.next); }



 

對於循環遍歷我想不用多說了吧。不過,值得注意的是遞歸的遍歷,先對數據進行打印,然后遍歷下一個節點。有趣的是,如果將打印語句放在遞歸調用的后面,將是一個逆序的打印。

分析

假設鏈表的結構是這樣的

A->B->C->D->E->F

遞歸調用時將發生如下情形

1.在遞歸調用之前打印(意味着進入函數體的時候打印)

(1)進入函數 (從左到右讀)

A->

B->

C->

D->

E->

F->

打印A

打印B

打印C

打印D

打印E

打印F

 

輸出:A, B, C, D, E, F.

(2)當函數退出 (從右到左度)

<-A

<-B

<-C

<-D

<-E

<-F

 

2. 在遞歸調用之后 (意味着只有退出函數體的時候,才進行打印)

(1)    進入函數體(從左到右讀)

A->

B->

C->

D->

E->

F->

 

(2)    退出出函數體(從右到左讀)

<-A

<-B

<-C

<-D

<-E

<-F

打印A

打印B

打印C

打印D

打印E

打印F

 

輸出:F, E, D, C, B, A

結論,當操作在遞歸調用之后進行,那么是從后向前對鏈表執行操作。這也是棧的特性之一。當然,具體何時決定,取決與程序員自己,是想從頭開始順序操作,還是后到前逆序操作,具體問題具體分析。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM