建立这种映射关系在一些情况下是非常有用的; 在数据库中存层级结构数据 一种最简单的方式就是 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快一些,没有测试过);
问题并不是很复杂,只适用单父节点的树结构上,我觉得以上是创建这种映射比较快的一种方式,希望不会在 玩算法的高手面前贻笑大方;