php左右值实现无限极分类,基于ThinkPHP的二叉树左右值无限极分类实现
说明:
每个数据项都有自己的左值和右值。所有数据的左右值是连续的数字。
① 当右值比左值大1时,表示该数据无子集;
② 当某一数据项的左值大于另一数据项的左值,且该数据项的右值小于同另一数据项的右值时,该数据项属于另一数据项的子集;
例如:中国(1,8) 广东(2,5) 珠海(3,4) 江西(6,7)
数据库表结构:
CREATE TABLE `jd_category` (
`id_category` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(24) NOT NULL,
`lft` int(10) NOT NULL,
`rgt` int(10) NOT NULL,
`level` tinyint(1) NOT NULL,
`is_del` tinyint(1) NOT NULL,
PRIMARY KEY (`id_category`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
BTreeR只用于实现数据读取:
'level',
'lft' => 'lft',
'rgt' => 'rgt',
);
/**
* 获取虚拟的顶级目录
*/
protected function virtualTop(){
return array(
self::$fieldMap['level'] => -1,
self::$fieldMap['lft'] => -1,
self::$fieldMap['rgt'] => ((int)$this->where($this->condition)->max('rgt') + 1),
);
return $this->obj;
}
// 设置当前对象
public function setObj( $obj ){
if( $obj[ $this->getPk() ] && isset($obj[ self::$fieldMap['lft'] ]) && isset($obj[ self::$fieldMap['rgt'] ]) && isset($obj[ self::$fieldMap['level'] ]) ){
$this->obj = $obj;
}else{
$this->obj = false;
}
return $this;
}
// 设置条件参数
public function setCondition( $condition ){
$this->condition = $condition;
return $this;
}
/**
* 是否存在父节点
*/
public function hasParent(){
if( !$this->obj[ $this->getPk() ] || !$this->obj[ self::$fieldMap['level'] ] ){
return false;
}
return true;
}
/**
* 查询父级节点
*
* @param boolean $width_self 是否包含当前节点
*/
public function parents( $width_self = false ){
if( !$this->obj[ $this->getPk() ] ){
return false;
}
$map = $this->condition;
if( $width_self ){
$map[ self::$fieldMap['lft'] ] = array('elt', $this->obj[ self::$fieldMap['lft'] ]);
$map[ self::$fieldMap['rgt'] ] = array('egt', $this->obj[ self::$fieldMap['rgt'] ]);
}else{
$map[ self::$fieldMap['lft'] ] = array('lt', $this->obj[ self::$fieldMap['lft'] ]);
$map[ self::$fieldMap['rgt'] ] = array('gt', $this->obj[ self::$fieldMap['rgt'] ]);
}
$this->where($map)->order( self::$fieldMap['lft'].' asc' );
return $this;
}
/**
* 是否存在子节点
*/
public function hasSub(){
if( $this->obj[ $this->getPk() ] && ($this->obj[ self::$fieldMap['rgt'] ] - $this->obj[ self::$fieldMap['lft'] ] == 1) ){
return false;
}
return true;
}
/**
* 查询子节点
* @param boolean $width_self 是否包含当前节点
*/
public function subs( $width_self = false ){
$map = $this->condition;
if( $this->obj[ $this->getPk() ] ){
if( $width_self ){
$map[ self::$fieldMap['lft'] ] = array('egt', $this->obj[ self::$fieldMap['lft'] ]);
$map[ self::$fieldMap['rgt'] ] = array('elt', $this->obj[ self::$fieldMap['rgt'] ]);
}else{
$map[ self::$fieldMap['lft'] ] = array('gt', $this->obj[ self::$fieldMap['lft'] ]);
$map[ self::$fieldMap['rgt'] ] = array('lt', $this->obj[ self::$fieldMap['rgt'] ]);
}
}
$this->where($map)->order( self::$fieldMap['lft'].' asc' );
return $this;
}
/**
* 把返回的数据集转换成Tree
* @param array $list 数据集合
* @param string $child 存放子集的key
*/
public function toTree($list, $child = '_child' ){
// TODO
}
}
?>
BTreeW继承子 BtreeR,用于实现数据操作:
condition;
if( !$this->obj[ $this->getPk() ] ){
$this->obj = $this->virtualTop();
}
$lft = $this->obj[ self::$fieldMap['rgt'] ];
$data[ self::$fieldMap['level'] ] = $this->obj[ self::$fieldMap['level'] ] + 1;
$data[ self::$fieldMap['lft'] ] = $lft;
$data[ self::$fieldMap['rgt'] ] = $lft + 1;
$this->startTrans();
$insert_id = $this->add($data);
if( !$insert_id ){
$this->rollback();
return false;
}
$map = $this->condition;
$map[ self::$fieldMap['lft'] ] = array('gt', $lft);
$res = $this->where( $map )->setInc( self::$fieldMap['lft'], 2 );
if( false === $res ){
$this->rollback();
return false;
}
$map = $this->condition;
$map[ $this->getPk() ] = array('neq', $insert_id);
$map[ self::$fieldMap['rgt'] ] = array('egt', $lft);
$res = $this->where( $map )->setInc( self::$fieldMap['rgt'], 2 );
if( false === $res ){
$this->rollback();
return false;
}
$this->commit();
return true;
}
/**
* 删除节点及所有子节点
* ① 删除当前节点及其所有子节点
* ② 更改父级右值-$move_count,更改父级右边记录左右值-$move_count
*
* @param string $field 标识删除的字段名
* @param int $value 标识删除的字段值
* @return array 所有删除的节点ID集
*/
public function delInBTree( $field = false, $value = 1 ) {
if( !$this->obj[ $this->getPk() ] ){
return false;
}
$map = $this->condition;
if( $this->obj[ self::$fieldMap['rgt'] ] - $this->obj[ self::$fieldMap['lft'] ] == 1 ){
$del_ids = $this->obj[ $this->getPk() ];
}else{
$map[ self::$fieldMap['lft'] ] = array('egt', $this->obj[ self::$fieldMap['lft'] ]);
$map[ self::$fieldMap['rgt'] ] = array('elt', $this->obj[ self::$fieldMap['rgt'] ]);
$del_ids = $this->where($map)->getField( $this->getPk(), true );
}
if( !$del_ids ){
return false;
}
$this->startTrans();
$this->where(array( $this->getPk() => array('in', $del_ids) ));
if($field){
$res = $this->setField( $field, $value );
}else{
$res = $this->delete();
}
if( !$res ){
$this->rollback();
return false;
}
$move_count = $this->obj[ self::$fieldMap['rgt'] ] - $this->obj[ self::$fieldMap['lft'] ] + 1;
$map = $this->condition;
$map[ self::$fieldMap['lft'] ] = array('gt', $this->obj[ self::$fieldMap['rgt'] ]);
$res = $this->where( $map )->setDec( self::$fieldMap['lft'], $move_count );
if( false === $res ){
$this->rollback();
return false;
}
$map = $this->condition;
$map[ self::$fieldMap['rgt'] ] = array('gt', $this->obj[ self::$fieldMap['rgt'] ]);
$res = $this->where( $map )->setDec( self::$fieldMap['rgt'], $move_count );
if( false === $res ){
$this->rollback();
return false;
}
$this->commit();
return $del_ids;
}
/**
* 节点左右移动
* ① 确定右左移动的节点
* ② 左节点集向右移动$r_move_count
* ③ 右节点集向左移动$l_move_count
*
* @param boolean $move_lft 是否是左移
*/
public function moveLOrRInBTree($move_lft = true){
if( !$this->obj[ $this->getPk() ] ){
return false;
}
$map = $this->condition;
$fields = $this->getPk().','.implode(',', self::$fieldMap);
if( $move_lft ){
$map[ self::$fieldMap['rgt'] ] = $this->obj[ self::$fieldMap['lft'] ] - 1;
$lft = $this->field($fields)->where($map)->find();
$rgt = $this->obj;
}else{
$lft = $this->obj;
$map[ self::$fieldMap['lft'] ] = $this->obj[ self::$fieldMap['rgt'] ] + 1;
$rgt = $this->field($fields)->where($map)->find();
}
if( !$lft || !$rgt ){
return false;
}
$l_move_count = $lft[ self::$fieldMap['rgt'] ] - $lft[ self::$fieldMap['lft'] ] + 1;
$r_move_count = $rgt[ self::$fieldMap['rgt'] ] - $rgt[ self::$fieldMap['lft'] ] + 1;
// 查询需要需要移动的ID集
$map = $this->condition;
if( $lft[ self::$fieldMap['rgt'] ] - $lft[ self::$fieldMap['lft'] ] == 1 ){
$lft_ids = $lft[ $this->getPk() ];
}else{
$map[ self::$fieldMap['lft'] ] = array('egt', $lft[ self::$fieldMap['lft'] ]);
$map[ self::$fieldMap['rgt'] ] = array('elt', $lft[ self::$fieldMap['rgt'] ]);
$lft_ids = $this->where($map)->getField( $this->getPk(), true );
}
if( $rgt[ self::$fieldMap['rgt'] ] - $rgt[ self::$fieldMap['lft'] ] == 1 ){
$rgt_ids = $rgt[ $this->getPk() ];
}else{
$map[ self::$fieldMap['lft'] ] = array('egt', $rgt[ self::$fieldMap['lft'] ]);
$map[ self::$fieldMap['rgt'] ] = array('elt', $rgt[ self::$fieldMap['rgt'] ]);
$rgt_ids = $this->where($map)->getField( $this->getPk(), true );
}
// 执行移动
$this->startTrans();
$res = $this->where( array($this->getPk() => array('in', $lft_ids)) )->save( array(
self::$fieldMap['lft'] => array('exp', self::$fieldMap['lft'].'+'.$r_move_count),
self::$fieldMap['rgt'] => array('exp', self::$fieldMap['rgt'].'+'.$r_move_count),
) );
if( false === $res ){
$this->rollback();
return false;
}
$res = $this->where( array($this->getPk() => array('in', $rgt_ids)) )->save( array(
self::$fieldMap['lft'] => array('exp', self::$fieldMap['lft'].'-'.$l_move_count),
self::$fieldMap['rgt'] => array('exp', self::$fieldMap['rgt'].'-'.$l_move_count),
) );
if( false === $res ){
$this->rollback();
return false;
}
$this->commit();
return true;
}
// TODO
public function moveLevelInBTree(){
}
}
?>
php左右值实现无限极分类,基于ThinkPHP的二叉树左右值无限极分类实现相关推荐
- php 自减函数,Thinkphp中某个字段值从增或自减函数
Thinkphp中某个字段值自增或自减函数 Thinkphp中某个字段值自增或自减函数,可以用于文章的浏览量 /** +---------------------- * 某个字段值自增或自减 +--- ...
- KNN分类器、最近邻分类、KD树、KNN分类的最佳K值、基于半径的最近邻分类器、KNN多分类、KNN多标签分类、KNN多输出分类、KNN分类的优缺点
KNN分类器.最近邻分类.KD树.KNN分类的最佳K值.基于半径的最近邻分类器.KNN多分类.KNN多标签分类.KNN多输出分类.KNN分类的优缺点 目录
- 【图像去噪】基于matlab GUI butterworth+中值+维纳+小波图像去噪【含Matlab源码 520期】
⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[图像去噪]基于matlab GUI butterworth+中值+维纳+小波图像去噪[含Matlab源码 520期] 获取代码方式2: ...
- 阅读笔记3:基于深度学习的运动想象脑电信号分类算法研究
1.论文信息 题目:基于深度学习的运动想象脑电信号分类算法研究 作者佟歌 单位:哈尔滨工程大学控制科学与工程 发表时间:201803 2.笔记 2.1 脑电信号采集及预处理 2.1.1脑电信号分析方法 ...
- 基于哈里斯鹰算法的极限学习机(ELM)分类算法-附代码
基于哈里斯鹰算法的极限学习机(ELM)分类算法 文章目录 基于哈里斯鹰算法的极限学习机(ELM)分类算法 1.极限学习机原理概述 2.ELM学习算法 3.分类问题 4.基于哈里斯鹰算法优化的ELM 5 ...
- 基于k近邻算法的干豆品种分类
摘 要 近年来,干豆由于其较高的营养价值和良好的口感越来越受到人们的欢迎.其种类繁多且易于种植,是世界食用作物中产量最高的一种.干豆品种分类对干豆培育方向.产量需求和品质改良具有重要意义.本文以k近邻 ...
- 基于粒子群算法的极限学习机(ELM)分类算法-附代码
基于粒子群算法的极限学习机(ELM)分类算法 文章目录 基于粒子群算法的极限学习机(ELM)分类算法 1.极限学习机原理概述 2.ELM学习算法 3.分类问题 4.基于粒子群算法优化的ELM 5.测试 ...
- input自适应_【正点原子FPGA连载】第十一章基于OV5640的自适应二值化实验-领航者ZYNQ之HLS 开发指南...
1)摘自[正点原子]领航者ZYNQ之HLS 开发指南 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手 ...
- 【图像去噪】基于matlab GUI均值+中值滤波图像去噪(含PNSR)【含Matlab源码 372期】
⛄一.图像去噪及滤波简介 1 图像去噪 1.1 图像噪声定义 噪声是干扰图像视觉效果的重要因素,图像去噪是指减少图像中噪声的过程.噪声分类有三种:加性噪声,乘性噪声和量化噪声.我们用f(x,y)表示图 ...
最新文章
- UVa 10701 - Pre, in and post
- linux大爱版本Vinux 盲人也能用的OS
- spring boot 启动 nested exception is java.lang.IllegalStateException
- iOS--动画demo--Launch Image淡出效果
- 寻找数组中只出现一次的数
- 关于负载均衡的三种传输模式(反向代理,透传,三角)
- 成功解决‘pip‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
- 【数据结构与算法】之深入解析“扁平化多级双向链表”的求解思路与算法示例
- JS与APP原生控件交互
- 遥感水文前景_遥感水文
- GMP文件分类与编码管理规程
- 您没有权限访问网络计算机,Win7提示“无法访问您可能没有权限使用网络资源”如何解决?...
- 什么是数字式射频信号发生器
- International Collegiate Programming Contest, Egyptian Collegiate Programming Contest (ECPC 2018)
- 镜像站(整理各个镜像站资源)
- 大学生PHP个人博客网站源码 简单个人动态网站设计模板 PHP毕业设计成品 学生PHP MYSQL日志管理系统网页
- 安全设计:加速传输软件镭速传输安全技术解读
- 关于打印机打印网页出现字迹显示不全的问题心得
- 师徒结对活动记录表计算机,师徒结对活动记录表一.doc
- FireFox必备插件(七)
热门文章
- linux驱动之i2c学习
- py2exe——.py文件转换成exe
- Linux下MySQL的几种安装方式
- hashtable、hashmap、ConcurrentHashMap、treemap的区别
- EchoesWorks —— 打造下一代技术Blog/Presentation 框架(招兵买马)
- Samba服务器配置(1)--源码安装
- python获取数据库查询的元数据_Python数据库、MySQL存储引擎、使用分区表、更改表结构、获取数据库元数据...
- python网络开发框架_greenev首页、文档和下载 - Python网络服务框架 - OSCHINA - 中文开源技术交流社区...
- 壁纸引擎java运行库_Microsoft Windows Desktop Runtime v5.0.0 桌面程序运行库(含常规运行库)...
- 2003系统服务器,雨林木风 windows server 2003企业版服务器系统