首頁  >  文章  >  後端開發  >  PHP實作無限分類的兩種方式

PHP實作無限分類的兩種方式

韦小宝
韦小宝原創
2018-02-05 09:38:471734瀏覽

這篇文章分為兩種情況,介紹了在遞歸和不使用遞歸的情況下PHP實現無限級分類,PHP無限分類在我們的開發過程中是非常長見到的,我們今後的開發中也會很常的使用到PHP無限分類,那麼我們就更應該掌握它了,不太了解PHP如何實現無限分類的小伙伴們可以參考一下本篇文章

做PHP這麼長時間,發現後台管理系統不可少的一個應用模組就是對欄目的分類,一般情況下欄目都要做成是無限級的,也就是說每個專欄理論上都可以添加子欄。在我看來這種情況處理起來整體上說也不是很複雜,唯一一個相對來說較難的點是無限級欄目的查詢。

下面就這種情況我來向大家做一個簡單的介紹,對於這種無限級欄目的查詢一般情況下有兩種方式,其中一種就是使用棧的機制,另一種是使用遞歸函數的方式(當然遞歸函數實作機制也是藉助於堆疊來實現的)。就這兩種方式下面我們分別介紹。

遞迴函數實作方式

上面提到,遞迴函數的也是藉助於堆疊的機制實現的,但是底層對於堆疊的處理對於程式設計師來說都是透明的,程式設計師只需要關心應用的實作邏輯。所以說使用遞歸處理上述問題理解起來比較容易,程式碼也比較簡潔。

既然使用遞歸函數,看名字我們就知道必須藉助於自訂的函數。我先大概說一下其實現思路,具體細節我們反映在程式碼中。

對於每一層的函數其主要做的工作就是查找父Id為當前Id的欄目,查找到以後再次調用自身函數,將查找到的欄目的id作為下一層的父id。

其流程圖如下

圖一

#不知道對於上面的解釋大家能不能理解,沒關係我們下面直接看程式碼

<?php
$channels = array(
  array(&#39;id&#39;=>1,&#39;name&#39;=>"衣服",&#39;parId&#39;=>0),
  array(&#39;id&#39;=>2,&#39;name&#39;=>"书籍",&#39;parId&#39;=>0),
  array(&#39;id&#39;=>3,&#39;name&#39;=>"T恤",&#39;parId&#39;=>1),
  array(&#39;id&#39;=>4,&#39;name&#39;=>"裤子",&#39;parId&#39;=>1),
  array(&#39;id&#39;=>5,&#39;name&#39;=>"鞋子",&#39;parId&#39;=>1),
  array(&#39;id&#39;=>6,&#39;name&#39;=>"皮鞋",&#39;parId&#39;=>5),
  array(&#39;id&#39;=>7,&#39;name&#39;=>"运动鞋",&#39;parId&#39;=>5),
  array(&#39;id&#39;=>8,&#39;name&#39;=>"耐克",&#39;parId&#39;=>7),
  array(&#39;id&#39;=>9,&#39;name&#39;=>"耐克",&#39;parId&#39;=>3),
  array(&#39;id&#39;=>10,&#39;name&#39;=>"鸿星尔克",&#39;parId&#39;=>7),
  array(&#39;id&#39;=>11,&#39;name&#39;=>"小说",&#39;parId&#39;=>2),
  array(&#39;id&#39;=>12,&#39;name&#39;=>"科幻小说",&#39;parId&#39;=>11),
  array(&#39;id&#39;=>13,&#39;name&#39;=>"古典名著",&#39;parId&#39;=>11),
  array(&#39;id&#39;=>14,&#39;name&#39;=>"文学",&#39;parId&#39;=>2),
  array(&#39;id&#39;=>15,&#39;name&#39;=>"四书五经",&#39;parId&#39;=>14)
);
$html = array();
/**
 * 递归查找父id为$parid的结点
 * @param array $html  按照父-》子的结构存放查找出来的结点
 * @param int $parid  指定的父id
 * @param array $channels  数据数组
 * @param int $dep  遍历的深度,初始化为1
 */
function getChild(&$html,$parid,$channels,$dep){
  /*
   * 遍历数据,查找parId为参数$parid指定的id
   */
  for($i = 0;$i<count($channels);$i++){
    if($channels[$i][&#39;parId&#39;] == $parid){
      $html[] = array(&#39;id&#39;=>$channels[$i][&#39;id&#39;],&#39;name&#39;=>$channels[$i][&#39;name&#39;],&#39;dep&#39;=>$dep);
      getChild($html,$channels[$i][&#39;id&#39;],$channels,$dep+1);
    }
  }
}
getChild($html,0,$channels,1);
?>

這是遞歸實現無限級欄位查詢的核心程式碼,結合圖一對其實作流程應該有一個較清晰的認知。

非遞歸,即使用堆疊機制實現無限級欄目的查詢

#在上面我們大概介紹了一下使用遞歸的方式實現無限級欄目的查詢,下面我們簡單介紹一下非遞歸的方式。雖然不用遞歸函數的方式,但是鑑於無限級欄目的結構頁需要參考遞歸的實作機制-棧的機制,解決這個問題。

在上學的時候老師就說,其實棧的核心機制也就四個字:先進後出。

在這對堆疊的機制不多說,主要說一下如何借助堆疊實作無限層級欄位查詢。

1. 先將頂層欄位壓入堆疊中

#2. 將堆疊頂元素出堆疊

3. 將出棧元素存入數組中,標記其深度(其深度就是在其父欄目的深度上面加1)

##4. 以出棧的元素為父欄目,找出其子欄位

5. 將查找到的子欄位入棧,重複步驟2

6.判斷棧為空的話,流程結束;

透過上述步驟的翻譯,可以將這些步驟翻譯成

PHP程式碼,其核心程式碼如下

<?php
$channels = array(
  array(&#39;id&#39;=>1,&#39;name&#39;=>"衣服",&#39;parId&#39;=>0),
  array(&#39;id&#39;=>2,&#39;name&#39;=>"书籍",&#39;parId&#39;=>0),
  array(&#39;id&#39;=>3,&#39;name&#39;=>"T恤",&#39;parId&#39;=>1),
  array(&#39;id&#39;=>4,&#39;name&#39;=>"裤子",&#39;parId&#39;=>1),
  array(&#39;id&#39;=>5,&#39;name&#39;=>"鞋子",&#39;parId&#39;=>1),
  array(&#39;id&#39;=>6,&#39;name&#39;=>"皮鞋",&#39;parId&#39;=>5),
  array(&#39;id&#39;=>7,&#39;name&#39;=>"运动鞋",&#39;parId&#39;=>5),
  array(&#39;id&#39;=>8,&#39;name&#39;=>"耐克",&#39;parId&#39;=>7),
  array(&#39;id&#39;=>9,&#39;name&#39;=>"耐克",&#39;parId&#39;=>3),
  array(&#39;id&#39;=>10,&#39;name&#39;=>"鸿星尔克",&#39;parId&#39;=>7),
  array(&#39;id&#39;=>11,&#39;name&#39;=>"小说",&#39;parId&#39;=>2),
  array(&#39;id&#39;=>12,&#39;name&#39;=>"科幻小说",&#39;parId&#39;=>11),
  array(&#39;id&#39;=>13,&#39;name&#39;=>"古典名著",&#39;parId&#39;=>11),
  array(&#39;id&#39;=>14,&#39;name&#39;=>"文学",&#39;parId&#39;=>2),
  array(&#39;id&#39;=>15,&#39;name&#39;=>"四书五经",&#39;parId&#39;=>14)
);
$stack = array(); //定义一个空栈
$html = array();  //用来保存各个栏目之间的关系以及该栏目的深度
/*
 * 自定义入栈函数
 */
function pushStack(&$stack,$channel,$dep){
  array_push($stack, array(&#39;channel&#39;=>$channel,&#39;dep&#39;=>$dep));
}
/*
 * 自定义出栈函数
 */
function popStack(&$stack){
  return array_pop($stack);
}
/*
 * 首先将顶级栏目压入栈中
 */
foreach($channels as $key=>$val){
  if($val[&#39;parId&#39;] == 0)
    pushStack($stack,$val,0);
}
/*
 * 将栈中的元素出栈,查找其子栏目
 */
do{
  $par = popStack($stack); //将栈顶元素出栈
  /*
   * 查找以此栏目为父级栏目的id,将这些栏目入栈
   */
  for($i=0;$i<count($channels);$i++){
    if($channels[$i][&#39;parId&#39;] == $par[&#39;channel&#39;][&#39;id&#39;]){
      pushStack($stack,$channels[$i],$par[&#39;dep&#39;]+1);
    }
  }
  /*
   * 将出栈的栏目以及该栏目的深度保存到数组中
   */
  $html[] = array(&#39;id&#39;=>$par[&#39;channel&#39;][&#39;id&#39;],&#39;name&#39;=>$par[&#39;channel&#39;][&#39;name&#39;],&#39;dep&#39;=>$par[&#39;dep&#39;]);
}while(count($stack)>0);

上面就是使用非遞歸方式實現的。

下載程式碼:

https://github.com/onmpw/phpApp

#總結

上面兩種方式各有利弊,雖然實作形式上面不同,但是鑑於無限級欄目的結構,二者實現的機制都是相同的──都藉助堆疊的方式來實現。在現實情況中,我們要根據現實情況的需要選擇一種方式來實現。

推薦文章:

#php實作無限分類樹

php如何實現無限分類樹?本文主要介紹了php簡單實現無限分類樹形列表的方...

php無限分類的開發過程以及實例分析

在我們日常在工作中,常常會遇到很多的分類,我們知道很多開源軟體的無限分類都是採用遞歸的演算法......

以上是PHP實作無限分類的兩種方式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn