从列表中构造树(非二进制,不平衡)的最低时间复杂度?
Posted
技术标签:
【中文标题】从列表中构造树(非二进制,不平衡)的最低时间复杂度?【英文标题】:Lowest time complexity to construct tree (nonbinary, unbalanced) from a list? 【发布时间】:2021-04-29 23:31:22 【问题描述】:假设我有一个像这样的列表/数组:
[
id: 1, parent: null ,
id: 2, parent: 1 ,
id: 4, parent: 2 ,
id: 5, parent: 3 ,
id: 6, parent: 2 ,
id: 3, parent: 4
]
我想把它转换成这样的树:
id: null,
children: [
id: 1,
children: [
id: 2,
children: [
id: 4,
children: [
id: 3,
children: [
id: 5,
children: []
]
]
,
id: 6,
children: [
]
]
]
]
我可以使用以下(伪代码)函数轻松做到这一点:
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)
我相信这将以 O(n²) 的时间复杂度运行。有没有一种算法可以更快地做到这一点?我见过一些类似的 BST 问题,但这不是 BST。
注意以下几点:
一个节点可能有无限的子节点 树可以无限深 列表中的项目可以按任意顺序出现(子项可能出现在父项之前)我曾想过尝试只传递列表的一部分而不传递父级,因此当您重复时,您会遍历一个逐渐变小的列表。我不知道这是否真的可以节省时间:
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)
【问题讨论】:
您可以通过使用地图/查找表更快地实现这一目标。看看这个问题:***.com/questions/444296/… 【参考方案1】:这个想法是维护一个哈希表,以 id 为键,其中的值是要创建的树的对象。因此,例如,在该哈希表中,您将有这样的条目:
key: 1
value: id: 1, children: []
在迭代输入数据时,查找当前 id 和当前父级的值。如果其中任何一个尚未出现在哈希表中,则在此时插入它。这为您提供了两个具有id
和children
属性的对象。然后将子节点对象追加到父对象的children
数组中。
这是它在 javascript 中的工作方式,对于哈希表,我使用本机 Map
:
function getOrCreateNode(map, id)
let node = map.get(id);
if (node == undefined) // Node not yet created
node = id, children: [] ; // Create a new node
map.set(id, node); // Add that new node to the map by its id
return node;
function createTree(data)
let map = new Map; // Keys are id, values are nodes of the tree
for (let item of data) // Iterate all objects in the input array
// Get parent and child object, and add child object to parent's children array:
getOrCreateNode(map, item.parent).children.push(getOrCreateNode(map, item.id));
return map.get(null); // Return the root node
// Sample input data:
let data = [
id: 1, parent: null ,
id: 2, parent: 1 ,
id: 4, parent: 2 ,
id: 5, parent: 3 ,
id: 6, parent: 2 ,
id: 3, parent: 4
];
// Output the result
console.log(createTree(data));
由于哈希表通常提供具有average amortised constant time complexity 的插入和查找实现,因此该算法将以线性时间复杂度运行(就输入数组中的条目数而言)。
我们应该添加免责声明,即哈希表上的插入和查找操作具有与其大小成线性关系的理论上的最差时间复杂度。有时您可能对id
值了解更多,这样您就可以使用完美的散列算法。例如,id
值都可以是小的无符号整数(如您的示例中)。在这种情况下,您可以将数组用作哈希表,并将 id
值用作数组索引。那么插入或查找操作的最坏情况时间复杂度仍然是 O(1)。
【讨论】:
以上是关于从列表中构造树(非二进制,不平衡)的最低时间复杂度?的主要内容,如果未能解决你的问题,请参考以下文章