【问题标题】:How to create a tree-type object in java? [duplicate]如何在java中创建树型对象? [复制]
【发布时间】:2016-01-26 08:14:07
【问题描述】:

我一直想知道创建在列表中包含列表的对象的最佳实践是什么。假设我有这种对象:

    root = new CarrierTreeNode(null, 
            new CarrierTreeNode[] {
                new CarrierTreeNode(new CarrierTreeItem("item1"), new CarrierTreeNode[] {
                    new CarrierTreeNode(new CarrierTreeItem("item1.1"))
                }),
                new CarrierTreeNode(new CarrierTreeItem("item2"), new CarrierTreeNode[] {
                    new CarrierTreeNode(new CarrierTreeItem("item2.1"))
            })
    });

我想动态生成它并动态访问和修改其中的列表/数组。这有设计模式吗? 谢谢。

为了更清楚,这里使用的构造函数是这样的:node (item, node[])

【问题讨论】:

  • 几乎是一个重复,但 OP 询问的是创建树,而不是结构本身。看起来很不一样。

标签: java tree nested


【解决方案1】:

您可能想看看复合模式。 简而言之,这是在 Object A 持有 Object A 的集合时使用的。

这种模式/数据结构允许简单的递归行为。

有很多来源,所以如果这还不够,只需转到 google 以获取更多信息,但这里是一个开始: https://en.wikipedia.org/wiki/Composite_pattern

至于创建部分,在这种情况下,我通常会使用工厂或构建器,但具体实现会有所不同。假设你有一个 2d 数组 if items,并且你想根据这个数组创建这些节点。

public class NodeBuilder{
    public CarrierTreeNode build(String[][] items){
        CarrierTreeNode node = new CarrierTreeNode(null);
        for(int i = 1; i < items.length; i++){
           CarrierTreeNode nextNode = new CarrierTreeNode(new CarrierTreeItem(items[i][0]));
           node.addNextNode(nextNode);
           for(int j = 1; j < items[i].length; j++)
               nextNode.addNextNode(new CarrierTreeItem(items[i][j]));
        }
        return node;
    }
}

这显然只适用于 3 层的结构。递归方法更可取。您可以创建一个系统,其中 build 调用 build n 次,以创建您想要的深度。问题在于获取数据,为了使其工作,数据必须已经在正确的结构中,但就像字符串一样。 如果您的字符串是动态生成的,以便构建器可以计算出数据,则可以使其工作。

【讨论】:

    【解决方案2】:

    我提出这个设计希望它能帮助你:

    • TreeElement iterface :通用树元素类型。
    • Item 实现 TreeElement iterface 的类:所以它可以是 key 表示树节点或树节点的
    • Node 类也实现了 TreeElement 接口,因此它可以 是基节点或键的值。

    这是实现:

    interface TreeElement {
    
        enum ElementType {
            NODE, ITEM
        };
    
        public TreeElement getElement(Item item);
    
        public Node addElement(Item item, TreeElement element);
    
        public ElementType getType();
    
    }
    
    class Item implements TreeElement {
    
        String name;
    
        public Item(String name) {
            super();
            this.name = name;
        }
    
        @Override
        public TreeElement getElement(Item item) {
            return null;
        }
    
        @Override
        public ElementType getType() {
            return ElementType.ITEM;
        }
    
        @Override
        public Node addElement(Item item, TreeElement element) {
            return null;
        }
    
        @Override
        public String toString() {
            return "Item [" + name + "]";
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((name == null) ? 0 : name.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Item other = (Item) obj;
            if (name == null) {
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))
                return false;
            return true;
        }
    
    }
    
    class Node implements TreeElement {
    
        Map<Item, TreeElement> map;
    
        {
            map = new HashMap<>();
        }
    
        @Override
        public TreeElement getElement(Item item) {
            return map.get(item);
        }
    
        @Override
        public ElementType getType() {
            return ElementType.NODE;
        }
    
        public Node addElement(Item item, TreeElement element) {
            this.map.put(item, element);
            return this;
        }
    
        @Override
        public String toString() {
            return "Node " + map + " ";
        }
    
    }
    

    测试代码:

    Node node = new Node();
    Item item = new Item("Item 1");
    node.addElement(item, new Node().addElement(new Item("Level 1"), new Item("Item 1")));
    
    System.out.println(node);
    //Print : Node {Item [Item 1]=Node {Item [Level 1]=Item [Item 1]} } 
    
    TreeElement element = node.getElement(item);
    
    if (element.getType().equals(ElementType.NODE)) {
        element.addElement(new Item("Level 2"), new Node().addElement(new Item("Item 2.1"), new Item("Item 2.2")));
    }
    
    System.out.println(node);
    //Print : Node {Item [Item 1]=Node {Item [Level 1]=Item [Item 1], Item [Level 2]=Node {Item [Item 2.1]=Item [Item 2.2]} } } 
    

    重要: equals()hashcode() 对示例的行为至关重要,尤其是 equals()。它们在Map 集合中用于确定集合是否包含给定元素。

    【讨论】:

      【解决方案3】:

      大多数简单的树节点实现必须包含一个用于存储数据的字段和自己的子节点列表。

      public class Node<T> {
      
          private T data;
          private List<Node> list = new LinkedList<>();
      
          public Node(){}
      
          public Node(T data){
              this.data = data;
          }
      
          public List<Node> getChildList() {
              return list;
          }
      
          public void setData(T data) {
              this.data = data;
          }
      
          public T getData() {
              return data;
          }
      }
      

      这个类已经准备好构建简单的树形结构了:

      Node<String> root = new Node<String>("Stark");
      root.getChildList().add(new Node<String>("Benjen"));
      
      Node<String> eddard = new Node<String>("Eddard");
      root.getChildList().add(eddard);
      eddard.getChildList().add(new Node<String>("Arya"));
      

      这个实现是最简单的,但肯定不是最好的。经典树节点提供有关父节点和兄弟节点的信息、内部递归搜索的方法、循环引用的控制和许多其他内容(wiki 描述得非常详细)。

      【讨论】:

        猜你喜欢
        • 2021-11-22
        • 2014-11-19
        • 1970-01-01
        • 1970-01-01
        • 2021-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多