遍历一个面向水平的结构

时间:2013-03-15 14:49:25

标签: java xml traversal linear

我有一个线性数据结构,每个节点都有一个级别。父节点的级别为1,父级的子节点的级别为2,子节点的节点的节点为3,另一个父节点的级别为1。以下

<node level=1> //parent node
<node level=2> //child of encountered parent node
<node level=2> //child of encountered parent node
<node level=3> //child of encountered child node
<node level=2> //child of encountered parent node
<node level=1> //parent node
<node level=1> //parent node
<node level=2> //child of encountered parent node
<node level=3> //child of encountered child node
<node level=4> //child of encountered child node
<node level=1> //parent node

本质上我正在尝试构建一个List ..(对其他建议开放),这样列表中的每个元素都是父节点,每个父节点都有子节点列表,每个子节点都可以有子列表节点等。每个元素都是一个节点,所有属性都是相同的。

我通过跟踪当前级别来尝试代码但是我不确定如何正确地将具有子节点的子节点添加回第一个子节点的父节点。我认为通过递归可以最好地处理这个问题,但我从来没有能够以有序的方式真正实现递归。

我的解决方案

以下是此遍历的工作实现。请随时评论如何优化:

Node currNode = root;
List<Root> roots = new ArrayList<Root>();

do {
      Node node = generateNode(nodesList.next());
      if (node.getLevel() == 1) { //implies root level node
         roots.add(node);
         currNode = node;
         index++;
         continue;
      } 
      if (node.getLevel() == currNode.getLevel() +1) {
         currNode.childrenList.addChild(node);
         node.setParent(currNode);
         currNode = node;
      } else {
         while (node.getLevel() <= currNode.getLevel()) {
           if (currNode.getParent() == null) {
               currNode = roots.get(roots.size()-1);
           } else {
               currNode = currNode.getParent();
         }
         if (node.getLevel() == currNode.getLevel() + 1) {
             currNode.childrenList.addChild(node);
             node.setParent(currNode);
             currNode = node;
         } else {
             currNode = roots.get(roots.size()-1);
             currNode.childrenList.addChild(node);
         }

} while (hasMoreNodes(nodesList));

我写了以下逻辑来打印这个结构,让我知道是否可以改进:

private void printNodes(List<Node> node) {

    for (int j = 0; j < node.size(); j++) {
        printContents(node.get(j));
        printChildren(node.get(j));
    }

}

private void printChildren(Node node) {
    for (int i = 0; i < node.getChildrenList().size(); i++) {
        printContents(node.getChildrenList().get(i));
        printChildren(node.getChildrenList().get(i));
    }

}

1 个答案:

答案 0 :(得分:0)

您不必考虑所有嵌套。您只需要考虑您的位置(如在节点列表中的前一个条目的级别)以及下一个条目的位置。

在这种情况下,解决方案在于读取树的方式。注意在节点列表中,即树输入源,在父节点之后,下一个节点是子节点。如果某个节点之后的节点不是该节点的子节点(即,如果它的级别不是低一级),则它是前一个节点的祖先之一的子节点。

所以:

  1. 如果第n行的等级等于1加上第n-1行的等级,则行n持有第n-1行的子等级。
  2. 否则,从第n-1行的节点向上移动树,直到找到比第n行的级别低一级的树。该祖先节点是第n行节点的父节点。
  3. 您也不必递归。

    currLevel = 0;
    currNode = root;
    do {
       node = read();
       if (somethingRead()) {
          // If this one is one level below the last one, it goes in as a child and we're done
          if (node.level == currNode.level + 1) {
             currNode.addChild(node);
             currNode = node;
          } else {
             // Otherwise this one has to be at a level above this node's child, so back up
             while (node.level >= currNode.level) {
                currNode = currNode.parent(); // check for root left out here ...
             }
             if (node.level == currNode.level + 1) {
                currNode.addChild(node);
                currNode = node;
             } else {
                // handle illegal condition in list
             }
          }
       }
    } while (moreNodesToRead());
    

    对您的解决方案的回应

    您的解决方案反映了您不愿意使用假节点作为树的根。这是一个可以做出的设计选择。这是我的版本。

    我有点担心你如何处理被污染的传入数据

    1. 提供的节点超出之前的节点。
    2. 显示的第一个节点不在第1级。
    3. 节点的级别为0或更低(不检查以下内容)
    4. 此外,我建议您在当前节点应为根时允许currNodenull。从理论上讲,它可能发生在备份当前节点的while循环中,但请注意,在代码中的那一点,您已经知道新节点的级别高于1,因此currNode应该永远不会备份超出1级节点。如果假设是错误的,那么生成NPE是合理的。

      我建议这些改变:

      Node currNode = null;
      List<Root> roots = new ArrayList<Root>();
      
      do {
            Node node = generateNode(nodesList.next());
            if (node.getLevel() == 1) { //implies root level node
               roots.add(node);
               currNode = node;
            } else if (currNode == null) {
               // ... handle misformed input ... first node isn't level 1, ignore it
            } else if (node.getLevel() == currNode.getLevel() + 1) {
               currNode.childrenList.addChild(node);
               node.setParent(currNode);
               currNode = node;
            } else {
               Node savedCurrNode = currNode;
               while (node.getLevel() <= currNode.getLevel()) {
                   currNode = currNode.getParent();
               }
               if (node.getLevel() == currNode.getLevel() + 1) {
                   currNode.childrenList.addChild(node);
                   node.setParent(currNode);
                   currNode = node;
               } else {
                   // ... handle misformed input ... node level > last node level + 1, ignore it
                   currNode = savedCurrNode;
               }
      
      } while (hasMoreNodes(nodesList));
      

      <强>打印

      我重新安排了一些,并更改了一些名称和职责(在评论中列出)。只是为了从上面开始,如果根只是一个节点,你根本就不需要'printRoots()'方法。只需在假根节点上调用'printChildren()',将其设置为0.但是它会在顶部打印一个额外的行。

      (如果你缩进输出,它总是让你更容易阅读。)

      警告:未经测试。

      /** Print all the root nodes, each with any children it may have */
      private void printRoots(List<Node> roots) {
      
          for (int j = 0; j < roots.size(); j++) {
              Node node = roots.get(j);
              printContents(node, 1);
          }
      
      }
      
      /** Print one node and any children it might have */
      private void printContents(Node node, int level) {
      
          for (int i=1 ; i < level ; ++i) {
              print("    ");
          }
          print(node.toString());
          println();
      
          printChildren(node, level+1);
      
      }
      
      /** Print each child of the supplied node. Notice how this is just like getting the
       * list of children and calling 'printRoots()'
       *//
      private void printChildren(Node node, int level) {
      
          for (int i = 0; i < node.getChildrenList().size(); i++) {
              Node childNode = node.getChildrenList().get(i);
              printContents(childNode, level);
          }
      
      }