递归和非递归算法生成树形数组

记一次遗忘的树形处理逻辑
    最近在小论文数据展示中,刚好我使用的echat插件来展示本体树结构,但是这个插件所需要的数据是树形数据,数据格式如下:

{
    "name": "flare",
    "children": [
        {
            "name": "data",
            "children": [
                {
                     "name": "converters",
                     "children": [
                      {"name": "Converters", "value": 721},
                      {"name": "DelimitedTextConverter", "value": 4294}
                     ]
                },
                {
                    "name": "DataUtil",
                    "value": 3322
                }
            ]
        },
        {
            "name": "display",
            "children": [
                {"name": "DirtySprite", "value": 8833},
                {"name": "LineSprite", "value": 1732},
                {"name": "RectSprite", "value": 3623}
           ]
        },
        {
            "name": "flex",
            "children": [
                {"name": "FlareVis", "value": 4116}
            ]
        }
    ]
}

处理方法A

    这时候的第一想法就是使用递归,递归算法要求的源数据的格式为:['id'=> 1, name='第一个节点','pid'=>'父级节点'] ,每一个节点的记录格式都是这样的即可满足树形数组的构建。
     代码逻辑:
$data = [

    [
        'id' => 1,
        'name' => '菜单一',
        'pid' => 0
    ],
    [
        'id' => 11,
        'name' => '菜单一点一',
        'pid' => 1
    ],
    [
        'id' => 12,
        'name' => '菜单一点二',
        'pid' => 1
    ],
    [
        'id' => 13,
        'name' => '菜单一点三',
        'pid'=>1
    ],
    [
        'id' => 2,
        'name' => '菜单二',
        'pid' => 0
    ],
    [
        'id' => 21,
        'name' => '菜单二点一',
        'pid' => 2
    ],
    [
        'id' => 111,
        'name' => '菜单一点一点一',
        'pid' => 11
    ],
    [
        'id' => 112,
        'name' => '菜单一点一点二',
        'pid' => 11
    ],
    [
        'id' => 113,
        'name' => '菜单一点一点三',
        'pid' => 11
    ],
    [
        'id' => 121,
        'name' => '菜单一点二点一',
        'pid' => 12
    ],
    [
        'id' => 1111,
        'name' => '菜单一点一点一点一',
        'pid' => 111
    ],
    [
        'id' => 1112,
        'name' => '菜单一点一点一点二',
        'pid' => 111
    ]
];

$parent = [];
getTree($parent,0,$data);
echo json_encode($parent['children'],256);

/**
 * 建立树形结构
 * @param $parent
 * @param $id
 * @param $data
 */
function getTree(&$parent, $id, $data){

    $child = getChildren($id,$data);
    if(!empty($child)){
        $i = 0;
        foreach ($child as $item){
            $parent['children'][$i] = $item;
            //依靠当前父节点的索引,来向下继续传递父级:$parent['children'][$i]
            getTree($parent['children'][$i],$parent['children'][$i]['id'],$data);
            $i++;
        }
    }
}

/**
 * 获取孩子节点
 * @param $id
 * @param $data
 * @return array
 */
function getChildren($id, $data){
    $child = [];
    foreach ($data as $item){
        if($item['pid'] == $id){
            $child[] = $item;
        }
    }
    return $child;
}

结果

    注释:依照先跟遍历的想法,依次找孩子,找孩子的孩子,往下找孩子的时候,传入父亲的地址,之后回溯找下一个孩子,找下一个孩子的孩子,最后即完成树形的构建。

处理方法B

    使用非递归的方式也可以解决问题,只不过非递归的方式要求数据源格式需要含有层级关系,即为该节点是第几层级的节点,数据源的格式为:['id'=> 1, name='第一个节点',level='1', 'pid'=>'父级节点'],按照层级进行降序排列,然后先封装最底层的,然后依次往上层组装孩子节点。      代码逻辑:
$data = [

    [
        'id' => 1,
        'name' => '菜单一',
        'pid' => 0,
        'level' => 1
    ],
    [
        'id' => 11,
        'name' => '菜单一点一',
        'pid' => 1,
        'level' => 2
    ],
    [
        'id' => 12,
        'name' => '菜单一点二',
        'pid' => 1,
        'level' => 2
    ],
    [
        'id' => 13,
        'name' => '菜单一点三',
        'pid'=>1,
        'level' => 2
    ],
    [
        'id' => 2,
        'name' => '菜单二',
        'pid' => 0,
        'level' => 1
    ],
    [
        'id' => 21,
        'name' => '菜单二点一',
        'pid' => 2,
        'level' => 2
    ],
    [
        'id' => 111,
        'name' => '菜单一点一点一',
        'pid' => 11,
        'level' => 3
    ],
    [
        'id' => 112,
        'name' => '菜单一点一点二',
        'pid' => 11,
        'level' => 3
    ],
    [
        'id' => 113,
        'name' => '菜单一点一点三',
        'pid' => 11,
        'level' => 3
    ],
    [
        'id' => 121,
        'name' => '菜单一点二点一',
        'pid' => 12,
        'level' => 3
    ],
    [
        'id' => 1111,
        'name' => '菜单一点一点一点一',
        'pid' => 111,
        'level' => 4
    ],
    [
        'id' => 1112,
        'name' => '菜单一点一点一点二',
        'pid' => 111,
        'level' => 4
    ]
];

//进行排序

function sortByLevel(&$data){

    foreach ($data as $item){
        $flag[] = $item['level'];
    }

    array_multisort($flag,SORT_DESC,$data);
}

//进行建树
function createTree($data){
    $nodeLevelList = [];
    foreach ($data as $key => &$item){
        $children = isset($nodeLevelList[$item['id']]['children']) ? $nodeLevelList[$item['id']]['children'] : [];
        //如果孩子不为空的话
        if(!empty($children)){
            //合并自己的孩子
            $item = array_merge($item,['children'=>$children]);
        }

        //如果不是定级的话
        if($item['pid'] !=0){
            //指定父级的孩子为自己下的数组
            $nodeLevelList[$item['pid']]['children'][] = $item;
            //释放掉自己所占资源
            unset($nodeLevelList[$item['id']]);
        }else{
            //如果节点是定级,就不能再找父级,到此结束
            $nodeLevelList[$item['id']] =$item;
        }
    }
    return $nodeLevelList;
}
sortByLevel($data);
$tree = createTree($data);
echo json_encode($tree,256);

结果

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值