建立这种映射关系在一些情况下是非常有用的; 在数据库中存层级结构数据 一种最简单的方式就是 id,pid,attributes... id是主键,pid是上级节点id,结构简单但使用起来就会比较麻烦;
首先,某级节点的子节点或者说后代节点不好查找,查找深度为2以上的父节点 为了效率就需要将所有的数据取出来迭代;虽然有这诸多麻烦,但这种结构维护起来确实非常方便;
好了,进入正题,问题并不是很麻烦,设想一种情况,多层级分类只有叶子节点关联数据,而需要用户点击一个节点(无论是父级还是叶子)都能取出相关的关联数据,那么建立这种关系放在redis等kv nosql数据库中使用起来就会非常方便,先上代码
private function _createMap(){ $connection = Yii::app()->db; $sql = "SELECT id,pid FROM { {nodes}}"; $command = $connection->createCommand($sql); $dataReader = $command->query(); $rows = array(); //struct 子节点 => 父节点 foreach($dataReader as $row){ $rows[$row['id']] = $row['pid']; } $map = array(); while(!empty($rows)){ foreach($rows as $key=>$value){ if(!in_array($key,$rows)){ if(!isset($map[$value])) $map[$value] = array(); if(!empty($map[$key])){ $map[$value] = array_merge($map[$value],$map[$key]); }else{ $map[$value][] = $key; } unset($rows[$key]); } } } foreach($map[0] as $v){ $map[$v]=array($v); } unset($map[0]); return $map;}
这里为了简单直接使用了Yii 的DAO 操作数据库;由于PHP数组的强大秒杀一切LinkedHashMap之类的东东;要充分使用这个优势,
代码中的$rows 是 '子节点'=>'父节点'的数组;$map是最后的结果 '节点'=>array(后代节点中的叶子节点);
下面来一个假设的$rows
$rows =array( array('id'=>1,'pid'=>0), array('id'=>2,'pid'=>1), array('id'=>3,'pid'=>2), array('id'=>4,'pid'=>3), array('id'=>5,'pid'=>4), array('id'=>9,'pid'=>4));
每次foreach将会取出$row里id不再pid里面的节点(当前的叶子节点) 存到$map中,然后unset;这样一次while循环之后就会把id为5,9的元素unset在$map中就会增加array(4=>array(5,9));下一次就会是id为4的依次类推,
到这里,你可能就会发现一个问题,就是如果照这样下去$map 只会存在每层节点的子节点而不是后代节点的叶子节点,所以在存到$map之前要先去判断一下这个id在$map中是否存在了,如果有就需要array_merge让其转换为叶子节点,这样问题就解决了;
下面贴出$map的最后结果;
array( 4 => array(5,9), 3 => array(5,9), 2 => array(5,9), 1 => array(5,9), 5 => array(5), 9 => array(9))
$map[0](pid=0)的为根节点 会存整棵树的叶子节点,将这些叶子节点转换为同样的结构便于使用;查询的时候可以根据ID取出ids OR查询(据说会比IN快一些,没有测试过);
问题并不是很复杂,只适用单父节点的树结构上,我觉得以上是创建这种映射比较快的一种方式,希望不会在 玩算法的高手面前贻笑大方;