Suppose I have a list/array like:
[
    { id: 1, parent: null },
    { id: 2, parent: 1 },
    { id: 4, parent: 2 },
    { id: 5, parent: 3 },
    { id: 6, parent: 2 },
    { id: 3, parent: 4 }
]
And I want to convert it to a tree like so:
{ 
    id: null,
    children: [
        { 
            id: 1,
            children: [
                { 
                    id: 2,
                    children: [
                        { 
                            id: 4,
                            children: [
                                {
                                    id: 3,
                                    children: [
                                        {
                                            id: 5,
                                            children: []
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            id: 6,
                            children: [
                                
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}
I can do this trivially with the following (pseudocode) function:
function GetChildren(rootNode, inputList) {
    for (item in inputList) {
        if (item.parent == rootNode.id) {
            childNode = {
                id: item.id,
                children: []
            }
            GetChildren(childNode, inputList)
            rootNode.children.append(childNode)
        }
    }
}
I believe this will run with time complexity of O(n²). Is there an algorithm that can do this faster? I have seen some similar sounding questions for BSTs, but this is not a BST.
Note the following:
- A node may have unlimited children
- The tree can be infinitely deep
- The items in the list may appear in any order (child may appear before parent)
I had a thought about trying to only pass the part of the list without the parent, so as you recur you iterate through a progressively smaller list. I don't know if that would actually save time though:
function GetChildren(rootNode, inputList) {
    for (item in inputList) {
        listWithoutParent = inputList.remove(rootNode) // O(?)
        if (item.parent == rootNode.id) {
            childNode = {
                id: item.id,
                children: []
            }
            GetChildren(childNode, listWithoutParent)
            rootNode.children.append(childNode)
        }
    }
}
 
    