js tree structure

let tree = [
    {
    
    
        id: '1',
        title: '节点1',
        children: [
            {
    
    
                id: '1-1',
                title: '节点1-1'
            }
        ]
    },
    {
    
    
        id: '2',
        title: '节点2',
        children: [
            {
    
    
                id: '2-1',
                title: '节点2-1'
            },
            {
    
    
                id: '2-2',
                title: '节点2-2'
            }
        ]
    },
]

1. Tree structure traversal

1.1 Breadth-first traversal
node 1, node 2, node 1-1, node 2-1, node 2-2, first traverse the large node, then traverse the child node

function scopeTreeForeach(tree, func) {
    
    
    let node, list = [...tree]
    while (node = list.shift()) {
    
    
        func(node)
        node.children && list.push(...node.children)
    }
}

1.2 Depth-first traversal
1.2.1. First-order traversal (node ​​1, node 1-1, node 2, node 2-1, node 2-2, first traverse a node and its children, and then traverse another node and its Child node)

function deepTreeForeach(tree, func) {
    
    
    tree.forEach(data => {
    
    
        func(data)
        data.children && deepTreeForeach(data.children, func) // 递归遍历子树
    })
}

1.2.2 Post-order traversal (node ​​1-1, node 1, node 2-1, node 2-2, node 2, first traverse a child node and its parent node, and then traverse another child node and its parent node)

function deepTreeLaterForeach(tree, func) {
    
    
    tree.forEach(data => {
    
    
        data.children && deepTreeForeach(data.children, func) // 递归遍历子树
        func(data)
    })
}

2. List to tree structure

const list = [
    {
    
    
        id: 0,
        parentId: null,
    },
    {
    
    
        id: 1,
        parentId: 0,
    },
    {
    
    
        id: 2,
        parentId: 4
    },
    {
    
    
        id: 3,
        parentId: 4
    },
    {
    
    
        id: 4,
        parentId: 0
    },
]

1. Double-layer for loop implementation

// 此处是数组对象里的id跟数组里另外一个对象里的parentId进行比较,
// 不同于排序时数组里单个值之间相互比较,
// 无法简单的用length-1这种不用和自己比较的操作
function forLoop(list) {
    
    
    for (var i = 0; i < list.length; i++) {
    
    
        // console.log("外部")
        for (var j = 0; j < list.length; j++) {
    
    
            // console.log("内部");
            // 自己的id不用跟自己的parentId比较
            if (i == j) continue
            if (list[i].id == list[j].parentId) {
    
    
                if (!list[i].children) {
    
    
                    list[i].children = [];
                }
                list[i].children.push(list[j]);
                // 因为只有一个父节点,找到后就跳出循环
                break;
            }
        };
        return list
    };
}
let value1 = forLoop(list)
console.log("双层for循环遍历:", value1);

2.reduce implementation

function listToTree(list) {
    
    
    let info = list.reduce((pre, item) => (pre[item.id] = item, item.children = [], pre), {
    
    })
    return list.filter(item => {
    
    
        info[item.parentId] && info[item.parentId].children.push(item)
        return !item.parentId
    })
}
let value2 = listToTree(list)
console.log("reduce遍历:", value2);
//最后
let treeList = list.filter(item => !item.parentId)
console.log(treeList);

3. Tree structure screening (0,1,2,3,4)

function treeFilter(tree, func) {
    
    
    // 使用map复制一下节点,避免修改到原树
    return tree.map(node => ({
    
     ...node })).filter(node => {
    
    
        node.children = node.children && treeFilter(node.children, func)
        return func(node) || (node.children && node.children.length)
    })
}

4. Tree structure search

4.1. Find Node

function treeFind(tree, func) {
    
    
    for (const data of tree) {
    
    
        //相当于func = node => node.id == '2-1'
        if (func(data)) {
    
    
            return data
        }
        if (data.children) {
    
    
            const res = treeFind(data.children, func)
            if (res) return res
        }
    }
    return null
}

4.2. Find node path (backtracking method)

function treeFindPath(tree, func, path = []) {
    
    
    // if (!tree) return []
    for (const data of tree) {
    
    
        // 假设满足条件,直接放到数组里
        path.push(data.id)
        if (func(data)) {
    
    
            return path
        }
        if (data.children) {
    
    
            const res = treeFindPath(data.children, func, path)
            // 只有当数组的长度大于0才返回值
            if (res.length) return res
        }
        // 条件都不满足,则直接删除,对应前面的push
        path.pop()
    }
    return []
}

5 Conclusion

For tree structure operations, recursion is the most basic and the easiest to understand. Recursion itself is the idea of ​​loop, so you can use loop to rewrite recursion.

Guess you like

Origin blog.csdn.net/m0_48076809/article/details/112269687