左右值编码,文章类别。无限级分类

在网上也搜了很多的例子,根据网络上的解释,慢慢摸索,用了将近2周的时间。笨人,没办法。有什么错的 请留言哦。

在yii php框架下 无限级分类。

通过网络上的,我们都了解到 实现文章 无限级分类,可以使用左右值编码,是通过二叉树的先序遍历 来得到 类别的,不使用递归。这种方法在 全部查询出 类别的时候,是很简单的。

先看数据库表格的设计。

id name lft rht father_id layer
1 顶级分类 1 4 0 0
2 网站底部 2 3 1 1

注释:

  id   ---     类别id

name  ------   类别名称

  lft      ------   左值(left 和right 在mysql 中是关键字,所以用lft 和 rht 来代替)

  rht    -----     右值

  father_id-------   父类的ID

  layer--------       层数(第几层)

现在我们来遍历 二叉树。

左值和右值。

那么某个节点到底有多少子孙节点呢?很简单,子孙总数 =(右值-左值-1)/2

以节点“底部”举例,其子孙总数=(7-2-1)/ 2 = 2  就是 有2 个子孙节点。

类别的增、删、改、查。

类别的增加:

增加,分为两种情况,一是增加顶级分类,即是 新增节点的父类是“顶级分类”,在这种情况下,只需要 将顶级节点的右值加上2.更新一下,然后将该节点的左值等于原“顶级分类”的右值,新增节点的右值=父类的右值+1,增加该节点即可;二是增加的节点是其他顶级分类的子节点,如在“公告”节点下 再新增一个节点——‘公告2’,规则为大于该新增节点的父节点的 右值 都 +2,如 以上的例子,新增节点“公告2”,那么 图为 ;

        

左值 都没有改变。大于11(“公告”右值)的都 +2了。

代码如下:

public function actionAdd(){
       // var_dump($_POST);die();
        if(isset($_POST)){
            $n = $_POST[‘cate‘];
            $fid = $_POST[‘catefather_id‘];
            $bath = dirname(Yii::app()->BasePath);
            $img = Articlecategory::upFile($_FILES,"$bath/uploads/article/",‘jpg,png‘);
           // var_dump($img);
            //echo $img[0];
            //die();增加顶级分类
            if($fid ==1){

                $cate = Articlecategory::model()->find(‘id=:id‘,array(":id"=>$fid));
                $f_rgt = $cate[‘rht‘];
                $c = Articlecategory::model()->updateByPk($fid,array(‘rht‘=>$f_rgt+2));
                $articlecate = new Articlecategory();
                $articlecate->name = $n;
                $articlecate->img_url = "/uploads/article/"."$img[0]";
                $articlecate->img_name = $img[0];
                $articlecate->father_id = $fid;
                $articlecate->lft =$f_rgt;
                $articlecate->rht = $f_rgt+1;
                $articlecate->layer = 2;
                $i = $articlecate->save();
                //var_dump($i);die();

            }else{
                //echo 2;          //给顶级分类 增加子节点。
                $cate = Articlecategory::model()->find(‘id=:id‘,array(":id"=>$fid));
                $f_rgt = $cate[‘rht‘];
                $f_lft = $cate[‘lft‘];
                $layer = $cate[‘layer‘];
                //echo $f_rgt;die();
                $ar = Articlecategory::model()->findAll("rht > :rht ",array(":rht"=>$f_rgt-1));
                //var_dump($ar);die();
                foreach($ar as $v){
                    $v->rht = $v->rht +2;
                    $v->update();
                }
                $ar2 = Articlecategory::model()->findAll(‘lft > :lft‘,array(":lft"=>$f_rgt));
                foreach($ar2 as $v2){
                    $v2->lft = $v2->lft +2;
                    $v2->update();
                }

                //var_dump($c);
                // echo $f_lft;echo $f_rgt;die();
                $articlecate = new Articlecategory();
                $articlecate->name = $n;
                $articlecate->father_id = $fid;
                $articlecate->lft =$f_rgt;
                $articlecate->rht = $f_rgt+1;
                $articlecate->layer = $layer+1;
                $articlecate->img_url = "/uploads/article/"."$img[0]";
                $articlecate->img_name = $img[0];
                $i = $articlecate->save();
                //var_dump($i);

            }
            if($i){
                $this->redirect(‘index‘);
            }
        }
    }

类别的删除

类别的删除,主要是看 要删除的该节点是否有子节点。如果有子节点,是否需要将子节点也一块删除。

代码如下:

  //删除 类别
 public function actionDel(){
        $id = $_POST[‘id‘];
        //$id = $_GET[‘id‘];
        /*
         * 先判定 该节点是否有子类
         */

        $articlecategory_1 = Articlecategory::model()->find("id = :id",array(":id"=>$id));
        $y_rht = $articlecategory_1[‘rht‘];
        $y_lft = $articlecategory_1[‘lft‘];
        $father = $articlecategory_1[‘father_id‘];
     // 1:得到该节点下的子孙节点的个数
        $criteria = new CDbCriteria();
        $criteria->addBetweenCondition(‘lft‘, $y_lft, $y_rht);//
        $criteria->order = "lft asc";
        $criteria->addNotInCondition(‘id‘,array($id));//去除本节点。
        $son = Articlecategory::model()->findAll($criteria);
        $count = count($son);

            if($count == 0){//没有子孙节点的节点
                $i = Articlecategory::model()->find(‘id = :id‘,array(‘:id‘=>$id));
                $yuan_lft = $i[‘lft‘];//本节点的左值
                $yuan_rht = $i[‘rht‘];//本节点的右值
                $father_id = $i[‘father_id‘]; //本节点的父节点 id
                Articlecategory::model()->find(‘id = :id‘,array(‘:id‘=>$id))->delete();//删除该节点
                $a =Articlecategory::model()->find("id = :id",array(":id"=>$father_id));
                $node_lft = $a[‘lft‘];//父节点的左值
                $node_rht = $a[‘rht‘];//父节点的右值
          //左值 >本节点左值的 所有值的 左值 -2; 右值 > 本节点的右值 也全部-2;
                $Articlecate = Articlecategory::model()->findAll("lft > :lft",array(":lft"=>$yuan_lft));
                foreach($Articlecate as $v1){
                    $v1->lft = $v1->lft - 2;
                    $i = $v1->update();
                }
                $article = Articlecategory::model()->findAll("rht > :rht",array(":rht"=>$yuan_rht));
                foreach($article as $v2){
                    $v2->rht = $v2->rht -2;
                    $j = $v2->update();
                }
            }else{         //删除本节点的子孙节点
                Articlecategory::model()->deleteAll($criteria);
                $n = ($count+1)*2;// (n+1)*2, n 是该节点的子孙个数.
                //该节点的父节点 所有右值  >=该右值的所有右值-(n+1)*2

                $articlecategory_2 =Articlecategory::model()->find("id = :id",array(":id"=>$father));
                $rht = $articlecategory_2[‘rht‘];//该父节点的右值;
                $lft = $articlecategory_2[‘lft‘];//该父节点的左值;
                $i = Articlecategory::model()->find(‘id = :id‘,array(‘:id‘=>$id))->delete();//删除本节点

                //全部左值>父节点右值 的 左值 全部要减去 $n.
                $model = Articlecategory::model()->findAll("lft > :lft",array(":lft"=>$rht));
                foreach($model as $v){
                    $v->lft = $v->lft - $n;
                    $i = $v->update();
                }         //全部右值 >本节点的右值的所有 右值 要减去$n。
                $model_2 = Articlecategory::model()->findAll("rht > :rht",array(":rht"=>$y_rht));
                foreach($model_2 as $m){
                    $m->rht = $m->rht - $n;
                    $j = $m->update();
                }

            }

类别的修改

这个是花费时间最长的一个。

主要分为两类。1 向前移动

       2 向后移动

贴代码

 public function actionUpdate(){
        //print_r($_POST);die();
        $id = $_GET[‘id‘];//该节点的id
        $bath = dirname(Yii::app()->BasePath);
        $img = Articlecategory::upFile($_FILES,"$bath/uploads/article/",‘jpg,png‘);
        // 该节点现在的左右值。  更新该节点的名字和父id
        $node_articlecategory1 = Articlecategory::model()->find("id = :id",array(":id"=>$id));
        $node_articlecategory1->name = $_POST[‘name‘];
        $node_articlecategory1->img_url = "/uploads/article/"."$img[0]";
        $node_articlecategory1->img_name = $img[0];
        $node_articlecategory1->father_id = $_POST[‘catefather_id‘];
        $i = $node_articlecategory1->update();
        $node_lft = $node_articlecategory1[‘lft‘];//节点 左值
        $node_rht = $node_articlecategory1[‘rht‘];//节点 右值
        $node_layer = $node_articlecategory1[‘layer‘];//节点 层数
        $old_f_id = $_GET[‘f_old‘]; //原本的父id
        $new_f_id = $_POST[‘catefather_id‘];//新更新的父id
        ////得到该节点的子孙节点个数。
        //$sql = "select * from xv_articlecategory where Lft between ".$node_lft." and ".$node_rht." order by Lft asc";
        $criteria = new CDbCriteria();
        $criteria->addBetweenCondition(‘lft‘, $node_lft, $node_rht);//
        $criteria->order = "lft asc";
        $criteria->addNotInCondition(‘id‘,array($id));//去除本节点。
        $son = Articlecategory::model()->findAll($criteria);
        // var_dump($son);die();
        $n = count($son);     //得到新更新父id的信息
        $new_articlecategory = Articlecategory::model()->find("id = :f_id",array(":f_id"=>$new_f_id));

        $new_lft = $new_articlecategory[‘lft‘];///该节点 新的父类的节点 左右值 层数
        $new_rht = $new_articlecategory[‘rht‘];
        $new_layer = $new_articlecategory[‘layer‘];     //得到原来父id的信息
        $old_articlecategory = Articlecategory::model()->find("id = :f_id",array(":f_id"=>$old_f_id));
        $old_lft = $old_articlecategory[‘lft‘];
        $old_rht = $old_articlecategory[‘rht‘];////该节点 原来的父类 节点左右值。
        $old_layer = $old_articlecategory[‘layer‘];
        //echo $new_rht;

        if($new_rht > $old_rht){
            /*
             * 向后移动
             */        //所有的左值    是  本节点_右值 < left < 新父节点_右值  全部-($n+1)*2;
            $lft_articlecategory= Articlecategory::model()->findAll("lft>$node_rht and lft < $new_rht ");
            //var_dump($lft_articlecategory); die();
            foreach($lft_articlecategory as $v1){
                //$v1->lft = $v1->lft - ($n+1)*2;
                $v1->lft = $v1->lft - ($n+1)*2;
                $i = $v1->update();
                //echo $i;
            }        //所有的右值 是 本节点_右值< rht < 新父节点_右值  全部-($n+1)*2;
            $rht_articlecategory = Articlecategory::model()->findAll("rht>$node_rht and rht < $new_rht");
            //var_dump($rht_articlecategory);
            foreach($rht_articlecategory as $v2){
                $v2->rht = $v2->rht - ($n+1)*2;
                 $j = $v2->update();
               // echo $j;
                //die();
            }       //更新本节点的左右值
            $node_articlecategory = Articlecategory::model()->find("id = :id",array(":id"=>$id));
            $node_articlecategory->rht = $new_rht-1;
            $node_articlecategory->lft = ($new_rht-1) - (2*$n+1);///是根据公式 子孙总数 = (右值 - 左值 -1)/2
            $node_articlecategory->layer = $new_layer+1;
            $node_articlecategory->father_id = $new_f_id;
            $node_articlecategory->update();
            $l = $old_articlecategory[‘layer‘] - $new_articlecategory[‘layer‘];/// 层数的计算:是为子孙 节点 的层数 做打算。
            $son_n =($new_rht-1)-$node_rht; // 本节点_原来_右值 - 本节点_现在_右值 = 差值。差值 也是 子孙节点的差值。
            foreach($son as $v3){
                $v3->lft = $v3->lft +  $son_n;
                $v3->rht = $v3->rht +  $son_n;
                $v3->layer = $v3->layer - $l;
                $v3->update();
            }

        }elseif($new_rht < $old_rht){
            /*
             * 向前移动
             */
            $lft_articlecategory= Articlecategory::model()->findAll("lft>$new_rht-1 and lft < $node_lft ");
            //var_dump($lft_articlecategory);
            foreach($lft_articlecategory as $v1){
                $v1->lft = $v1->lft +($n+1)* 2;
                $v1->update();
            }
            $rht_articlecategory = Articlecategory::model()->findAll("rht>$new_rht-1 and rht < $node_lft");
            foreach($rht_articlecategory as $v2){
                $v2->rht = $v2->rht +($n+1)* 2;
                $v2->update();
            }

            //echo $new_rht;die();
            $f_rht = Articlecategory::model()->find(‘id = :id‘,array(":id"=>$new_f_id));
            $node_articlecategory = Articlecategory::model()->find("id = :id",array(":id"=>$id));
            $node_articlecategory->rht = $new_rht + (2*$n+1);
            $node_articlecategory->lft = $new_rht;
            $node_articlecategory->layer = $new_layer+1;
            $node_articlecategory->father_id = $new_f_id;
            $node_articlecategory->update();
           // var_dump($node_articlecategory);die();
            $l = $old_layer - $new_layer;
            $son_n =abs(($new_rht + (2*$n+1))-$node_rht) ;
            foreach($son as $v3){
                $v3->lft = $v3->lft -  $son_n;
                $v3->rht = $v3->rht -  $son_n;
                $v3->layer = $v3->layer - $l;
                $v3->update();
            }

        }

    }

左右值编码,文章类别。无限级分类

时间: 2024-10-12 04:20:24

左右值编码,文章类别。无限级分类的相关文章

左右值无限级分类 MVC + EntityFramework 的简单实现

在度娘上查了大半个月的资料,最后发现每个网友分享的文章都有一定的错误(PS:大家是故意的么?).最后是在看了一个ASP版本后知道了大概流程:看了一个存储过程实现的文章后知道了大概需要的功能:看了一个SQL语句看到了比较直观的实现:看了一个php示例后才知道最复杂的一个功能的实现.每篇文章都是网友们自己正在使用或已经测试通过的,但都很巧,恰好关键地方就有点出错,不过还是感谢这些资料了,不然我也搞不出来. 因为查了很久的资料,基本上没有可用的,所以一直不敢直接写到项目的DAL里面,就直接在控制器里面

平均数编码:针对某个分类特征类别基数特别大的编码方式

原文:https://zhuanlan.zhihu.com/p/26308272 插入一条信息:特征编码一定要考虑是否需要距离度量,编码方式对距离度量的适应:例如:我们用one-hot编码颜色,向量正交,各个颜色之间的距离等同,如果此处用序数编码显然不太合适,但是我们用one-hot编码星期几就不好了,显然星期一和星期二的距离小于星期一和星期三的距离. 应用条件:某一个特征是分类的,特征的可能值非常多,那么平均数编码是一种高效的编码方式. 适用问题:平均数编码是一种有监督的编码方式,适用于分类和

mysql无限级分类实现基于汇报关系的信息管理权限

汇报关系和家族族谱的实现类似,采用树的数据结构进行定义,树采用递归进行定义.即要嘛是一个根节点,要嘛是由一个根节点和其子树组成.OA中的汇报关系也采用这种结构(与树稍有不同),除董事长外,其他人有且只有一个非其本人的直接主管,董事长的直接主管和越级主管是其本人.从以上的定义其实可以看出,汇报关系类似树,但又与树并不完全相同.除董事长外,其他汇报关系均是树形结构.树形结构采用递归定义,如采用递归查询是非常耗时的操作.比如以下需求: 1.主管可以看到所有直线下属的绩效信息: 针对以上需求,我们提出三

mysql 无限级分类实现思路

第一种方案: 使用递归算法,也是使用频率最多的,大部分开源程序也是这么处理,不过一般都只用到四级分类. 这种算法的数据库结构设计最为简单.category表中一个字段id,一个字段fid(父id).这样可以根据WHERE id = fid来判断上一级内容,运用递归至最顶层. 分析:通过这种数据库设计出的无限级,可以说读取的时候相当费劲,所以大部分的程序最多3-4级分类,这就足以满足需求,从而一次性读出所有的数据,再对得到数组或者对象进行递归.本身负荷还是没太大问题.但是如果分类到更多级,那是不可

无限级分类实现思路 (组织树的分级管理)

关于该问题,暂时自己还没有深入研究,在网上找到几种解决方案,各有优缺点. 第一种方案: 使用递归算法,也是使用频率最多的,大部分开源程序也是这么处理,不过一般都只用到四级分类.这种算法的数据库结构设计最为简单.category表中一个字段id,一个字段fid(父id).这样可以根据WHERE id = fid来判断上一级内容,运用递归至最顶层. 分析:通过这种数据库设计出的无限级,可以说读取的时候相当费劲,所以大部分的程序最多3-4级分类,这就足以满足需求,从而一次性读出所有的数据,再对得到数组

无限级分类实现思路

无限级分类实现思路 关于该问题,暂时自己还没有深入研究,在网上找到几种解决方案,各有优缺点. 第一种方案: 使用递归算法,也是使用频率最多的,大部分开源程序也是这么处理,不过一般都只用到四级分类.这种算法的数据库结构设计最为简单.category表中一个字段id,一个字段fid(父id).这样可以根据WHERE id = fid来判断上一级内容,运用递归至最顶层. 分析:通过这种数据库设计出的无限级,可以说读取的时候相当费劲,所以大部分的程序最多3-4级分类,这就足以满足需求,从而一次性读出所有

php无限级分类

使用递归方法,遍历子类,对数据进行重新排序,使用level进行无限级分类 /** * 功能:无限级分类 * 参数:$data 类别查询结果集 * 返回值:$arr 排序后的数组 */ public function getCateTree($data) { $arr = $this->cateSort($data); return $arr; } /** * 功能:无限级分类排序 * 参数:$data 类别查询结果集 * 返回值:$arr 递归查询排序后的数组 */ public functio

php利用递归函数实现无限级分类

相信很多学php的很多小伙伴都会尝试做一个网上商城作为提升自己技术的一种途径.各种对商品分类,商品名之类的操作应该是得心应手,那么就可以尝试下无限级分类列表的制作了. 什么是无限级分类? 无限级分类是一种分类技巧,例如部门组织,文章分类,学科分类等常用到无限级分类,将其简单理解成分类就好了.其实我们仔细想一下,生活中的分类简直太多了,衣服可以分为男装和女装,也可以分为上衣和裤子,也可以根据年龄段分类.分类无处不在,分类显得“无限”.我这里就不说无限分类的必要性了. 无限级分类原理简介 无限分类看

php无限级分类实战——评论及回复功能

经常在各大论坛或新闻板块详情页面下边看到评论功能,当然不单单是直接发表评论内容那么简单, 可以对别人的评论进行回复,别人又可以对你的回复再次评论或回复,如此反复,理论上可以说是 没有休止,从技术角度分析很容易想到运用无限级分类技术存储数据,运用递归获取评论层级结构 数据,运用ajax实现评论页面交互,这里用thinkphp框架做个简单的demo练练手,为了简化流程 这里第三级评论不再提供回复功能,当然只要在这个基础上稍作修改就可以实现无限回复功能,主 要是view层样式修改较麻烦,需花些时间.