Java에서 트리 데이터 구조를 구현하는 방법은 무엇입니까? [닫은]


496

Java에서 트리를 나타내는 표준 Java 라이브러리 클래스가 있습니까?

특히 나는 다음을 대표해야합니다.

  • 모든 노드의 하위 트리는 임의의 수의 자식을 가질 수 있습니다
  • 각 노드 (루트 뒤)와 그 하위 노드는 문자열 값을 갖습니다.
  • 주어진 노드의 모든 자식 (일부 목록 또는 문자열 배열)을 가져와야하며 문자열 값입니다 (즉, 노드를 입력으로 사용하고 자식 노드의 모든 문자열 값을 출력으로 반환하는 메소드)

이것에 사용 가능한 구조가 있습니까? 아니면 직접 작성해야합니다 (구현 제안이 좋을 경우).


3
Java 8을 사용하고 있고 스트림, 필터링 등으로 노드를 탐색하려는 경우; 당신은 두리안을 살펴 걸릴 수도 있습니다 github.com/diffplug/durian을
네드 트위그에게

1
이 API를 사용할 수 있습니다 : sourceforge.net/p/treeds4j
Mohamed Ennahdi El Idrissi

답변:


306

여기:

public class Tree<T> {
    private Node<T> root;

    public Tree(T rootData) {
        root = new Node<T>();
        root.data = rootData;
        root.children = new ArrayList<Node<T>>();
    }

    public static class Node<T> {
        private T data;
        private Node<T> parent;
        private List<Node<T>> children;
    }
}

그것은 기본 트리 구조 String나 다른 객체에 사용될 수 있습니다 . 간단한 트리를 구현하여 필요한 작업을 수행하는 것은 매우 쉽습니다.

추가해야 할 것은 추가, 제거, 순회 및 생성자를위한 메소드입니다. 의 Node기본 빌딩 블록입니다 Tree.


304
엄격하게 말하면 Tree수업 Node자체는 나무로 볼 수 있기 때문에 필요하지 않습니다 .
Joachim Sauer

34
@Joa, 루트를 포함하는 구조를 좋아합니다. 단일 노드가 아닌 트리를 호출하는 것이 더 합리적인 방법을 트리 클래스에 추가 할 수 있습니다.
jjnguy

24
@Justin : 예를 들어? 그것은 정직한 질문입니다. 하위 트리에서는 의미가없는 전체 트리에서 의미가있는 단일 방법을 생각할 수 없습니다.
Joachim Sauer

22
Tree 클래스가 필요하지 않다는 @Joa에 동의합니다. 별도의 Tree 클래스를 추가하지 않고 지속적으로 Node 클래스를 사용하여 코드에서 트리의 재귀 적 특성을 명시 적으로 유지하는 것을 선호합니다. 대신 트리의 루트 노드를 다루고 있음을 분명히 해야하는 경우 변수 이름을 'tree'또는 'root'로 지정하십시오.
jvdbogae

89
@Joa 네 살 난 당신과 완전히 동의합니다. 나무 클래스 Nix.
jjnguy

122

또 다른 트리 구조 :

public class TreeNode<T> implements Iterable<TreeNode<T>> {

    T data;
    TreeNode<T> parent;
    List<TreeNode<T>> children;

    public TreeNode(T data) {
        this.data = data;
        this.children = new LinkedList<TreeNode<T>>();
    }

    public TreeNode<T> addChild(T child) {
        TreeNode<T> childNode = new TreeNode<T>(child);
        childNode.parent = this;
        this.children.add(childNode);
        return childNode;
    }

    // other features ...

}

샘플 사용법 :

TreeNode<String> root = new TreeNode<String>("root");
{
    TreeNode<String> node0 = root.addChild("node0");
    TreeNode<String> node1 = root.addChild("node1");
    TreeNode<String> node2 = root.addChild("node2");
    {
        TreeNode<String> node20 = node2.addChild(null);
        TreeNode<String> node21 = node2.addChild("node21");
        {
            TreeNode<String> node210 = node20.addChild("node210");
        }
    }
}

보너스
다음과 같은 본격적인 나무를보십시오.

  • 반복자
  • 수색
  • 자바 / C #

https://github.com/gt4dev/yet-another-tree-structure


2
라이브러리가 매우 유용하다는 것을 알았습니다. 감사합니다. 그러나 부모와 자식 간의 참조 관계를 기반으로 트리 구조를 동적으로 채우는 방법을 알고 싶습니다. 예를 들어 한 멤버 1이 다른 멤버 2를 스폰서하고 멤버 2 스폰서 멤버 3 등이 있습니다. 테이블 레코드 관계가 이미 있지만 라이브러리를 사용하여 트리에 채울 수 있는지 확실하지 않습니다.
d4v1dv00

1
2016 년 현재 링크에는 소스 파일이나 다운로드가 포함되어 있지 않습니다
Sharon Ben Asher

2
내 생각에, 위의 높은 등급의 답변 후 3 년이 답변은 더 깨끗한 답변입니다. 그러나 LinkedList를 this.children의 ArrayList로 바꿉니다.
HopeKing

1
나는 아이들을 위해 세트를 사용할 것입니다.
DPM

틀릴 수도 있지만이 구현에서는 유효한 결과를 얻으려면 hasNext()각 호출 전에 호출 해야합니다 next(). 이것은 Iterator사양의 일부가 아닙니다 .
Robert Lewis

97

실제로 JDK에는 꽤 좋은 트리 구조가 구현되어 있습니다.

javax.swing.tree , TreeModelTreeNode를 살펴보십시오 . 그것들은 함께 사용하도록 설계 JTreePanel되었지만 실제로는 꽤 좋은 트리 구현이며 스윙 인터페이스없이 사용하지 못하게하는 것은 없습니다.

Java 9부터는 'Compact profiles'에 존재하지 않으므로 이러한 클래스를 사용하지 않을 수 있습니다 .


5
예, 나는 과거에 그것들을 사용했고 그들은 나무에서 원하는 모든 것을 할 것입니다. 내가 생각할 수있는 유일한 단점은 해당 구현 클래스의 이름 길이입니다 : DefaultTreeModel 및 DefaultMutableTreeNode. 장황하지만, 그게 내가 생각하는 모든 중요한 것은 아닙니다.
Ultimate Gobblement

4
이에 대처하는 좋은 방법은 몇 가지 정적 메서드 newModel () 및 newNode ()를 만든 다음 정적 가져 오는 것입니다.
Gareth Davis

140
스윙 관련이 아닌 함수에서 Swing 라이브러리를 사용하지 마십시오. 이것은 나쁜 코딩 관행 입니다. Swing이 어떻게 나무를 구현하는지, 종속성이 무엇인지, 앞으로 어떻게 변할 수 있는지 전혀 알지 못합니다. Swing은 유틸리티 라이브러리가 아니라 UI 라이브러리입니다.
jasop

44
나쁜 코딩 관행은 조금 가혹하다고 생각합니다.
Gareth Davis

51
javax.swing.tree.TreeModel은 공용 인터페이스 (정확하게 java.util.List와 유사)이며 호환되지 않는 변경 사항은 없습니다. 추가 이점은 개발하는 동안 트리를 쉽게 디버깅 / 시각화 할 수 있다는 것입니다.
lbalazscs

45

이건 어때?

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

/**
  * @author ycoppel@google.com (Yohann Coppel)
  * 
  * @param <T>
  *          Object's type in the tree.
*/
public class Tree<T> {

  private T head;

  private ArrayList<Tree<T>> leafs = new ArrayList<Tree<T>>();

  private Tree<T> parent = null;

  private HashMap<T, Tree<T>> locate = new HashMap<T, Tree<T>>();

  public Tree(T head) {
    this.head = head;
    locate.put(head, this);
  }

  public void addLeaf(T root, T leaf) {
    if (locate.containsKey(root)) {
      locate.get(root).addLeaf(leaf);
    } else {
      addLeaf(root).addLeaf(leaf);
    }
  }

  public Tree<T> addLeaf(T leaf) {
    Tree<T> t = new Tree<T>(leaf);
    leafs.add(t);
    t.parent = this;
    t.locate = this.locate;
    locate.put(leaf, t);
    return t;
  }

  public Tree<T> setAsParent(T parentRoot) {
    Tree<T> t = new Tree<T>(parentRoot);
    t.leafs.add(this);
    this.parent = t;
    t.locate = this.locate;
    t.locate.put(head, this);
    t.locate.put(parentRoot, t);
    return t;
  }

  public T getHead() {
    return head;
  }

  public Tree<T> getTree(T element) {
    return locate.get(element);
  }

  public Tree<T> getParent() {
    return parent;
  }

  public Collection<T> getSuccessors(T root) {
    Collection<T> successors = new ArrayList<T>();
    Tree<T> tree = getTree(root);
    if (null != tree) {
      for (Tree<T> leaf : tree.leafs) {
        successors.add(leaf.head);
      }
    }
    return successors;
  }

  public Collection<Tree<T>> getSubTrees() {
    return leafs;
  }

  public static <T> Collection<T> getSuccessors(T of, Collection<Tree<T>> in) {
    for (Tree<T> tree : in) {
      if (tree.locate.containsKey(of)) {
        return tree.getSuccessors(of);
      }
    }
    return new ArrayList<T>();
  }

  @Override
  public String toString() {
    return printTree(0);
  }

  private static final int indent = 2;

  private String printTree(int increment) {
    String s = "";
    String inc = "";
    for (int i = 0; i < increment; ++i) {
      inc = inc + " ";
    }
    s = inc + head;
    for (Tree<T> child : leafs) {
      s += "\n" + child.printTree(increment + indent);
    }
    return s;
  }
}

5
이 클래스 객체를 사용하여 만든 트리에서 DFS를 어떻게 구현합니까?
leba-lev

3
이 클래스를 사용하여 리프 제거는 어떻게 구현됩니까?
ghedas

2
헤드 필드는 무엇에 사용됩니까?
Acour83

2
이 클래스에 문서가 있다면 좋을 것입니다. 꽤 같은 방법이 무엇인지 이해하지 못하는 setAsParentgetHead할이 정말 트리 데이터 구조에 대한 몇 가지 도움을받을 수있는 시간입니다. 문서의 원본도 주석이 없습니다.
disasterkid

23

내가 핸들 일반적인 나무 그 작은 라이브러리를. 스윙 물건보다 훨씬 가볍습니다. 또한 그것을위한 maven 프로젝트 가 있습니다.


3
나는 지금 그것을 사용하고 있으며 훌륭하게 작동합니다. 내 자신의 사용자 정의를 위해 소스를 크게 변경해야했지만 훌륭한 출발점이되었습니다. 고마워요 Vivin!
jasop

20
public class Tree {
    private List<Tree> leaves = new LinkedList<Tree>();
    private Tree parent = null;
    private String data;

    public Tree(String data, Tree parent) {
        this.data = data;
        this.parent = parent;
    }
}

분명히 하위를 추가 / 제거하는 유틸리티 메소드를 추가 할 수 있습니다.


1
이것은 나무의 부모가 나무라는 것을 암시합니다. Tree Node 클래스를 만들려고한다고 생각합니다.
Madhur Bhargava

16

도메인을 위해 트리가 무엇인지 정의하는 것부터 시작해야합니다 . 먼저 인터페이스 를 정의하는 것이 가장 좋습니다 . 모든 트리 구조를 수정할 수있는 것은 아니며 노드 를 추가제거 할 수있는 기능은 선택적인 기능이므로 추가 인터페이스를 만들어야합니다.

값을 보유하는 노드 객체를 만들 필요가 없습니다 . 사실 이것은 대부분의 트리 구현에서 주요 디자인 결함과 오버 헤드로 간주됩니다. Swing을 보면 실제로 필요하지 않기 때문에 TreeModel노드 클래스가 없습니다 (만 DefaultTreeModel사용 TreeNode).

public interface Tree <N extends Serializable> extends Serializable {
    List<N> getRoots ();
    N getParent (N node);
    List<N> getChildren (N node);
}

가변 트리 구조 (노드 추가 및 제거 가능) :

public interface MutableTree <N extends Serializable> extends Tree<N> {
    boolean add (N parent, N node);
    boolean remove (N node, boolean cascade);
}

이러한 인터페이스가 주어지면 트리를 사용하는 코드는 트리가 어떻게 구현되는지에 대해 신경 쓸 필요가 없습니다. 이를 통해 일반 구현특수한 구현 을 사용할 수 있으며, 함수를 다른 API에 위임하여 트리를 실현할 수 있습니다.

예 : 파일 트리 구조

public class FileTree implements Tree<File> {

    @Override
    public List<File> getRoots() {
        return Arrays.stream(File.listRoots()).collect(Collectors.toList());
    }

    @Override
    public File getParent(File node) {
        return node.getParentFile();
    }

    @Override
    public List<File> getChildren(File node) {
        if (node.isDirectory()) {
            File[] children = node.listFiles();
            if (children != null) {
                return Arrays.stream(children).collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }
}

예 : 일반 트리 구조 (부모 / 자식 관계 기반) :

public class MappedTreeStructure<N extends Serializable> implements MutableTree<N> {

    public static void main(String[] args) {

        MutableTree<String> tree = new MappedTreeStructure<>();
        tree.add("A", "B");
        tree.add("A", "C");
        tree.add("C", "D");
        tree.add("E", "A");
        System.out.println(tree);
    }

    private final Map<N, N> nodeParent = new HashMap<>();
    private final LinkedHashSet<N> nodeList = new LinkedHashSet<>();

    private void checkNotNull(N node, String parameterName) {
        if (node == null)
            throw new IllegalArgumentException(parameterName + " must not be null");
    }

    @Override
    public boolean add(N parent, N node) {
        checkNotNull(parent, "parent");
        checkNotNull(node, "node");

        // check for cycles
        N current = parent;
        do {
            if (node.equals(current)) {
                throw new IllegalArgumentException(" node must not be the same or an ancestor of the parent");
            }
        } while ((current = getParent(current)) != null);

        boolean added = nodeList.add(node);
        nodeList.add(parent);
        nodeParent.put(node, parent);
        return added;
    }

    @Override
    public boolean remove(N node, boolean cascade) {
        checkNotNull(node, "node");

        if (!nodeList.contains(node)) {
            return false;
        }
        if (cascade) {
            for (N child : getChildren(node)) {
                remove(child, true);
            }
        } else {
            for (N child : getChildren(node)) {
                nodeParent.remove(child);
            }
        }
        nodeList.remove(node);
        return true;
    }

    @Override
    public List<N> getRoots() {
        return getChildren(null);
    }

    @Override
    public N getParent(N node) {
        checkNotNull(node, "node");
        return nodeParent.get(node);
    }

    @Override
    public List<N> getChildren(N node) {
        List<N> children = new LinkedList<>();
        for (N n : nodeList) {
            N parent = nodeParent.get(n);
            if (node == null && parent == null) {
                children.add(n);
            } else if (node != null && parent != null && parent.equals(node)) {
                children.add(n);
            }
        }
        return children;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        dumpNodeStructure(builder, null, "- ");
        return builder.toString();
    }

    private void dumpNodeStructure(StringBuilder builder, N node, String prefix) {
        if (node != null) {
            builder.append(prefix);
            builder.append(node.toString());
            builder.append('\n');
            prefix = "  " + prefix;
        }
        for (N child : getChildren(node)) {
            dumpNodeStructure(builder, child, prefix);
        }
    }
}

1
tree.add ( "A", "B"); 할 때이 구조를 따를 때 문제가 발생합니다. tree.add ( "A", "C"); tree.add ( "C", "D"); tree.add ( "E", "A"); E는 A의 부모입니다. 어떻게하면됩니까?
saNiks

1
안녕하세요 saNicks, 위의 코드에 버그가있어 마지막 관계가 추가되지 않았습니다. 이제 수정되었으며 null이 아닌 검사와 (더 중요한) 순환 트리 검사를 추가하여 트리 구조를 위반하지 않도록합니다 (코드 또는 조상 중 하나를 자식으로 추가). 힌트 주셔서 감사합니다!
피터 월저

1
누군가가 당신이해야 할 버그에 대한 수정을 찾고 있다면 버그를 수정했습니다 .add 메소드가 false를 반환하는지 확인하고 false 인 경우 임시 새 LinkedHashSet <N>을 만들고 트리의 노드 목록을 복제하면 U를 지울 수 있습니다 트리에서 이전 단계에서 추가되지 않은 부모 노드를 추가 한 다음 모든 tempNode를 부모 트리에 다시 추가하십시오 ...하지만 구조에 감사드립니다!
saNiks

2
인터페이스에서 쓸모없는 공용 수정자를 제거하십시오.
Hamedz

1
어떻게 이것에서 json 배열을 생성 할 수
있습니까?

12

지나치게 단순화되었지만 작동하는 코드에 대한 답변은 없으므로 다음과 같습니다.

public class TreeNodeArray<T> {
    public T value;
    public final  java.util.List<TreeNodeArray<T>> kids =  new java.util.ArrayList<TreeNodeArray<T>>();
}

10

Java의 모든 XML API를 문서 및 노드로 사용할 수 있습니다. XML은 문자열이있는 트리 구조입니다.


5
훌륭한 아이디어, dom4j + jaxen xpath를 사용하여 노드를 검색하는 메모리 XML 스키마에서 사용할 수 있습니다.
벤 후마 Zied

8

화이트 보드 코딩, 인터뷰 또는 트리 사용을 계획하고있는 경우에는 그 정도가 약간입니다.

더 이유 나무는, 말처럼 거기에 아니라고 말할 수 있어야 Pair당신이 그것을 사용하여 클래스에 데이터를 캡슐화해야하기 때문에 (동일라고 할 수있는 대한)입니다 간단한 구현 외모와 같은 :

/***
/* Within the class that's using a binary tree for any reason. You could 
/* generalize with generics IFF the parent class needs different value types.
 */
private class Node {
  public String value;
  public Node[] nodes; // Or an Iterable<Node> nodes;
}

그것은 실제로 임의의 폭 트리에 대한 것입니다.

이진 트리를 원한다면 명명 된 필드와 함께 사용하기가 더 쉽습니다.

private class Node { // Using package visibility is an option
  String value;
  Node left;
  Node right;
}

또는 트라이를 원한다면 :

private class Node {
  String value;
  Map<char, Node> nodes;
}

이제 당신이 원한다고 말 했어요

주어진 노드를 나타내는 입력 문자열이 주어지면 모든 자식 (일종의 목록 또는 문자열 배열)을 얻을 수 있습니다.

숙제처럼 들리네
하지만 마감 기한이 지났다는 것이 합리적입니다.

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;

public class kidsOfMatchTheseDays {
 static private class Node {
   String value;
   Node[] nodes;
 }

 // Pre-order; you didn't specify.
 static public List<String> list(Node node, String find) {
   return list(node, find, new ArrayList<String>(), false);
 }

 static private ArrayList<String> list(
     Node node,
     String find,
     ArrayList<String> list,
     boolean add) {
   if (node == null) {
     return list;
   }
   if (node.value.equals(find)) {
     add = true;
   }
   if (add) {
     list.add(node.value);
   }
   if (node.nodes != null) {
     for (Node child: node.nodes) {
       list(child, find, list, add);
     }
   }
   return list;
 }

 public static final void main(String... args) {
   // Usually never have to do setup like this, so excuse the style
   // And it could be cleaner by adding a constructor like:
   //     Node(String val, Node... children) {
   //         value = val;
   //         nodes = children;
   //     }
   Node tree = new Node();
   tree.value = "root";
   Node[] n = {new Node(), new Node()};
   tree.nodes = n;
   tree.nodes[0].value = "leftish";
   tree.nodes[1].value = "rightish-leafy";
   Node[] nn = {new Node()};
   tree.nodes[0].nodes = nn;
   tree.nodes[0].nodes[0].value = "off-leftish-leaf";
   // Enough setup
   System.out.println(Arrays.toString(list(tree, args[0]).toArray()));
 }
}

이렇게하면 다음과 같이 사용할 수 있습니다.

$ java kidsOfMatchTheseDays leftish
[leftish, off-leftish-leaf]
$ java kidsOfMatchTheseDays root
[root, leftish, off-leftish-leaf, rightish-leafy]
$ java kidsOfMatchTheseDays rightish-leafy
[rightish-leafy]
$ java kidsOfMatchTheseDays a
[]

7

Gareth의 답변과 동일한 줄을 따라 DefaultMutableTreeNode를 확인하십시오 . 일반적인 것은 아니지만 법안에 맞는 것 같습니다. javax.swing 패키지에 있지만 AWT 또는 Swing 클래스에 의존하지 않습니다. 실제로 소스 코드에는 실제로 주석이 있습니다.// ISSUE: this class depends on nothing in AWT -- move to java.util?


롤,이 수업을 어떻게 봤어?
Pacerier

7

Java에는 JDK Swing의 DefaultMutableTreeNode, Stanford 파서 패키지의 Tree 및 기타 장난감 코드와 같은 몇 가지 트리 데이터 구조가 있습니다. 그러나 이것들 중 어느 것도 일반적인 목적으로 충분하지만 충분히 작지는 않습니다.

Java-tree 프로젝트는 Java에서 또 다른 범용 트리 데이터 구조를 제공하려고합니다. 이것과 다른 것의 차이점은

  • 완전 무료입니다. 어디에서나 사용할 수 있습니다 (숙제 제외 : P)
  • 작지만 일반적입니다. 데이터 구조의 모든 것을 하나의 클래스 파일에 넣었으므로 복사 / 붙여 넣기가 쉽습니다.
  • 장난감뿐만 아니라 이진 트리 또는 제한된 작업 만 처리 할 수있는 수십 개의 Java 트리 코드를 알고 있습니다. 이 TreeNode는 그 이상입니다. 프리오더, 포스트 오더, 너비 우선, 잎, 루트 경로 등 노드를 방문하는 다양한 방법을 제공합니다. 또한, 반복자도 충분하게 제공됩니다.
  • 더 많은 유틸리티가 추가됩니다. 특히 github을 통해 요청을 보내는 경우이 프로젝트를 포괄적으로 만들기 위해 더 많은 작업을 추가하고자합니다.


5

질문에 사용 가능한 데이터 구조가 필요하므로 목록 또는 배열로 트리를 구성 할 수 있습니다.

Object[] tree = new Object[2];
tree[0] = "Hello";
{
  Object[] subtree = new Object[2];
  subtree[0] = "Goodbye";
  subtree[1] = "";
  tree[1] = subtree;
}

instanceof 요소가 서브 트리인지 터미널 노드인지를 판별하는 데 사용될 수 있습니다.


2
아주 못생긴. 데이터 객체가 각각 배열로 나열되어 있으면 작동하지 않습니다.
user686249 2016 년

1
나는 그것이 추한 것에 동의합니다. Object들 중 하나 잎 개체 (예를 들어, 것 String(배열로 표시됨) S) 또는 지점을. 그리고 그것은 작동합니다 : 그 코드는 컴파일되고 작은 트리를 만듭니다 String.
Olathe

5
public abstract class Node {
  List<Node> children;

  public List<Node> getChidren() {
    if (children == null) {
      children = new ArrayList<>();
    }
    return chidren;
  }
}

사용하기 매우 쉽고 간단합니다. 사용하려면 확장하십시오.

public class MenuItem extends Node {
  String label;
  String href;
  ...
}

3

예를 들면 다음과 같습니다.

import java.util.ArrayList;
import java.util.List;



/**
 * 
 * @author X2
 *
 * @param <T>
 */
public class HisTree<T> 
{
    private Node<T> root;

    public HisTree(T rootData) 
    {
        root = new Node<T>();
        root.setData(rootData);
        root.setChildren(new ArrayList<Node<T>>());
    }

}

class Node<T> 
{

    private T data;
    private Node<T> parent;
    private List<Node<T>> children;

    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
    public Node<T> getParent() {
        return parent;
    }
    public void setParent(Node<T> parent) {
        this.parent = parent;
    }
    public List<Node<T>> getChildren() {
        return children;
    }
    public void setChildren(List<Node<T>> children) {
        this.children = children;
    }
}

3

과거에는 이것을 위해 중첩 맵을 사용했습니다. 이것은 내가 오늘 사용하는 것입니다. 매우 간단하지만 내 요구에 맞습니다. 어쩌면 이것이 다른 도움이 될 것입니다.

import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * Created by kic on 16.07.15.
 */
public class NestedMap<K, V> {
    private final Map root = new HashMap<>();

    public NestedMap<K, V> put(K key) {
        Object nested = root.get(key);

        if (nested == null || !(nested instanceof NestedMap)) root.put(key, nested = new NestedMap<>());
        return (NestedMap<K, V>) nested;
    }

    public Map.Entry<K,V > put(K key, V value) {
        root.put(key, value);

        return (Map.Entry<K, V>) root.entrySet().stream().filter(e -> ((Map.Entry) e).getKey().equals(key)).findFirst().get();
    }

    public NestedMap<K, V> get(K key) {
        return (NestedMap<K, V>) root.get(key);
    }

    public V getValue(K key) {
        return (V) root.get(key);
    }

    @JsonValue
    public Map getRoot() {
        return root;
    }

    public static void main(String[] args) throws Exception {
        NestedMap<String, Integer> test = new NestedMap<>();
        test.put("a").put("b").put("c", 12);
        Map.Entry<String, Integer> foo = test.put("a").put("b").put("d", 12);
        test.put("b", 14);
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(test));

        foo.setValue(99);
        System.out.println(mapper.writeValueAsString(test));

        System.out.println(test.get("a").get("b").getValue("d"));
    }
}

3

경로 추가를 지원하는 "HashMap"을 기반으로 작은 "TreeMap"클래스를 작성했습니다.

import java.util.HashMap;
import java.util.LinkedList;

public class TreeMap<T> extends LinkedHashMap<T, TreeMap<T>> {

    public void put(T[] path) {
        LinkedList<T> list = new LinkedList<>();
        for (T key : path) {
            list.add(key);
        }
        return put(list);
    }

    public void put(LinkedList<T> path) {
        if (path.isEmpty()) {
            return;
        }
        T key = path.removeFirst();
        TreeMap<T> val = get(key);
        if (val == null) {
            val = new TreeMap<>();
            put(key, val);
        }
        val.put(path);
    }

}

"T"(일반) 유형의 트리를 저장하는 데 사용할 수 있지만 노드에 추가 데이터 저장을 지원하지는 않습니다. 다음과 같은 파일이있는 경우 :

root, child 1
root, child 1, child 1a
root, child 1, child 1b
root, child 2
root, child 3, child 3a

그런 다음 다음을 실행하여 트리로 만들 수 있습니다.

TreeMap<String> root = new TreeMap<>();
Scanner scanner = new Scanner(new File("input.txt"));
while (scanner.hasNextLine()) {
  root.put(scanner.nextLine().split(", "));
}

그리고 당신은 좋은 나무를 얻을 것입니다. 귀하의 요구에 쉽게 적응할 수 있어야합니다.


2

Jakarta Project의 일부인 Apache JMeter에 포함 된 HashTree 클래스를 사용할 수 있습니다 .

HashTree 클래스는 org.apache.jorphan.collections 패키지에 포함되어 있습니다. 이 패키지는 JMeter 프로젝트 외부에서 출시되지는 않지만 쉽게 얻을 수 있습니다.

1) JMeter 소스 다운로드 .

2) 새 패키지를 작성하십시오.

3) / src / jorphan / org / apache / jorphan / collections /에 복사하십시오. Data.java를 제외한 모든 파일

4) /src/jorphan/org/apache/jorphan/util/JOrphanUtils.java도 복사하십시오.

5) HashTree를 사용할 준비가되었습니다.


2

Java에는 요구 사항에 맞는 특정 데이터 구조가 없습니다. 요구 사항은 매우 구체적이며 자체 데이터 구조를 설계해야합니다. 요구 사항을 살펴보면 누구나 특정 기능을 가진 일종의 n-ary 트리가 필요하다고 말할 수 있습니다. 다음과 같은 방식으로 데이터 구조를 설계 할 수 있습니다.

  1. 트리의 노드 구조는 노드의 컨텐츠 및 하위 목록과 같습니다. class Node {String value; 자녀 나열;}
  2. 주어진 문자열의 자식을 검색해야하므로 두 가지 방법을 사용할 수 있습니다 1 : Node searchNode (String str), 주어진 입력과 동일한 값을 가진 노드를 반환합니다 (검색에 BFS 사용) 2 : List getChildren (String str) :이 메소드는 내부적으로 searchNode를 호출하여 동일한 문자열을 가진 노드를 가져온 다음 하위의 모든 문자열 값 목록을 작성하고 리턴합니다.
  3. 또한 트리에 문자열을 삽입해야합니다. void insert (String parent, String value)라는 하나의 메소드를 작성해야합니다. 이것은 다시 parent와 같은 값을 가진 노드를 검색 한 다음 주어진 값으로 노드를 생성하고 발견 된 부모에 대한 자식 목록에 추가 할 수 있습니다 .

Class Node {String value;와 같은 하나의 클래스에 노드의 구조를 작성하는 것이 좋습니다. children;} 및 다른 NodeUtils 클래스에 search, insert 및 getChildren과 같은 다른 모든 메소드를 나열하여 트리의 루트를 전달하여 다음과 같은 특정 트리에서 작업을 수행 할 수 있습니다. class NodeUtils {public static Node search (Node root, String value) {// BFS를 수행하고 노드를 반환}


2
    // TestTree.java
// A simple test to see how we can build a tree and populate it
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;

public class TestTree extends JFrame {

  JTree tree;
  DefaultTreeModel treeModel;

  public TestTree( ) {
    super("Tree Test Example");
    setSize(400, 300);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public void init( ) {
    // Build up a bunch of TreeNodes. We use DefaultMutableTreeNode because the
    // DefaultTreeModel can use it to build a complete tree.
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
    DefaultMutableTreeNode subroot = new DefaultMutableTreeNode("SubRoot");
    DefaultMutableTreeNode leaf1 = new DefaultMutableTreeNode("Leaf 1");
    DefaultMutableTreeNode leaf2 = new DefaultMutableTreeNode("Leaf 2");

    // Build our tree model starting at the root node, and then make a JTree out
    // of it.
    treeModel = new DefaultTreeModel(root);
    tree = new JTree(treeModel);

    // Build the tree up from the nodes we created.
    treeModel.insertNodeInto(subroot, root, 0);
    // Or, more succinctly:
    subroot.add(leaf1);
    root.add(leaf2);

    // Display it.
    getContentPane( ).add(tree, BorderLayout.CENTER);
  }

  public static void main(String args[]) {
    TestTree tt = new TestTree( );
    tt.init( );
    tt.setVisible(true);
  }
}

3
코드를 덤프하지 말고 코드의 기능, 특히 다른 모든 응답과 다른 이유를 설명하십시오.
Jan Doggen

2

Java8과 잘 작동하고 다른 종속성이없는 트리 라이브러리를 작성했습니다. 또한 함수형 프로그래밍의 일부 아이디어에 대한 느슨한 해석을 제공하며 전체 트리 또는 하위 트리를 매핑 / 필터링 / 정리 / 검색 할 수 있습니다.

https://github.com/RutledgePaulV/prune

구현은 인덱싱과 관련하여 특별한 작업을 수행하지 않으며 재귀를 피하지 않았으므로 큰 트리를 사용하면 성능이 저하되고 스택을 날릴 수 있습니다. 그러나 필요한 모든 것이 작고 중간 정도의 간단한 나무이면 충분하다고 생각합니다. 평등에 대한 제정신 (값 기반) 정의를 제공하고 트리를 시각화 할 수있는 toString 구현도 있습니다!


1

Collection 클래스를 사용하지 않고 Tree 데이터 구조를 사용한 아래 코드를 확인하십시오. 코드에 버그 / 개선이있을 수 있지만 참조 용으로 만 사용하십시오

package com.datastructure.tree;

public class BinaryTreeWithoutRecursion <T> {

    private TreeNode<T> root;


    public BinaryTreeWithoutRecursion (){
        root = null;
    }


    public void insert(T data){
        root =insert(root, data);

    }

    public TreeNode<T>  insert(TreeNode<T> node, T data ){

        TreeNode<T> newNode = new TreeNode<>();
        newNode.data = data;
        newNode.right = newNode.left = null;

        if(node==null){
            node = newNode;
            return node;
        }
        Queue<TreeNode<T>> queue = new Queue<TreeNode<T>>();
        queue.enque(node);
        while(!queue.isEmpty()){

            TreeNode<T> temp= queue.deque();
            if(temp.left!=null){
                queue.enque(temp.left);
            }else
            {
                temp.left = newNode;

                queue =null;
                return node;
            }
            if(temp.right!=null){
                queue.enque(temp.right);
            }else
            {
                temp.right = newNode;
                queue =null;
                return node;
            }
        }
        queue=null;
        return node; 


    }

    public void inOrderPrint(TreeNode<T> root){
        if(root!=null){

            inOrderPrint(root.left);
            System.out.println(root.data);
            inOrderPrint(root.right);
        }

    }

    public void postOrderPrint(TreeNode<T> root){
        if(root!=null){

            postOrderPrint(root.left);

            postOrderPrint(root.right);
            System.out.println(root.data);
        }

    }

    public void preOrderPrint(){
        preOrderPrint(root);
    }


    public void inOrderPrint(){
        inOrderPrint(root);
    }

    public void postOrderPrint(){
        inOrderPrint(root);
    }


    public void preOrderPrint(TreeNode<T> root){
        if(root!=null){
            System.out.println(root.data);
            preOrderPrint(root.left);
            preOrderPrint(root.right);
        }

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BinaryTreeWithoutRecursion <Integer> ls=  new BinaryTreeWithoutRecursion <>();
        ls.insert(1);
        ls.insert(2);
        ls.insert(3);
        ls.insert(4);
        ls.insert(5);
        ls.insert(6);
        ls.insert(7);
        //ls.preOrderPrint();
        ls.inOrderPrint();
        //ls.postOrderPrint();

    }

}

2
" Collection 클래스를 사용하지 않고 "Ah? 그렇다면 큐 클래스는 어디에서 왔습니까? 그리고 위에서 말했듯이, 그것은 첫 번째 요구 사항 (모든 자식 노드)에서 실패하는 이진 트리입니다.
PhiLho

1

java.util. *에서 TreeSet 클래스를 사용할 수 있습니다. 이진 검색 트리처럼 작동하므로 이미 정렬되어 있습니다. TreeSet 클래스는 Iterable, Collection 및 Set 인터페이스를 구현합니다. 세트처럼 반복자를 사용하여 트리를 통과 할 수 있습니다.

TreeSet<String> treeSet = new TreeSet<String>();
Iterator<String> it  = treeSet.Iterator();
while(it.hasNext()){
...
}

Java Doc기타를 확인할 수 있습니다 .


-1

Collection 프레임 워크를 사용하지 않고 Tree의 Custom Tree 구현. Tree 구현에 필요한 다른 기본 작업이 포함되어 있습니다.

class Node {

    int data;
    Node left;
    Node right;

    public Node(int ddata, Node left, Node right) {
        this.data = ddata;
        this.left = null;
        this.right = null;      
    }

    public void displayNode(Node n) {
        System.out.print(n.data + " "); 
    }

}

class BinaryTree {

    Node root;

    public BinaryTree() {
        this.root = null;
    }

    public void insertLeft(int parent, int leftvalue ) {
        Node n = find(root, parent);
        Node leftchild = new Node(leftvalue, null, null);
        n.left = leftchild;
    }

    public void insertRight(int parent, int rightvalue) {
        Node n = find(root, parent);
        Node rightchild = new Node(rightvalue, null, null);
        n.right = rightchild;
    }

    public void insertRoot(int data) {
        root = new Node(data, null, null);
    }

    public Node getRoot() {
        return root;
    }

    public Node find(Node n, int key) {     
        Node result = null;

        if (n == null)
            return null;

        if (n.data == key)
            return n;

        if (n.left != null)
            result = find(n.left, key);

        if (result == null)
            result = find(n.right, key);

        return result;
    } 

    public int getheight(Node root){
        if (root == null)
            return 0;

        return Math.max(getheight(root.left), getheight(root.right)) + 1; 
    }

    public void printTree(Node n) {     
        if (n == null)
            return;

        printTree(n.left);
        n.displayNode(n);
        printTree(n.right);             
    }

}

11
이진 트리, 그것은 OP의 첫 번째 요구 사항에서 실패합니다 ...
PhiLho
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.