数据结构之从链表而来的森林

公司项目有个需求,用户通过网页对目录结果进行编辑后,产生了如下的数组结构,后台需要对这个数组转换成一个森林,然后方便的进行渲染。

这个数组原型大概如下图,

|—— 根目录 level:-1
    |—— 目录A level:0
        |—— 目录A_1 level:1
            |—— 目录A_1_1 level:2
        |—— 目录A_2 level:1
            |—— 目录A_2_1 level:2
                |—— 目录A_2_1_1 level:3
                    |—— 目录A_2_1_1_1 level:4
        |—— 目录A_3 level:1
            |—— 目录A_3_1 level:2
            |—— 目录A_3_2 level:2
    |—— 目录B level:0
        |—— 目录B_1 level:1
            |—— 目录B_1_1 level:2
                |—— 目录B_1_1_1 level:3
        |—— 目录B_2 level:1
    |—— 目录C level:0
    ..........

数组结果类似下图(上面的结构和下面的数组并不匹配,只是一个栗子)

[
    {
        value: '根目录',
        level: -1,
        childs: [],
    },
    {
        value: '目录A',
        level: 0,
        childs: []
    },
    {
        value: '目录A_1',
        level: 1,
        childs: []
    },
    {
        value: '目录A_1_1',
        level: 2,
        childs: []
    },
    {
        value: '目录A_2',
        level: 1,
        childs: []
    },
    {
        value: '目录B',
        level: 0,
        childs: []
    },
    {
        value: '目录B_1',
        level: 1,
        childs: []
    },
    {
        value: '目录B_1_1',
        level: 2,
        childs: []
    },

    {
        value: '目录B_1_2',
        level: 2,
        childs: []
    },
    {
        value: '目录B_1_2_1',
        level: 3,
        childs: []
    },
    {
        value: '目录C',
        level: 0,
        childs: []
    },
];

从上向下遍历数组然后比较,判断父子节点的关系也可以建立这颗森林,我想的是从最深的节点开始,对树进行收敛。中心思想是:找到最深的节点,判断它上一个节点,如果是它的父,则建立父子关系,然后重新寻找最深的节点;如果是它的兄弟,则建立兄弟关系,然后兄弟抱团去找他们的父亲(他两合并变成最深的节点,继续向上找一个节点),循环如此,直到找到根节点为止。

算法使用JS实现如下,buildTree是入口方法,参数就是我们需要转换的数组结构,返回值为结果森林。

/**
 * 建立树
 */
function buildTree(source) {
    if (source.length == 1) {
        return source;
    }

    var index = indexOfMaxLevel(source);
    var target = source[index];
    return restrainTree(source, target, index);
}

/**
 * 对树本身进行收敛拼接
 * index表示当前node所在的source的位置
 */
function restrainTree(source, node, index) {
    var preIndex = index - 1;
    if (preIndex < 0) {
        console.log("这里出现应该是树错误")
        return source;
    }

    // 从当前节点往上取一个节点进行比较
    var pre = source[preIndex];
    // 取出最顶上面的节点,也就是当前节点
    var cur = Array.isArray(node) ? node[0] : node;

    if (pre.level < cur.level) {
        // 处理节点
        pre.childs = node;
        // 将已经处理的数据清理,防止多次处理
        source = removeFromArray(source, index, node);
        // 重新开始build
        return buildTree(source);
    } else if (pre.level == cur.level) {
        var tmp = [];
        tmp = tmp.concat(pre).concat(node);
        // 合并节点后,继续向上
        return restrainTree(source, tmp, preIndex);
    } else {
        console.log("应该不存在吧....")
    }
}

/**
 * 清理树中已经处理过的节点
 */
function removeFromArray(arr, index, node) {
    var size = 1;
    if (Array.isArray(node)) {
        size = node.length;
    }

    return arr.slice(0, index).concat(arr.slice(index + size, arr.length));
}



// 获得最大层数的index
function indexOfMaxLevel(arr) {
    var index = -1;
    var max = -1;
    for (var i = 0; i < arr.length; i++) {
        var item = arr[i];
        if (item.level >= max) {
            max = item.level;
            index = i;
        }
    }
    return index;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值