ecshop 無限分類解析(轉)

對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;
    }
}
相關文章
相關標籤/搜索