【问题标题】:recursion - remove Nodes if their String is "Leonardo"递归 - 如果节点的字符串是“Leonardo”,则删除节点
【发布时间】:2017-07-24 02:19:51
【问题描述】:

我有一棵节点树。

class Node {
    String mName;
    List<Node> children = new ArrayList<>();
    Node(String name) {
        mName = name;
    }
}

我想检查所有的树节点,如果我找到一些 mName 为“Leonardo”的节点,我想将 Leonardo 的所有孩子添加到 Leonardo 的父亲并删除 Leonardo。

例如

初始树是:

                        Jessy
                   /      |       \
 Leonardo                John                  Leonardo
 /     \                 /   \                  /   \
Rafael  David      Leonardo   Keren         Denis  Leonardo
                                                       |
                                                   Phillipe

结果应该是:

                        Jessy
                   /      |       \
 Rafael  David           John         Denis  Phillipe
                          |             
                        Keren         

(对Leonardo、Denis、Phillipe和Leonardo的子树结果的解释:Jessy的第三个儿子是Leonardo,因此Leonardo被移除,他的儿子(Denis和Leonardo)成为Jessy的儿子。但随后另一个莱昂纳多被免职,菲利普代替他来。)

孩子的顺序无关紧要(即,拉斐尔和大卫可以在菲利普之后)

假设当“Leonardo”在根中时,没有办法获得初始树。

我已经尝试过了,但不幸的是它不起作用..

for (int i = 0; i < root.children.size(); ++i) {
        removeLeonardo(root, root.children.get(i));
}

public void removeLeonardo(Node curr, Node child) {
    if (child == null || child.children.isEmpty() == true) {
        return;
    }

    if (child.mName.equals("Leonardo") == true) {
        // add all Leonardo's children to current father
        for (int i = 0; i < child.children.size(); ++i) {
            curr.children.add(child.children.get(i));
            // apply the func for the current father with each of Leonardo's children
            removeLeonardo(curr, child.children.get(i));
        }
        // remove "Leonardo" from the current father
        curr.children.remove(child);
    }

    else { // no "Leonardo" found, so apply the func for each child and this child's children
        for (int i = 0; i < child.children.size(); ++i) {
            removeLeonardo(child, child.children.get(i));
        }
    }
}

但是 Java 不能通过引用来工作。你能帮我解决这个问题吗?

【问题讨论】:

    标签: java algorithm recursion graph-algorithm breadth-first-search


    【解决方案1】:

    我相信这应该可行。

    如果您担心效率,那么从 ArrayList 内部删除和插入并不是最好的。 LinkedList 会更好,但是您不想通过索引访问子级。您可能会改用 ListIterator,并使用 add 和 remove 方法。

    public static void main(String[] args)
    {
        Node root = new Node("Jessy");
        root.children.addAll(Arrays.asList(new Node[]{new Node("Leonardo"), new Node("John"), new Node("Leonardo")}));      
        root.children.get(0).children.addAll(Arrays.asList(new Node[]{new Node("Rafael"), new Node("David")}));
        root.children.get(1).children.addAll(Arrays.asList(new Node[]{new Node("Leonardo"), new Node("Keren")}));
        root.children.get(2).children.addAll(Arrays.asList(new Node[]{new Node("Denis"), new Node("Leonardo")}));
        root.children.get(2).children.get(1).children.add(new Node("Phillipe"));
    
        print(root, "");                
        pruneByName(root, "Leonardo");
        print(root, "");
    }
    
    static void pruneByName(Node node, String name)
    {       
        assert !node.mName.equals(name);
    
        for(int i=0; i<node.children.size(); )
        {
            Node child = node.children.get(i);
            if(child.mName.equals(name))
            {
                node.children.remove(i);
                node.children.addAll(i, child.children);
            }
            else
            {
                pruneByName(child, name);
                i += 1;
            }
        }
    }
    
    static void print(Node node, String ind)
    {
        System.out.println(ind + node.mName);
        for(Node child : node.children)
        {
            print(child, ind + "  ");
        }
    }
    

    输出:

    Jessy
      Leonardo
        Rafael
        David
      John
        Leonardo
        Keren
      Leonardo
        Denis
        Leonardo
          Phillipe
    Jessy
      Rafael
      David
      John
        Keren
      Denis
      Phillipe 
    

    【讨论】:

      【解决方案2】:

      在初始循环中将跳过子 John。方法如下。

      Jessy 的孩子 Leonardo、John 等位于数组列表中的索引 0、1 等处。 for 循环从索引 0 开始处理第一个 Leonardo,而那个 Leonardo 已移除。在移除索引为 1 的莱昂纳多约翰的过程中, 被移动到索引 0。for 循环然后移动到索引 1 跳过 John 和 没有移除约翰的孩子莱昂纳多。

      下面是使用ListIterator 的代码,应该可以解决问题。有了这个 代码,您可以使用任何类型的列表,包括 LinkedList's 以及 ArrayList's。

      public static void removeLeonardo2(Node node) {
          if (node == null || node.children.isEmpty()) {
              return;
          }
      
          for(ListIterator<Node> it = node.children.listIterator(); it.hasNext();) {
              Node n;
              n = it.next();
              if(n.mName.equals("Leonardo")) {
                  removeLeonardo2(n);
                  it.remove();
                  for(Node childNode: n.children) {
                      it.add(childNode);;
                  }
              }else {
                  removeLeonardo2(n);
              }
          }
      }
      

      【讨论】:

      • 谢谢@YvetteColomb :)
      猜你喜欢
      • 2022-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-29
      • 2023-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多