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 相关文章推荐
PHP5 安装方法
Jan 15 PHP
php下的权限算法的实现
Apr 28 PHP
php array的学习笔记
May 16 PHP
php类中private属性继承问题分析
Nov 01 PHP
PHP错误Cannot use object of type stdClass as array in错误的解决办法
Jun 12 PHP
ECSHOP在PHP5.5及高版本上报错的解决方法
Aug 31 PHP
非常有用的9个PHP代码片段
Apr 06 PHP
浅谈PHP检查数组中是否存在某个值 in_array 函数
Jun 13 PHP
PHP入门教程之自定义函数用法详解(创建,调用,变量,参数,返回值等)
Sep 11 PHP
php中通过eval实现字符串格式的计算公式
Mar 18 PHP
ThinkPHP实现登录退出功能
Jun 29 PHP
windows下的WAMP环境搭建图文教程(推荐)
Jul 27 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
为了这两部电子管收音机,买了6套全新电子管和10粒刻度盘灯泡
2021/03/02 无线电
PHP源码之explode使用说明
2011/08/05 PHP
PHP代码网站如何防范SQL注入漏洞攻击建议分享
2012/03/01 PHP
PHP中Notice错误常见解决方法
2017/04/28 PHP
贴一个在Mozilla中常用的Javascript代码
2007/01/09 Javascript
基于jQuery的日期选择控件
2009/10/27 Javascript
网页上的Javascript编辑器和代码格式化
2010/04/25 Javascript
一些有用的JavaScript和jQuery的片段分享
2011/08/23 Javascript
关于javascript中的typeof和instanceof介绍
2012/12/04 Javascript
JQuery调用WebServices的方法和4个实例
2014/05/06 Javascript
ECMAScript6的新特性箭头函数(Arrow Function)详细介绍
2014/06/07 Javascript
jQuery函数map()和each()介绍及异同点分析
2014/11/08 Javascript
javascript arguments使用示例
2014/12/16 Javascript
jQuery绑定事件的几种实现方式
2016/05/09 Javascript
Javascript中数组去重与拍平的方法示例
2017/02/03 Javascript
深入理解 webpack 文件打包机制(小结)
2018/01/08 Javascript
详解javascript对数组和json数组的操作
2019/04/15 Javascript
vue-cli2与vue-cli3在一台电脑共存的实现方法
2019/09/25 Javascript
vue.js的状态管理vuex中store的使用详解
2019/11/08 Javascript
vue 项目@change多个参数传值多个事件的操作
2021/01/29 Vue.js
用Python实现一个简单的多线程TCP服务器的教程
2015/05/05 Python
Python学习入门之区块链详解
2017/07/25 Python
pandas.cut具体使用总结
2019/06/24 Python
Django认证系统user对象实现过程解析
2020/03/02 Python
Python 字节流,字符串,十六进制相互转换实例(binascii,bytes)
2020/05/11 Python
基于Python爬取股票数据过程详解
2020/10/21 Python
python实现一个简单RPC框架的示例
2020/10/28 Python
HTML5触摸事件(touchstart、touchmove和touchend)的实现
2020/05/08 HTML / CSS
物业工作计划书
2014/01/10 职场文书
生物制药专业自我鉴定
2014/02/19 职场文书
优秀班集体先进事迹材料
2014/05/28 职场文书
会计电算化专业求职信
2014/06/10 职场文书
奥巴马上海演讲稿
2014/09/10 职场文书
个人授权委托书模板
2014/09/14 职场文书
护士心得体会范文
2016/01/25 职场文书
MySQL数据库如何使用Shell进行连接
2022/04/12 MySQL