我一直在尝试通过将子级分配给其父级然后通过it.remove()
删除它来有效地创建树:
for (OgOrganizationTreeDTO parent : parents) {
setChildren(parent, organizationTree);
}
这是setChildren
函数的实现
private void setChildren(OgOrganizationTreeDTO root, List<OgOrganizationTreeDTO> allOrganizations) {
if (allOrganizations.isEmpty()) {
return ;
}
Iterator<OgOrganizationTreeDTO> it = allOrganizations.iterator();
while (it.hasNext()) {
OgOrganizationTreeDTO potentialChild = it.next();
if (potentialChild.getIdParentId() != null && potentialChild.getIdParentId().equals(root.getId())) {
root.addChild(potentialChild);
it.remove();
setChildren(potentialChild, allOrganizations);
}
}
}
我正在使用LinkedList,并且得到了ConcurrentModificationException
。我已经通过将allOrganizations
的副本传递给递归setChildren
的递归new LinkedList<>(allOrganizations)
函数来解决了这个问题,但是副本部分要花O(n)
的时间,我不想那。
我也尝试过使用LinkedBlockingQueue
,但是我发现删除操作需要O(n)
时间。
我想利用LinkedList
O(1)
的删除功能,因此每次我添加一个孩子并重复出现时,列表都会变小。
我还通过将各个节点标记为可见并将基例设置为HashSet
来成功实现了hashSet.size() == allOrganizations.size()
的解决方案,但是我仍然在相同大小的List上重复执行此操作,因此别帮我。
是否有任何方法可以实现我使用LinkedList
O(1)
删除的目标,或者是否有更有效的替代方法?
答案 0 :(得分:1)
好吧,我不知道如何使用递归,因为您实际上在每个递归调用中都创建了一个新的迭代器(allOrganizations.iterator()-创建新的迭代器实例)。因此,当您调用delete时,您需要为其他迭代器修改集合,这就是为什么它将引发该异常的原因。
一种解决方案是使用一些CopyOnWriteList,它允许并发修改,但它只是传递列表的一个副本,而不是修改同一列表,因此将占用更多内存。
另一种解决方案是向OgOrganizationTreeDTO类添加一些属性,以标记该行是否已被处理。在这种情况下,您无需将其从列表中删除,只需将其标记为已处理即可。
但是无论如何,既然您在询问性能和大O,那么我可以为您提供另一种具有O(n)复杂度的解决方案。当然,在使用更多内存时需要权衡取舍,但这是标准内存与复杂性的问题...
private static void setChildrenMap(OgOrganizationTreeDTO root,
List<OgOrganizationTreeDTO> allOrganizations) {
Map<Integer, OgOrganizationTreeDTO> organizationsMap = new HashMap<>();
organizationsMap.put(root.getId(), root);
for (OgOrganizationTreeDTO element : allOrganizations) {
organizationsMap.put(element.getId(), element);
}
for (OgOrganizationTreeDTO element : allOrganizations) {
organizationsMap.get(element.getParentId()).addChild(element);
}
}
基本上,从哈希图中获取一个元素是恒定的时间,因此我们使用它来查找所需的父对象。如果您期望元素包含错误的数据,则可能需要添加一些检查,因为organizationsMap.get(element.getParentId())
可能返回null