Java'da bir ağaç veri yapısı nasıl uygulanır? [kapalı]


496

Java'da bir ağacı temsil eden herhangi bir standart Java kütüphane sınıfı var mı?

Özellikle aşağıdakileri temsil etmeliyim:

  • Herhangi bir düğümdeki alt ağacın gelişigüzel sayıda çocuğu olabilir
  • Her düğüm (kökten sonra) ve alt öğeleri dize değerine sahip olacaktır
  • Belirli bir düğümün tüm çocukları (bir tür liste veya Dizeler dizisi) almak gerekir ve bu dize değeri (yani bir düğüm giriş olarak alacak ve çıkış olarak çocuk düğüm tüm dize değerlerini döndürecek bir yöntem)

Bunun için mevcut herhangi bir yapı var mı yoksa kendiminkini oluşturmam gerekiyor mu (eğer öyleyse uygulama önerileri harika olurdu).


3
Java 8 kullanıyorsanız ve düğümlerinizi akışlar, filtreleme vb.Ile dolaşmak istiyorsanız; o zaman Durian'a
Ned Twigg

1
Bu API'yı kullanabilirsiniz: sourceforge.net/p/treeds4j
Mohamed Ennahdi El Idrissi

Yanıtlar:


306

Buraya:

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;
    }
}

Bu, Stringherhangi bir nesne veya başka bir nesne için kullanılabilecek temel bir ağaç yapısıdır . İhtiyacınız olanı yapmak için basit ağaçlar uygulamak oldukça kolaydır.

Eklemeniz gereken tek şey yapıcılara ekleme, çıkarma, çapraz geçiş yapma ve yapıcı yöntemler. NodeTemel yapı taşıdır Tree.


304
Kesin anlamda Treeher çünkü sınıf, gerekli değildir Nodekendi içinde kutu bir ağaç olarak görülebilir.
Joachim Sauer

34
@Joa, kökü içerecek bir yapıya sahip olmayı seviyorum. Ağaç sınıfına, tek bir düğüm yerine bir ağaçta çağırmak için daha anlamlı yöntemler ekleyebilirsiniz.
jjnguy

24
@ Justin: örneğin? Bu dürüst bir soru: Bir alt ağaçta mantıklı olmayan tüm ağaç için anlamlı olan tek bir yöntem düşünemiyorum.
Joachim Sauer

22
@Joa ile Tree sınıfının gerekli olmadığını kabul ediyorum. Ayrı bir Tree sınıfı ekleyerek ve sürekli olarak Node sınıfını kullanarak kodların açıkça yinelenen ağaçlarını bırakmayı tercih ederim. Bunun yerine, bir ağacın kök Düğümüyle uğraştığınız net olması gerekiyorsa, değişken bir 'ağaç' veya 'kök' adını veririm.
jvdbogae

89
@Joa Dört yaşında bir çocuk benimle tamamen aynı fikirde. Ağaç sınıfını Nix.
jjnguy

122

Yine başka bir ağaç yapısı:

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 ...

}

Örnek kullanım:

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");
        }
    }
}

BONUS
Tam teşekküllü ağaca bakın:

  • yineleyici
  • Aranıyor
  • Java / C #

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


2
Sadece kitaplığınızı son derece kullanışlı buldunuz. Teşekkür ederim. Ancak ebeveyn ve çocuk arasındaki referans ilişkisine dayalı olarak ağaç yapısını dinamik olarak doldurarak nasıl uygulanacağını bilmek istiyorum. Verilen örnekte bir üye1 sponsorum başka bir üye2, üye2 sponsor üye 3 ve benzeri var. Zaten tablo kayıtları ilişkisi var ama emin değilim ben kitaplığınızı kullanarak onları bir ağaca doldurabilirsiniz.
d4v1dv00

1
2016 itibariyle, bağlantı hiçbir kaynak dosyası veya indirme içermiyor
Sharon Ben Asher

2
Benim görüşüme göre, yukarıdaki yüksek puanlı cevaptan üç yıl sonra bu cevap daha temizdir. Ancak, LinkedList, bunun için bir ArrayList ile değiştiririm. Çocuklar.
HopeKing

1
Çocuklar için bir Set kullanırdım.
DPM

Ben yanlış olabilir ama bu uygulama ile, geçerli sonuçlar almak hasNext()için her çağrıdan önce aramak gerekir gibi görünüyor next(). Bu Iteratorşartnamenin bir parçası değil .
Robert Lewis

97

Aslında JDK'da oldukça iyi bir ağaç yapısı var.

Göz at javax.swing.tree , TreeModel ve TreeNode . Onlar ile kullanılmak üzere tasarlanmıştır, JTreePanelancak aslında, oldukça iyi bir ağaç uygulamasıdır ve bir salıncak arayüzü ile kullanmanıza engel olan hiçbir şey yoktur.

Java 9'dan itibaren bu sınıfları 'Kompakt profiller'de bulunmayacağından kullanmak istemeyebilirsiniz .


5
Evet, onları geçmişte kullandım ve bir ağaçtan istediğiniz her şeyi yapacaklar. Düşünebildiğim tek dezavantajı, ilgili uygulama sınıflarının adlarının uzunluğudur: DefaultTreeModel ve DefaultMutableTreeNode. Ayrıntılı, ama bu kadar önemli değil sanırım.
Ultimate Gobblement

4
Bununla başa çıkmanın iyi bir yolu, birkaç statik yöntem oluşturmaktır: newModel () ve newNode () ve ardından bunları statik olarak içe aktarın.
Gareth Davis

140
Swing kütüphanelerini Swing ile ilgili olmayan fonksiyonlarda kullanmaktan kaçınırım. Bu kötü kodlama uygulaması . Swing'in ağaçlarını nasıl uyguladığını, bağımlılıklarının ne olduğunu ve gelecekte nasıl değişebileceğini asla bilemezsiniz. Swing bir yardımcı program kütüphanesi değil, bir UI kütüphanesidir.
jasop

44
Kötü kodlama pratiğinin biraz sert olduğunu düşünüyorum.
Gareth Davis

51
javax.swing.tree.TreeModel genel bir arayüzdür (tam olarak java.util.List gibi) ve uyumsuz değişikliklere sahip olmayacaktır. Ek bir avantaj, gelişirken ağacınızda kolayca hata ayıklama / görselleştirme yapabilmenizdir.
lbalazscs

45

Peki buna ne dersin?

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
Bu sınıf nesnesi kullanılarak oluşturulan bir ağaca DFS nasıl uygulanır?
leba-lev

3
Bu sınıf kullanılarak bir yaprağın kaldırılması nasıl uygulanır?
ghedas

2
Kafa alanı ne için kullanılır?
Acour83

2
Bu sınıfın bazı belgeleri olsaydı harika olurdu. Hangi yöntemlerin beğenildiğini setAsParentveya getHeadyapıldığını tam olarak anlamıyorum ve bu, ağaç veri yapıları hakkında gerçekten yardım alabileceğim zamandır. Belgenin orijinal kaynağında bile yorum yok.
disasterkid

23

Ben yazdım kolları genel ağaçlar bu biraz kütüphane. Salıncak malzemelerinden çok daha hafif. Bunun için bir maven projem de var .


3
Şimdi kullanıyorum, harika çalışıyor. Kendi özelleştirmelerim için kaynağı önemli ölçüde değiştirmek zorunda kaldım, ama harika bir başlangıç ​​noktasıydı. Teşekkürler 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;
    }
}

Açıkçası çocuk eklemek / kaldırmak için yardımcı yöntemler ekleyebilirsiniz.


1
Bu, bir ağacın ebeveyninin bir ağaç olduğunu gösterir. Bir Tree Node sınıfı oluşturmaya çalıştığınıza inanıyorum.
Madhur Bhargava

16

Bir ağacın ne olduğunu tanımlayarak başlamalısınız (etki alanı için), bu en iyi önce arabirimi tanımlayarak yapılır . Tüm ağaçlar yapıları edememek, modifyable olan ekleyebilir ve kaldır biz bunun için ekstra bir arayüz yapmak, böylece, düğümler isteğe bağlı bir özelliktir olmalıdır.

Değerleri tutan düğüm nesneleri oluşturmaya gerek yoktur , aslında bunu çoğu ağaç uygulamasında büyük bir tasarım hatası ve ek yük olarak görüyorum. Swing'e bakarsanız, gerçekten gerekli olmadıkları için TreeModeldüğüm sınıflarından (yalnızca DefaultTreeModelyararlanır TreeNode) arınmış olur .

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

Değişken ağaç yapısı (düğüm eklemeye ve kaldırmaya izin verir):

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

Bu arayüzler göz önüne alındığında, ağaçları kullanan kodun ağacın nasıl uygulandığı ile ilgilenmesi gerekmez. Bu, işlevleri başka bir API'ya devrederek ağacı gerçekleştirdiğiniz genel uygulamaları ve özel uygulamaları kullanmanıza olanak tanır .

Örnek: dosya ağacı yapısı

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();
    }
}

Örnek: genel ağaç yapısı (ebeveyn / çocuk ilişkilerine dayalı):

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") yaptığımda bu yapıyı izlediğimde bir sorunla karşılaşıyorum; tree.add ("A", "C"); tree.add ("C", "D"); tree.add ("E", "A"); E, A'nın bir ebeveynidir.
saNiks

1
Merhaba saNicks, yukarıdaki kodda son ilişkinin eklenmemesine neden olan bir hata vardı. Şimdi düzeltildi ve null olmayan kontroller ve (daha önemli): ağaç yapısını ihlal etmeyi önleyen döngüsel kontroller ekledim (çocuk olarak bir kod veya atalarından birini kendisine ekleme). İpucu için teşekkürler!
Peter Walser

1
Herkes bu hata için bir düzeltme arıyorsanız eğer ekleme yöntemi yanlış döndürür görmek ve yanlışsa sadece bir temp yeni LinkedHashSet <N> oluşturmak ve içine ağacın nodelist klonlamak o zaman u temizleyebilir hata düzeltildi ağaç, önceki adımda eklenmeyen üst düğümü ekleyin ve sonra tempNode öğesinin tümünü üst ağaca geri ekleyin ... Yine de yapı için teşekkürler!
saNiks

2
Bu yararsız genel değiştiricileri arayüzlerinizden kaldırın .
Hamedz

1
bundan nasıl bir json dizisi oluşturabilirim
Pawan Pandey

12

Hiçbir cevap aşırı basitleştirilmiş ama çalışma kodundan bahsetmez, işte burada:

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

10

Java'nın herhangi bir XML API'sını Belge ve Düğüm olarak kullanabilirsiniz ... XML, Dizeleri olan bir ağaç yapısıdır


5
mükemmel Fikir, biz düğüm XML arama dom4j + jaxen xpath kullanarak bellek XML şemasında kullanabilirsiniz.
Ben Rhouma Zied

8

Beyaz tahta kodlaması, röportaj veya hatta sadece bir ağaç kullanmayı planlıyorsanız, bunların ayrıntısı biraz fazladır.

Ayrıca, bir ağacın orada olmama nedeninin, örneğin, Pair(aynı şeylerin söylenebileceği gibi), verilerinizi sınıfta kullanarak onu kapsüllemeniz gerektiği ve en basit uygulamanın şöyle göründüğü söylenmelidir :

/***
/* 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;
}

Rastgele bir genişlik ağacı için gerçekten bu kadar.

İkili bir ağaç istiyorsanız, adlandırılmış alanlarla kullanmak genellikle daha kolaydır:

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

Veya bir trie istiyorsanız:

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

Şimdi istediğini söyledin

Belirli bir düğümü temsil eden bir giriş dizesi verilen tüm alt öğeleri (bir tür liste veya Dizeler dizisi) alabilmek

Ödevine benziyor.
Ama son teslim tarihinin geçtiğinden oldukça emin olduğum için…

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()));
 }
}

Bu gibi kullanır:

$ 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'in cevabı ile aynı satırlar boyunca, DefaultMutableTreeNode öğesine bakın . Genel değil, ama aksi takdirde tasarıyı uygun görünüyor. Javax.swing paketinde olmasına rağmen, herhangi bir AWT veya Swing sınıfına bağlı değildir. Aslında, kaynak kodun yorumu// ISSUE: this class depends on nothing in AWT -- move to java.util?


Lol, bu sınıfa nasıl rastladın?
Pacerier

7

Java'da JDK Swing'deki DefaultMutableTreeNode, Stanford ayrıştırıcı paketindeki Tree ve diğer oyuncak kodları gibi birkaç ağaç veri yapısı vardır. Ancak bunların hiçbiri genel amaç için yeterince küçük ve yeterli değildir.

Java ağacı projesi, Java'da başka bir genel amaçlı ağaç veri yapısı sağlamaya çalışır. Bu ve diğerleri arasındaki fark

  • Tamamen ücretsiz. Her yerde kullanabilirsiniz (ödeviniz hariç: P)
  • Küçük ama yeterince genel. Veri yapısının her şeyi tek bir sınıf dosyasına koydum, bu yüzden kopyalamak / yapıştırmak kolay olurdu.
  • Sadece bir oyuncak değil. Yalnızca ikili ağaçları veya sınırlı işlemleri gerçekleştirebilen düzinelerce Java ağacı kodunun farkındayım. Bu TreeNode bundan çok daha fazlası. Ön sipariş, postorder, genişlik, yapraklar, kök yolu vb. Gibi düğümleri ziyaret etmenin farklı yollarını sağlar. Ayrıca yineleyiciler de yeterlilik için sağlanır.
  • Daha fazla araç eklenecek. Özellikle github aracılığıyla bir istek gönderirseniz, bu projeyi kapsamlı hale getirmek için daha fazla işlem eklemek istiyorum.


5

Soru mevcut bir veri yapısı istediğinden, listelerden veya dizilerden bir ağaç oluşturulabilir:

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

instanceof bir öğenin alt ağaç mı yoksa terminal düğümü mü olduğunu belirlemek için kullanılabilir.


2
Oldukça çirkin. Veri nesneleriniz sıralı olarak listeleniyorsa ve çalışmaz.
user686249

1
Çirkin olduğuna katılıyorum. ObjectS, ya yaprak nesneleri (örneğin, olacaktır String(dizileri ile temsil edilmektedir) s) ya da dalları. Ve işe yarıyor: bu kod derlenecek ve küçük bir Strings ağacı oluşturacak .
Olathe

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

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

Oldukça basit ve kullanımı çok kolay. Kullanmak için uzatın:

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

3

Örneğin :

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

Geçmişte bunun için iç içe bir harita kullandım. Bugün kullandığım bu, çok basit ama ihtiyaçlarıma uyuyor. Belki bu bir başkasına yardım eder.

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

Ben yol eklemeyi destekleyen "HashMap" dayalı küçük bir "TreeMap" sınıfı yazdım:

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" (genel) türünde bir Ağacı saklamak için kullanılabilir, ancak düğümlerinde fazladan veri depolamayı desteklemez (henüz). Böyle bir dosyanız varsa:

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

Daha sonra bunu uygulayarak bir ağaç yapabilirsiniz:

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

Ve güzel bir ağaç alacaksın. İhtiyaçlarınıza uyum sağlamak kolay olmalıdır.


2

Jakarta Projesinin bir parçası olan Apache JMeter'de bulunan HashTree sınıfını kullanabilirsiniz .

HashTree sınıfı org.apache.jorphan.collections paketine dahil edilmiştir. Bu paket JMeter projesi dışında piyasaya sürülmese de kolayca alabilirsiniz:

1) JMeter kaynaklarını indirin .

2) Yeni bir paket oluşturun.

3) Üzerine kopyalayın / src / jorphan / org / apache / jorphan / collections /. Data.java dışındaki tüm dosyalar

4) Ayrıca /src/jorphan/org/apache/jorphan/util/JOrphanUtils.java kopyalayın

5) HashTree kullanıma hazırdır.


2

Java'da gereksinimlerinize uygun belirli bir veri yapısı yoktur. Gereksinimleriniz oldukça belirgindir ve bunun için kendi veri yapınızı tasarlamanız gerekir. Gereksinimlerinize bakıldığında, herkes belirli bir işlevselliğe sahip bir çeşit n-ary ağacına ihtiyacınız olduğunu söyleyebilir. Veri yapınızı aşağıdaki şekilde tasarlayabilirsiniz:

  1. Ağaç düğümünün yapısı, düğümdeki içerik ve aşağıdaki gibi çocukların listesi gibi olacaktır: class Node {String value; Çocukları listeleyin;}
  2. Belirli bir dizenin alt öğelerini almanız gerekir, böylece 2 yönteminiz olabilir 1: Düğüm searchNode (String str), verilen girişle aynı değere sahip düğümü döndürür (arama için BFS kullanın) 2: List getChildren (String str): bu yöntem, düğümün aynı dizeye sahip olmasını sağlamak için dahili olarak searchNode öğesini çağırır ve ardından tüm dize değerlerinin listesini oluşturur ve döndürür.
  3. Ayrıca ağaca bir dize eklemeniz istenir. Void insert (String parent, String value) diyen bir yöntem yazmanız gerekir: bu yine üst değere eşit olan düğümü arar ve verilen değere sahip bir Düğüm oluşturabilir ve bulunan üst öğeye çocuk listesine ekleyebilirsiniz. .

Sınıf Düğümü {String değeri gibi bir sınıfta düğümün yapısını yazmanızı öneririm. Çocukları;} ve başka bir NodeUtils sınıfında search, insert ve getChildren gibi diğer tüm yöntemleri listeler; {// BFS gerçekleştirin ve Düğümü döndürün}


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
Lütfen sadece kodu dökmeyin - ne yaptığını ve özellikle neden diğer tüm cevaplardan farklı olduğunu (daha iyi) açıklayın.
Jan Doggen

2

Java8 ile iyi oynanan ve başka bağımlılıkları olmayan bir ağaç kütüphanesi yazdım. Ayrıca, işlevsel programlamadan bazı fikirlerin gevşek bir yorumunu sağlar ve tüm ağacı veya alt ağaçları eşlemenizi / filtrelemenizi / budamanızı / aramanızı sağlar.

https://github.com/RutledgePaulV/prune

Uygulama indeksleme ile özel bir şey yapmaz ve özyinelemeden uzak durmadım, bu nedenle büyük ağaçlarda performansın düşmesi ve yığını patlatması mümkündür. Ancak ihtiyacınız olan tek şey küçük ila orta derinlikte basit bir ağaçsa, bence yeterince iyi çalışır. Aklı başında (değer temelli) bir eşitlik tanımı sağlar ve ayrıca ağacı görselleştirmenizi sağlayan bir toString uygulamasına sahiptir!


1

Lütfen koleksiyon kodlarını kullanmadan Tree veri yapılarını kullandığım aşağıdaki kodu kontrol edin. Kodda hatalar / iyileştirmeler olabilir, ancak lütfen sadece referans için kullanın

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
" Koleksiyon derslerini kullanmadan " Ah? Yani Queue sınıfı nereden geliyor? Ve yukarıda belirtildiği gibi, ilk gereksinimde (herhangi bir sayıda çocuk düğümü) başarısız olan bir ikili ağaçtır.
PhiLho

1

Java.util. * İçindeki TreeSet sınıfını kullanabilirsiniz. İkili arama ağacı gibi çalışıyor, bu yüzden zaten sıralanmış. TreeSet sınıfı Yinelenebilir, Toplama ve Ayarlama arabirimlerini uygular. Bir küme gibi yineleyici ile ağaçta gezinebilirsiniz.

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

Java Doc ve diğerlerini kontrol edebilirsiniz .


-1

Koleksiyon çerçevesini kullanmadan Tree'nin Özel Ağacı uygulaması. Ağaç uygulamasında ihtiyaç duyulan farklı temel işlemleri içerir.

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
Bu ikili bir ağaç, OP'nin ilk gereksiniminde başarısız ...
PhiLho
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.