php无序树实现方法


Posted in PHP onJuly 28, 2015

本文实例讲述了php无序树实现方法。分享给大家供大家参考。具体如下:

运行效果如下图所示:

php无序树实现方法

php代码如下:

<?php
/* 
用php写的无序树
 */
 class unorderedTree{
 // 节点id计数器
 protected $nodeId=0;
 // 树的深度
 protected $depth=0;
 // 树的节点数,
 protected $nodesCount=0;
 // 树的度 @todo: 使其发挥作用
 public $degree=" to be implent";
 // 根节点id
 // 由于树有多种从根节点开始操作,不想每次遍历树到顶找root,用一个变量始终指向根节点
 protected $rootid=null;
 // 子节点集合, k-v 为 nodeid=>(stdclass)node
 // 一些树的实现常常是采用节点和树同一class,这里节点是使用 stdclass{ data, parent, id , childrenIds} ,因我认为节点和树应为两种对象,且stdclass要轻于树的class
 // 节点格式说明: $this->nodes[nodeId] = new stdclass{ id ,parentId, childrenIds, data }
 // id: 节点id
 // parentId: 节点父节点id
 // childrenIds: 子节点的id 不想每次遍历树确定层次关系 
 // 注意: 节点中, #只保存其自身数据和其子节点id的集合#, 子节点的数据通过从树 $tree->nodes[ $node->childrenIds[a_child_id] ] 访问
 // data: 节点中包含的数据,如节点名称等属性数据
 protected $nodes=array();
 // 用户自定义访问节点
 protected $userVisitFunction=null;
 /* 分组: 类的基本函数 */
 // @todo: 构造树
 public function __construct(){
 }
 // @todo: 销毁树 
 public function __destruct(){
  unset($this->nodes) ;
 }
  //------------ 获取数据类函数---------------
  // 获取树的深度,
  public function getTreeDepth(){
  return $this->depth;
  }
  // 获取树的节点数目 
  public function getCount(){
  return $this->NodesCount;
  }
  // 获取树的度 
  public function getDegree(){
  // @todo: 获取树的度(因为对度暂时没什么需要就不实现了 )
  return $this->degree;
  }
  //获取指定节点
  public function getNode($nodeId){
  if(isset($this->Nodes[$nodeId])){
   return $this->Nodes[$nodeId];
  }
  else{
   return false;
  }
  }
  // 获取最新id
  public function getId(){
  return $this->nodeId;
  }
  //获取指定节点高度
  public function getNodeHeight($nodeId){
  if( array_key_exists($nodeId, $this->nodes) ){
   // 此节点已在树里,高度至少为1,每找到一个父节点+1
   $height=1;
   // 记录此树中已经访问过的节点, 用于防止节点构造时互相parent导致此函数死循环且及时结束查找
   $visitedNodesIds=array();
   // 记录当前操作节点的id
   $cid=$nodeId;
   // 当前节点的父节点必须存在于此树中
   // 不用递归
   while( isset($cid) ) {
    if( !in_array($cid,$visitedNodesIds ) ){
     if( $this->rootid===$cid){ //到顶,返回 
      return $height;
     }
     $visitedNodesIds[]=$cid;
     $cid= $this->nodes[ $cid ]->parentId;
     $height++; 
    }
    else{
     return false;
    }
   }
   return false;
  }
  else{
   return false;
  }
  }
  //获取根节点
  public function getRoot(){
  return (!is_null($this->rootid) ) && $this->nodes[$this->rootid];
  }
  //获取指定节点和其所有子节点构成的数组 
  //这是用于获取子树的一个关键基础操作
  public function getSubNodes($nodeId){
  if(isset($this->nodes[$nodeId])){
   $result=array();
   $toVisitNodeIds=array();
   $toVisitedNodeIds[]=$nodeId; 
   $result[]=$this->nodes[$nodeId]->id;
   array_shift($toVisitedNodeIds); 
   $toVisitedNodeIds=array_merge( $toVisitedNodeIds, $this->nodes[$nodeId]->childrenIds);
   while(!empty($toVisitedNodeIds)){
    $toVisitNodeId=array_shift($toVisitedNodeIds);
    $result[]=$this->nodes[$toVisitNodeId]->id;
    $toVisitedNodeIds=array_merge( $toVisitedNodeIds, $this->nodes[$toVisitNodeId]->childrenIds);
   }
   return $result ;
  }
  else{
   return false;
  }
  } 
  //@todo: 获取由指定节点和其所有子节点构建的子树
  public function getSubTree($nodeid){
  }
  //---------------- 数据更新 -----------------
  public function setId($nodeId){
   $this->nodeId=$nodeId;
   return $this;
  }
  // 创建不重复的(树中未被使用的) 新id
  public function seekId(){
  $this->nodeId++;
  return $this->nodeId;
  }
 public function setVisitFunction($userFunction){
  $this->userVisitFunction=$userFunction;
  }
  //插入子节点,默认为插在根节点下
  public function insertNode($parent_id=null , $data=null){
  //注意node不是class tree
  $node = new stdclass; 
  $node->data = $data;
  //树的节点数增加
  $this->nodeCount++;
  // 分配节点id
  $this->seekId();
  $node->id =$this->getId();
  //插入根节点
  if( (is_null($parent_id)) && is_null($this->rootid)){
   $node->parentId = null;
   $node->childrenIds = array();
   $this->depth=1; 
   $this->rootid=$node->id;
   $this->nodes [$node->id]=$node;
   return $this;
  } 
  elseif( isset($this->nodes[$parent_id]) || is_null($parent_id) ){
  // 插在此树已有节点下
   if(is_null($parent_id)){
    $parent_id=$this->rootid;
   }
   $node->parentId = $parent_id;
   $node->childrenIds = array();
   //更新树的最大深度
   $depth=$this->getNodeHeight($parent_id);
   $this->depth=max($depth+1, $this->depth);
   $this->nodes[$parent_id]->childrenIds []= $node->id;
   $this->nodes [$node->id]=$node;
   return $this;
  }
  else{
   return $this; 
  }
  } 
  //insert node 的别名
  public function append($parent_id=null , $data=null){
  return $this->insertNode($parent_id,$data);
  }
  // --------------- 数据访问 -----
  //广度优先遍历节点的别名, 全名太长了
  public function b($nodeId=null){
  return $this->breadthTraversal($nodeId);
  }
  // 广度优先遍历节点
  public function breadthTraversal($nodeId=null){
  if(is_null($this->rootid)){
   die("此树为空树,不可访问");
  }
  else{
   //全部遍历
   if(is_null($nodeId) || ( $this->rootid===$nodeId) ){
    $nodeId=$this->rootid;
   }
   $toVisitNodeIds=array();
   $toVisitedNodeIds[]=$nodeId; 
   $this->visit( $this->nodes[$nodeId]);
   array_shift($toVisitedNodeIds); 
   $toVisitedNodeIds=array_merge( $toVisitedNodeIds, $this->nodes[$nodeId]->childrenIds);
   while(!empty($toVisitedNodeIds)){
    $toVisitNodeId=array_shift($toVisitedNodeIds);
    $this->visit( $this->nodes[$toVisitNodeId]);
    $toVisitedNodeIds=array_merge( $toVisitedNodeIds, $this->nodes[$toVisitNodeId]->childrenIds);
   }
  }
  return $this;
  }
  //深度优先的别名
  public function d($nodeId=null){
  return $this->depthTraversall($nodeId);
  }
  // 深度优先遍历
  // 和广度优先的不同实现只在于array_merge的顺序不同而已 ( php array 忒好用啊忒好用 )
  public function depthTraversall($nodeId=null){
  if(is_null($this->rootid)){
   die("此树为空树,不可访问");
  }
  else{
   //全部遍历
   if(is_null($nodeId)){
    $nodeId=$this->rootid;
   }
   $toVisitNodeIds=array();
   $toVisitedNodeIds[]=$nodeId; 
   $this->visit( $this->nodes[$nodeId]);
   array_shift($toVisitedNodeIds); 
   $toVisitedNodeIds=array_merge( $this->nodes[$nodeId]->childrenIds, $toVisitedNodeIds );
   while(!empty($toVisitedNodeIds)){
    $toVisitNodeId=array_shift($toVisitedNodeIds);
    $this->visit( $this->nodes[$toVisitNodeId]);
    $toVisitedNodeIds=array_merge( $this->nodes[$toVisitNodeId]->childrenIds, $toVisitedNodeIds );
   }
  }
  return $this;
  }
  //访问单个节点
  public function visit($node){
  if(is_null($this->userVisitFunction )){
   return $node->id;
  }
  else{
   return call_user_func($this->userVisitFunction,$node,$this);
  }
  }
 }
?>

希望本文所述对大家的php程序设计有所帮助。

PHP 相关文章推荐
用PHP和MySQL保存和输出图片
Oct 09 PHP
PHP 增加了对 .ZIP 文件的读取功能
Oct 09 PHP
简单的PHP图片上传程序
Mar 27 PHP
PHP中$_SERVER的详细参数与说明
Jul 29 PHP
Cannot modify header information错误解决方法
Oct 08 PHP
$_GET['goods_id']+0 的使用详解
Jun 06 PHP
PHP将session信息存储到数据库的类实例
Mar 04 PHP
深入浅出php socket编程
May 13 PHP
PHP按指定键值对二维数组进行排序的方法
Dec 22 PHP
DEDE实现转跳属性文档在模板上调用出转跳地址
Nov 04 PHP
PHP5.6读写excel表格文件操作示例
Feb 26 PHP
PHP7内核CGI与FastCGI详解
Apr 14 PHP
分享PHP函数实现数字与文字分页代码
Jul 28 #PHP
PHP实现简单汉字验证码
Jul 28 #PHP
PHP代码实现表单数据验证类
Jul 28 #PHP
在Mac上编译安装PHP7的开发环境
Jul 28 #PHP
详谈PHP编码转换问题
Jul 28 #PHP
php技术实现加载字体并保存成图片
Jul 27 #PHP
php实现向javascript传递数组的方法
Jul 27 #PHP
You might like
php cc攻击代码与防范方法
2012/10/18 PHP
PHP调用存储过程返回值不一致问题的解决方法分析
2016/04/26 PHP
PHP实现用户登录的案例代码
2018/05/10 PHP
详解阿里云视频直播PHP-SDK接入教程
2020/07/09 PHP
如何确保JavaScript的执行顺序 之jQuery.html深度分析
2011/03/03 Javascript
JavaScript实现表格排序方法
2013/06/14 Javascript
前端开发过程中浏览器版本的两种判定方法
2013/10/30 Javascript
多种方法实现load加载完成后把图片一次性显示出来
2014/02/19 Javascript
jQuery实现按键盘方向键翻页特效
2015/03/18 Javascript
JQuery中DOM事件绑定用法详解
2015/06/13 Javascript
微信小程序商城项目之侧栏分类效果(1)
2017/04/17 Javascript
vue.js实现格式化时间并每秒更新显示功能示例
2018/07/07 Javascript
Angular6笔记之封装http的示例代码
2018/07/27 Javascript
JavaScript代码调试方法实例小结
2019/01/05 Javascript
详解React中合并单元格的正确写法
2019/01/08 Javascript
JS实现滑动导航效果
2020/01/14 Javascript
详解vue中在循环中使用@mouseenter 和 @mouseleave事件闪烁问题解决方法
2020/04/07 Javascript
Python将xml和xsl转换为html的方法
2015/03/10 Python
python编码最佳实践之总结
2016/02/14 Python
python print 按逗号或空格分隔的方法
2018/05/02 Python
Python实现的根据文件名查找数据文件功能示例
2018/05/02 Python
python利用百度AI实现文字识别功能
2018/11/27 Python
PyCharm使用Docker镜像搭建Python开发环境
2019/12/26 Python
浅谈pytorch torch.backends.cudnn设置作用
2020/02/20 Python
pycharm实现在虚拟环境中引入别人的项目
2020/03/09 Python
python datetime处理时间小结
2020/04/16 Python
python实现一个简单RPC框架的示例
2020/10/28 Python
python多线程和多进程关系详解
2020/12/14 Python
CSS3盒子模型详解
2013/04/24 HTML / CSS
澳大利亚男士西服品牌:M.J.Bale
2018/02/06 全球购物
澳洲女装时尚在线:Blue Bungalow
2018/05/05 全球购物
西班牙最好的在线购买葡萄酒的商店:Vinoseleccion
2019/10/30 全球购物
校园摄影活动策划方案
2014/02/05 职场文书
2014年党的群众路线教育实践活动整改措施(个人版)
2014/09/25 职场文书
婚礼嘉宾致辞
2015/07/28 职场文书
《唯一的听众》教学反思
2016/02/18 职场文书