遞歸函數實現方式
上面提到,遞歸函數的也是借助於棧的機制實現的,但是底層對於棧的處理對於程序員來說都是透明的,程序員只需要關心應用的實現邏輯。所以說使用遞歸處理上述問題理解起來比較容易,代碼也比較簡潔。
既然使用遞歸函數,看名字我們就知道必須借助於自定義的函數。我先大概說一下其實現思路,具體細節我們反映在代碼中。
對於每一層的函數其主要做的工作就是查找父Id為當前Id的欄目,查找到以后再次調用自身函數,將查找到的欄目的id作為下一層的父id。
其流程圖如下

不知道對於上面的解釋大家能不能理解,沒關系我們下面直接看代碼
1 <?php 2 /** 3 * 個人博客:跡憶博客 4 * 博客地址:www.onmpw.com 5 * 遞歸實現無限極分類 6 */ 7 $channels = array( 8 array('id'=>1,'name'=>"衣服",'parId'=>0), 9 array('id'=>2,'name'=>"書籍",'parId'=>0), 10 array('id'=>3,'name'=>"T恤",'parId'=>1), 11 array('id'=>4,'name'=>"褲子",'parId'=>1), 12 array('id'=>5,'name'=>"鞋子",'parId'=>1), 13 array('id'=>6,'name'=>"皮鞋",'parId'=>5), 14 array('id'=>7,'name'=>"運動鞋",'parId'=>5), 15 array('id'=>8,'name'=>"耐克",'parId'=>7), 16 array('id'=>9,'name'=>"耐克",'parId'=>3), 17 array('id'=>10,'name'=>"鴻星爾克",'parId'=>7), 18 array('id'=>11,'name'=>"小說",'parId'=>2), 19 array('id'=>12,'name'=>"科幻小說",'parId'=>11), 20 array('id'=>13,'name'=>"古典名著",'parId'=>11), 21 array('id'=>14,'name'=>"文學",'parId'=>2), 22 array('id'=>15,'name'=>"四書五經",'parId'=>14) 23 ); 24 $html = array(); 25 /** 26 * 遞歸查找父id為$parid的結點 27 * @param array $html 按照父-》子的結構存放查找出來的結點 28 * @param int $parid 指定的父id 29 * @param array $channels 數據數組 30 * @param int $dep 遍歷的深度,初始化為1 31 */ 32 function getChild(&$html,$parid,$channels,$dep){ 33 /* 34 * 遍歷數據,查找parId為參數$parid指定的id 35 */ 36 for($i = 0;$i<count($channels);$i++){ 37 if($channels[$i]['parId'] == $parid){ 38 $html[] = array('id'=>$channels[$i]['id'],'name'=>$channels[$i]['name'],'dep'=>$dep); 39 getChild($html,$channels[$i]['id'],$channels,$dep+1); 40 } 41 } 42 } 43 getChild($html,0,$channels,1); 44 ?>
這是遞歸實現無限級欄目查詢的核心代碼,結合圖一對其實現流程應該有一個較清晰的認識。
非遞歸,即使用棧機制實現無限級欄目的查詢
在上面我們大概介紹了一下使用遞歸的方式實現無限級欄目的查詢,下面我們簡單介紹一下非遞歸的方式。雖說不用遞歸函數的方式,但是鑒於無限級欄目的結構頁需要參考遞歸的實現機制——棧的機制,解決這一問題。
在上學的時候老師就說,其實棧的核心機制也就四個字:先進后出。
在這對於棧的機制不多說,主要說一下如何借助棧實現無限級欄目查詢。
1. 首先將頂級欄目壓入棧中
2. 將棧頂元素出棧
3. 將出棧元素存入數組中,標記其深度(其深度就是在其父欄目的深度上面加1)
4. 以出棧的元素為父欄目,查找其子欄目
5. 將查找到的子欄目入棧,重復步驟2
6. 判斷棧為空的話,流程結束;
通過對以上步驟的翻譯,可以將這些步驟翻譯成PHP代碼,其核心代碼如下
1 <?php 2 /** 3 * 個人博客:跡憶博客 4 * 博客地址:www.onmpw.com 5 *使用非遞歸,即使用棧的方式實現欄目的無限極分類查詢 6 */ 7 $channels = array( 8 array('id'=>1,'name'=>"衣服",'parId'=>0), 9 array('id'=>2,'name'=>"書籍",'parId'=>0), 10 array('id'=>3,'name'=>"T恤",'parId'=>1), 11 array('id'=>4,'name'=>"褲子",'parId'=>1), 12 array('id'=>5,'name'=>"鞋子",'parId'=>1), 13 array('id'=>6,'name'=>"皮鞋",'parId'=>5), 14 array('id'=>7,'name'=>"運動鞋",'parId'=>5), 15 array('id'=>8,'name'=>"耐克",'parId'=>7), 16 array('id'=>9,'name'=>"耐克",'parId'=>3), 17 array('id'=>10,'name'=>"鴻星爾克",'parId'=>7), 18 array('id'=>11,'name'=>"小說",'parId'=>2), 19 array('id'=>12,'name'=>"科幻小說",'parId'=>11), 20 array('id'=>13,'name'=>"古典名著",'parId'=>11), 21 array('id'=>14,'name'=>"文學",'parId'=>2), 22 array('id'=>15,'name'=>"四書五經",'parId'=>14) 23 ); 24 $stack = array(); //定義一個空棧 25 $html = array(); //用來保存各個欄目之間的關系以及該欄目的深度 26 /* 27 * 自定義入棧函數 28 */ 29 function pushStack(&$stack,$channel,$dep){ 30 array_push($stack, array('channel'=>$channel,'dep'=>$dep)); 31 } 32 /* 33 * 自定義出棧函數 34 */ 35 function popStack(&$stack){ 36 return array_pop($stack); 37 } 38 /* 39 * 首先將頂級欄目壓入棧中 40 */ 41 foreach($channels as $key=>$val){ 42 if($val['parId'] == 0) 43 pushStack($stack,$val,0); 44 } 45 /* 46 * 將棧中的元素出棧,查找其子欄目 47 */ 48 do{ 49 $par = popStack($stack); //將棧頂元素出棧 50 /* 51 * 查找以此欄目為父級欄目的id,將這些欄目入棧 52 */ 53 for($i=0;$i<count($channels);$i++){ 54 if($channels[$i]['parId'] == $par['channel']['id']){ 55 pushStack($stack,$channels[$i],$par['dep']+1); 56 } 57 } 58 /* 59 * 將出棧的欄目以及該欄目的深度保存到數組中 60 */ 61 $html[] = array('id'=>$par['channel']['id'],'name'=>$par['channel']['name'],'dep'=>$par['dep']); 62 }while(count($stack)>0);
上面就是使用非遞歸方式實現的。
