前序遍历树算法实现无限级分类

分类的话一般用的都是无限极分类,无限极分类的有点是灵活,容易插入,但是在分类量特别大的情况下,使用前序遍历树算法代替无限极分类更好,因为当分类特别多的时候无限极分类的查询是每次都要查询所有,所以前序遍历树算法在此方面的能更好的。当然如果分类涉及经常变更,更改。无限极分类还是有他的有点。在此,分享一个自己的实现类。

<?php
/**
* 前序遍历树算法实现无限极分类
* @author zaizai
* @link http://www.tuhuokeji.com
*/
class Category
{
private $tablename = null;
public function __construct($tablename)
{
if(is_null($this->$tablename)){
$this->tablename = $tablename;
}
}
/**
* 设置表名
* @Author   zaizai
* @DateTime 2016-04-02T11:31:39+0800
* @param    string                   $tablename [description]
*/
public function setTbale(string $tablename)
{
return $this->tablename = $tablename;
}
public function getTable()
{
return $this->tablename;
}
/**
* 显示树状结构
* @Author   zaizai
* @DateTime 2016-04-02T11:33:33+0800
* @return   [type]                   [description]
*/
public function view($pageindex,$pagesize,$where = '')
{            
$total = pdo_fetchcolumn('select count(id) from '.tablename($this->tablename).' where id!=1');
$list = pdo_fetchAll('select * from '.tablename($this->tablename).$where.' order by lft asc  limit ' . ($pageindex - 1) * $pagesize . ',' . $pagesize);
$pager = pagination($total, $pageindex, $pagesize);
//两个循环而已,没有递归
$parent = array();
$arr_list = array();
foreach($list as $item){
if(count($parent)){
while (count($parent) -1 > 0 && $parent[count($parent) -1]['rgt'] < $item['rgt']){
array_pop($parent);
}
}
$item['depath'] = count($parent);
$parent[]  = $item;
$arr_list[]= $item;
}
//显示树状结构
foreach($arr_list as $k=> $a)
{
if($a['id'] != 1 ){
if($a['depath'] !=1){
$arr_list[$k]['view'] = str_repeat("&nbsp;&nbsp;&nbsp;&nbsp;", $a['depath']).'|---';
}
}else{
unset($arr_list[$k]);
}
}
return array('list'=>$arr_list,'pager'=>$pager);
}
/**
* 插入操作很简单找到其父节点,之后把左值和右值大于父节点左值的节点的左右值加上2,之后再插入本节点,左右值分别为父节点左值加一和加二
* @Author   zaizai
* @DateTime 2016-04-02T11:34:01+0800
* @param    [type]                   $parent_id [description]
* @param    [type]                   $data      [description]
*/
public function add($parent_id,$data)
{
$parent_id = empty($parent_id)?1:$parent_id;
//获取到父级分类的lft rgt
$parent_category = pdo_get($this->tablename,array('id'=>$parent_id),array('lft','rgt','id'));
// 1.左值和右值大于父节点左值的节点的左右值加上2
if(!empty($parent_category)){
pdo_query('update '.tablename($this->tablename).' set lft=lft+2 where lft >'.$parent_category['lft']);
pdo_query('update '.tablename($this->tablename).' set rgt=rgt+2 where rgt >'.$parent_category['lft']);
}
$data = array_merge(array('lft'=>$parent_category['lft']+1,'rgt'=>$parent_category['lft']+2),$data);
return pdo_insert($this->tablename,$data);
}
/**
* 删除
* 
* #1.得到删除的节点,将右值减去左值然后加1,得到值$width = $rgt - $lft + 1;
* #2.删除左右值之间的所有节点
* #3.修改条件为大于本节点右值的所有节点,操作为把他们的左右值都减去$width
* @Author   zaizai
* @DateTime 2016-04-02T11:36:44+0800
* @param    int                   $id 删除的节点id
* @return   bool                       返回值
*/
public function delete($id)
{
//通过分类id获取分类
$category = pdo_get($this->tablename,array('id'=>$id),array('id','lft','rgt'));
//计算$width
$width = $category['rgt'] - $category['lft'] + 1;
// 1.删除该条分类
$res = pdo_delete($this->tablename,array('id'=>$id));
// 2.删除左右值之间的所有分类
pdo_query('delete from '.tablename($this->tablename).' where lft>:lft and lft<:rgt and id!=1',array(':lft'=>$category['lft'],':rgt'=>$category['rgt']));
// 3.修改其它节点的值        
$res1 = pdo_update($this->tablename,array('lft'=>"lft-{$width}"),array('lft'=>$category['rgt']));
$res2 = pdo_update($this->tablename,array('rgt'=>"rgt-{$width}"),array('rgt'=>$category['rgt']));
return $res;
}
/**
* 编辑节点
* @Author   zaizai
* @DateTime 2016-04-02T11:34:58+0800
* @param    int                   $id   节点名称
* @param    array                   $data 入库的数据
* @return   bool                         返回值
*/
public function edit($id,$data)
{
//不用说了, 直接通过id编辑
return pdo_update($this->tablename,$data,array('id'=>$id));
}
//获取子孙
public function getSons($id)
{
$item = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$id));
if($item){
$sql = 'SELECT `id`,`title`,`lft`,`rgt` FROM '.tablename($this->tablename).' WHERE `lft`>='.$item['lft'].' AND `rgt`<='.$item['rgt'];
return pdo_fetchAll($sql);
}
return false;
}
/**
* 获取子类的直接父类
* @Author   zaizai
* @DateTime 2016-05-03T11:00:43+0800
* @param    int                   $sonid    子类的id  
* @return   array|false                          直接父类
*/
public function getParent($sonid)
{
$item = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$sonid));
if($item){
$sql = 'SELECT `id`,`title`,`lft`,`rgt` FROM '.tablename($this->tablename).' WHERE `lft`<'.$item['lft'].' AND `rgt`>'.$item['rgt'].' order by rgt asc limit 1';
return pdo_fetch($sql);
}
return false;
}
/**
* 获取所有的子类
* @Author   zaizai
* @DateTime 2016-05-03T11:00:05+0800
* @param    int                   $sonid 子类的id
* @return   array                          所有的父类
*/
public function getParents($sonid)
{
$item = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$sonid));
if($item){
$sql = 'SELECT `id`,`title`,`lft`,`rgt` FROM '.tablename($this->tablename).' WHERE `lft`<'.$item['lft'].' AND `rgt`>'.$item['rgt'];
return pdo_fetchAll($sql);
}
return false;
}
/**
* 取出第几级
* @Author   zaizai
* @DateTime 2016-05-13T18:07:09+0800
* @param    [type]                   $depath 层级
* @return   [type]                           [description]
*/
public function get_Paret($depath = 1)
{
$list = pdo_fetchAll('select * from '.tablename($this->tablename) .' where status=:status  order by lft asc',array(':status'=>0));
//两个循环而已,没有递归
$parent = array();
$arr_list = array();
foreach($list as $k => $item){
if(count($parent)){
while (count($parent) -1 > 0 && $parent[count($parent) -1]['rgt'] < $item['rgt']){
array_pop($parent);
}
}
$item['depath'] = count($parent);
$parent[]  = $item;
$arr_list[]= $item;
if($item['id'] != 1 ){
if($item['depath'] == $depath){
$aa[] = $item;
//按照sort排序
foreach ($aa as $key => $row)
{
$vals[$key] = $row['sort'];
}
array_multisort($vals, SORT_ASC, $aa);
}
}else{
unset($list[$k]);
}         
}
return $aa;
}
/**
* 取出某父级的第几级子级
* @Author   zaizai
* @DateTime 2016-05-13T18:07:09+0800
* @param    [type]                   $depath 层级
* @return   [type]                           [description]
*/
public function get_sons_level($id,$depath = 1)
{
$abc = pdo_fetch('select * from '.tablename($this->tablename).' where id=:id',array(':id'=>$id));
if($abc){
$list = pdo_fetchAll('select * from '.tablename($this->tablename).' WHERE `lft`>='.$abc['lft'].' AND `rgt`<='.$abc['rgt'] .' order by lft asc');
}
//两个循环而已,没有递归
$parent = array();
$arr_list = array();
foreach($list as $k => $item){
if(count($parent)){
while (count($parent) -1 > 0 && $parent[count($parent) -1]['rgt'] < $item['rgt']){
array_pop($parent);
}
}
$item['depath'] = count($parent);
$parent[]  = $item;
$arr_list[]= $item;
if($item['id'] != 1 ){
if($item['depath'] == $depath){
$aa[] = $item;
//按照sort排序
foreach ($aa as $key => $row)
{
$vals[$key] = $row['sort'];
}
array_multisort($vals, SORT_ASC, $aa);
}
}else{
unset($list[$k]);
}
}
return $aa;
}
//测试排序
public function test_sort($where=''){
foreach ($this->get_Paret(1) as $v){   //PHP<5.5   用这个
$parentid[]=$v['id'];
}
for ($i=0;$i<count($parentid);$i++){
$sons[$parentid[$i]]= ($this->get_sons_level($parentid[$i],1));
}
foreach ($sons as $k=>$v){
$sons[$parentid[$k]]=$v[$k];
}
foreach ($this->get_Paret(1) as $k=>$v){   //PHP<5.5   用这个
$parent[]=$v;
}
foreach ($this->get_Paret(2) as $v){   //PHP<5.5   用这个
$sonsid[]=$v['id'];
}
for ($i=0;$i<count($sonsid);$i++){
$sun[$sonsid[$i]]= ($this->get_sons_level($sonsid[$i],1));
}
foreach ($sun as $k=>$v){
$sun[$sonsid[$k]]=$v[$k];
}
return  $this->name($parent,$sons,$sun);
}
public function name($a,$b,$c)
{
$list = array();
$list[] = $a;
$list[] = $b;
$list[] = $c;
return $list;
}
}
原文地址:https://www.cnblogs.com/gyrgyr/p/6806743.html