對ecshop無限級分類的解析,認真分析後發現真的其算法仍是比較精典的其實並不難理解,有舉例方便你們理解 function cat_options($spec_cat_id, $arr) { static $cat_options = array(); if (isset($cat_options[$spec_cat_id])) { return $cat_options[$spec_cat_id]; } /* 初始化關鍵參數: $level:當前子節點深度 $last_cat_id:當前父節點ID $options:帶有縮進級別的數組 $cat_id_array:沿同一路徑的父節點依次進駐 $level_array:該節點的子節點深度,也是依次進駐 */ if (!isset($cat_options[0])) { $level = $last_cat_id = 0; $options = $cat_id_array = $level_array = array(); while (!empty($arr))//若是還有待構造的節點則繼續遍歷 { foreach ($arr AS $key => $value) { $cat_id = $value['cat_id']; //一級分類結點 if ($level == 0 && $last_cat_id == 0) { if ($value['parent_id'] > 0) { break; } $options[$cat_id] = $value; $options[$cat_id]['level'] = $level; $options[$cat_id]['id'] = $cat_id; $options[$cat_id]['name'] = $value['cat_name']; //遍歷過了就再也不遍歷 unset($arr[$key]); if ($value['has_children'] == 0) { continue; } $last_cat_id = $cat_id;//下層結點的父親結點 $cat_id_array = array($cat_id); $level_array[$last_cat_id] = ++$level; continue; } //當前結點的父親結點ID等於它的上一級結點ID if ($value['parent_id'] == $last_cat_id) { $options[$cat_id] = $value; $options[$cat_id]['level'] = $level; $options[$cat_id]['id'] = $cat_id; $options[$cat_id]['name'] = $value['cat_name']; unset($arr[$key]);//遍歷過了就再也不遍歷 //若是當前結點有孩子則當前結點要進駐,但再也不遍歷;反之不進駐也再也不遍歷 if ($value['has_children'] > 0) { if (end($cat_id_array) != $last_cat_id) { $cat_id_array[] = $last_cat_id; } $last_cat_id = $cat_id;//當現結點作爲下一級結點的新的父親結點 $cat_id_array[] = $cat_id;//進駐 $level_array[$last_cat_id] = ++$level;//當前結點的下一級結點深度 } } elseif ($value['parent_id'] > $last_cat_id) {//若是當前結點父親深度大於目前父親結點的深度則進行下一輪循環 break; } }//endforeach $count = count($cat_id_array); if ($count > 1) { //取出最後進駐的父親節點做爲當前父親節點 $last_cat_id = array_pop($cat_id_array); } elseif ($count == 1) { if ($last_cat_id != end($cat_id_array)) { //進駐的父親結點只有一個時而且沒有做爲當前父親節點時把它取出 $last_cat_id = end($cat_id_array); } else { //不然最後取出的父親結點必定是一級分類結點 $level = 0; $last_cat_id = 0; $cat_id_array = array(); continue; } } if ($last_cat_id && isset($level_array[$last_cat_id])) { //取出當前結點的深度 $level = $level_array[$last_cat_id]; } else { $level = 0; } }//end while,此時已完成非遞歸前序遍歷構造樹的工做,其中$options已保存了從根結點開始的全部結點帶有分層性質的數組 $cat_options[0] = $options; } else { $options = $cat_options[0]; } //若是從0開始即取整個樹則直接返回再也不處理. if (!$spec_cat_id) { return $options; } //不然開始從指定結點截取,如下比較簡單我仍是稍微說說吧,要說就說幾個參數含義吧 /* $spec_cat_id_level:截取結點的深度 $spec_cat_id_array:最終返回的以該結點爲根結點的一棵商品分類樹 最終返回的數組是這樣排序的:按父親結點大小,按直接父親結點,按同一父親結點這樣的先根遍歷,具個例子: 一級結點有1,5 二級結點有2,6,7 三級結點有8,9,若是1的直接孩子是2,6而2的直接孩子是8,9;另外 5的直接孩子是7那麼最終的數組是這樣排列的1->2->8->9->6->5->7 */ else { if (empty($options[$spec_cat_id])) { return array(); } $spec_cat_id_level = $options[$spec_cat_id]['level']; foreach ($options AS $key => $value) { if ($key != $spec_cat_id) { unset($options[$key]); } else { break; } } $spec_cat_id_array = array(); foreach ($options AS $key => $value) { if (($spec_cat_id_level == $value['level'] && $value['cat_id'] != $spec_cat_id) || ($spec_cat_id_level > $value['level'])) { break; } else { $spec_cat_id_array[$key] = $value; } } $cat_options[$spec_cat_id] = $spec_cat_id_array; return $spec_cat_id_array; } }