lony 发表于 2008-4-13 10:02:33

根据parent_id递归的无限分类和下拉菜单。

先说下,这个对小树来讲还是很快的,大树没有测试,呵呵,递归对大树没什么优势。
数据库设计
id, title, parent_id, last

MODEL:
先来个正常全部列表哦:

function get_list()
{
    $query = $this->db->get('catalog');
    return $query->result_array();
}

在看一个根据parent_id自动生成的多维数组:
function get_tree($parent_id = null)
{
$this->db->where('parent_id',$parent_id);
$this->db->select('id,parent_id,last,title_english');
$query = $this->db->get('catalog');
$list['son'] = $query->result_array();
foreach ($list['son'] as &$row) {
if(array_key_exists('last',$row))
{
if(!$row['last'])
{
$temp = $this->get_tree($row['id']);//这里用了个递归
$row['son'] = $temp['son'];
}
}


}
return $list;
}
下一个是生成视图的下拉列表或者多级的菜单:

function read_tree($tree,$display = array(
'str_out'=>array('open'=>"<ul>\n",'close'=>"</ul>\n"),
'str_in'=> array('open'=>"<li>",'close'=>"</li>\n"),
'blank'=>array('many'=>0,'what'=>' ','increase'=>0),
'attr'=>array('value'=>'id'),
'with_last' => true)
)
{
    $str = "";
    $str .= $display['str_out']['open'];
    foreach ($tree['son'] as $t)
    {
      if(array_key_exists('last',$t))
      {
      $show = true;
      if($t['last']){if(!$display['with_last']){$show = false;}}
      if($show){
          $str .= $display['str_in']['open'];
          if($display['attr'] != array())
          {
            $str = substr($str,0,strlen($str)-1);
            foreach ($display['attr'] as $k=>$v)
            {
            $str .= ' '.$k.'="'.$t[$v].'"';
            }
            $str .= '>';
          }
          for($i=0;$i<$display['blank']['many'];$i++)
          {
            $str .= $display['blank']['what'];
          }
          $str .= $t['title_english'].$display['str_in']['close'];
      }
      }
      if(array_key_exists('son',$t))
      {
      //    print_r($display);
      $str .= $this->read_tree(
      $t,
      array('str_out'=>$display['str_out'],
      'str_in'=>$display['str_in'],
      'blank'=>array(
      'many'=>($display['blank']['many']+$display['blank']['increase']),
      'what'=>$display['blank']['what'],
      'increase'=>$display['blank']['increase']
      ),
      'attr' => $display['attr'],
      'with_last'=>$display['with_last'],
      )
      );
      }
    }
    $str .= $display['str_out']['close'];
    return $str;
}

控制器里调用:

$tree = $this->catalog_model->get_tree();
    echo '<select>';
    echo $this->catalog_model->read_tree($tree,array('str_out'=>array('open'=>'','close'=>''),'str_in'=>array('open'=>'<option>','close'=>'</option>'),'blank'=>array('increase'=>1,'what'=>'    ','many'=>0),'attr'=>array('value'=>'id'),'with_last'=>false));
    echo '</select>';

大家把echo的东西换成变量传递到视图里就可以啦。
参数设置的有点多,但是还是很好用D。
嘿嘿。数据结构学的不好,搞了半个下午。
希望能帮助更多的人。

le_el 发表于 2008-9-18 19:33:33

兄弟,将实例打个包吧。。

testabc111 发表于 2009-10-23 10:13:17

我最担心的就是每次递归就要查一遍数据库,当数据库有1万条数据,你的栏目有50个,那就相当于要递归50次(就是循环50次),查询50次数据库,总数就要查询50万行得出结果。如果是多人cms系统,这种查询方法就很吓人了。

我认为最好的方法是把符合要求的 50条数据先查出来放在一个数组里。然后对数组进行递归或者别的什么方法进行计算。

就和楼主说的,只能使用小树。

有没有高人指点一下大树的递归啊

pk4321 发表于 2009-10-27 17:14:15

本帖最后由 pk4321 于 2009-10-27 17:30 编辑

ptCID        ptPID        ptName        ptRank
1        0        A        0001
3        1        A1        00010001
6        3        A11        000100010001
5        1        A2        00010002
4        1        A3        00010003
2        0        B        0002

至少加个类似上面的最后一列,就完全避免了递归了,但就是添加、移动、删除结点的需要额外的维护!
这样一来,这个树的每个子树最多可以有9999个结点,而整个树的深度 varchar(200) 就有50级!

CI应该增加一个用以上模式的树的一个library

星语 发表于 2012-11-20 14:30:01

分类当然要做成缓存文件,考虑性能的话
页: [1]
查看完整版本: 根据parent_id递归的无限分类和下拉菜单。