您好,登錄后才能下訂單哦!
利用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怎么實現一個無序樹功能的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。