Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对象未从ArrayList中删除_Java_Loops_Arraylist_Collections_Remove - Fatal编程技术网

Java 对象未从ArrayList中删除

Java 对象未从ArrayList中删除,java,loops,arraylist,collections,remove,Java,Loops,Arraylist,Collections,Remove,有一个通用的树数据结构。现在,它的节点类将如下所示 private static class Node { int data; ArrayList<Node> children = new ArrayList<>(); } 私有静态类节点{ int数据; ArrayList子项=新的ArrayList(); } DS的形成完全是通过输入来构造的。现在我需要执行的是删除所有叶节点。下面的代码无法删除其实例成员中已存在的子项 public static

有一个通用的树数据结构。现在,它的节点类将如下所示

private static class Node {
    int data;
    ArrayList<Node> children = new ArrayList<>();
  }
私有静态类节点{
int数据;
ArrayList子项=新的ArrayList();
}
DS的形成完全是通过输入来构造的。现在我需要执行的是删除所有叶节点。下面的代码无法删除其实例成员中已存在的子项

public static void removeLeaves(Node node) {
ArrayList<Node> nodeChildrenList = node.children;
int childrenSize = nodeChildrenList.size();
for(int i = 0; i < childrenSize; i++){
    Node child = nodeChildrenList.get(i);
    removeLeaves(child);
    if(child.children.size() == 0){
        child.children.remove(child); // Problem
    }
}
}
publicstaticvoidremoveeves(节点){
ArrayList nodeChildrenList=node.children;
int childrenSize=nodeChildrenList.size();
for(int i=0;i
我无法理解没有从ArrayList中删除对象(节点)子对象。但迭代器工作正常。我甚至在每一步都尝试过调试。当断点到达child.children.remove(child)时;线路。它不能完成它

而这段代码工作起来很有魅力

    ArrayList<Node> nodeChildrenList = node.children;
    // int childrenSize = nodeChildrenList.size();
    Iterator itr = nodeChildrenList.iterator();
    while(itr.hasNext()){
       Node child = (Node)itr.next();
       if(child.children.size() == 0){
           itr.remove();
       }
       removeLeaves(child);
    }
    // for(int i = 0; i < childrenSize; i++){
    //     Node child = nodeChildrenList.get(i);
    //     removeLeaves(child);
    //     if(child.children.size() == 0){
    //         child.children.remove(child);
    //     }
    // }
  }
ArrayList nodeChildrenList=node.children;
//int childrenSize=nodeChildrenList.size();
迭代器itr=nodeChildrenList.Iterator();
while(itr.hasNext()){
Node child=(Node)itr.next();
if(child.children.size()==0){
itr.remove();
}
拆除屋檐(儿童);
}
//for(int i=0;i
让我们看看您的for循环的removeLeaves正在做什么。在下面添加了评论

ArrayList<Node> nodeChildrenList = node.children;
int childrenSize = nodeChildrenList.size();
for(int i = 0; i < childrenSize; i++){    // Loop through each of node's children
    Node child = nodeChildrenList.get(i); // Get the child of node at index i
    removeLeaves(child);                  // recursively call removeLeaves with the child
    if(child.children.size() == 0){       // If the node's child has no children
        // This is a problem because you are telling the program to remove the node's 
        // child from the node's child's children, not from the node's children.
        child.children.remove(child);     
    }
}
在本例中,我们有一个值为1的根节点和两个子节点。 第一个子项的值为2,并且没有子项。 第二个子项的值为3,并且没有子项

for(int i = 0; i < childrenSize; i++){  // i = 1 and childrenSize of the root node is 2, so we can continue
    Node child = nodeChildrenList.get(i); // Uh oh, we don't have a child at index 1!
因此,如果我们逐行浏览
removeeves
方法,让我们看看会发生什么

使用根节点调用时:

ArrayList<Node> nodeChildrenList = node.children; // nodeChildrenList contains two nodes - the ones with values 2 and 3

int childrenSize = nodeChildrenList.size(); // childrenSize is 2
for(int i = 0; i < childrenSize; i++){  // Start with i = 0
    Node child = nodeChildrenList.get(i); // The first child is the one with value 2
    removeLeaves(child);  // Call remove leaves again with the child with value 2
现在我们有一个根节点和一个子节点(值为3)很好,对吗?嗯,没那么多。由于我们已经修改了正在循环的结构,我们将遇到一个问题。让我们带着根节点的子节点遍历循环的下一个迭代

for(int i = 0; i < childrenSize; i++){  // i = 1 and childrenSize of the root node is 2, so we can continue
    Node child = nodeChildrenList.get(i); // Uh oh, we don't have a child at index 1!
for(int i=0;i

这里的问题是,由于对nodeChildrenList进行了结构修改,现在列表中只有一个元素(在索引0处)-值为3的元素。索引1处没有元素,因此会引发IndexOutOfBoundsException。这就是为什么在对正在循环的集合进行结构修改时要使用迭代器的原因。

这是否回答了您的问题?例如,For循环正在调用
child.children.remove(child)
child.children
数组列表的大小为0时。它已为空。另一方面,请使用迭代器就地修改,而不是对每个循环进行修改。后者可能会产生或更糟的非确定性行为。您的意思可能是
if(child.children.size()>0)
为什么要在列表为空时从列表中删除某些内容?为什么要尝试从节点的子列表中删除节点本身?@NomadMaker我打赌OP实际上是指如果子节点没有子节点,则从其父节点中删除子节点本身,即
if(child.children.isEmpty(){nodeChildrenList.remove(child);}
---但是,递归调用没有任何意义,因为该方法最终会删除所有子节点。真的谢谢你,伙计。如果我从一开始就删除子节点,那么其他节点将被移动,如果我从最后迭代列表,这也将得到解决。是的,child.children.remove确实是一个错误。是的,你肯定可以向后工作并使此案例生效。只需确保在调用
节点.children.remove之后移动
removeeves
,否则只剩下根节点。
    if(child.children.size() == 0){ // child is still the first child (value 2), and it doesn't have any children, so this is true
        node.children.remove(child); // So we remove it from the root node's children. 
    }
}
for(int i = 0; i < childrenSize; i++){  // i = 1 and childrenSize of the root node is 2, so we can continue
    Node child = nodeChildrenList.get(i); // Uh oh, we don't have a child at index 1!