node library code java data-structures tree

library - tree java api



Estructura de datos del árbol de Java? (24)

Árbol personalizado implementado de árbol sin utilizar el marco de la colección. Contiene diferentes operaciones fundamentales necesarias en la implementación del árbol.

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

¿Existe una buena estructura de datos disponible (Java estándar) para representar un árbol en Java?

Específicamente necesito representar lo siguiente:

  • El árbol en cualquier nodo puede tener un número arbitrario de hijos
  • Cada nodo (después de la raíz) es solo una cadena (cuyos hijos también son cadenas)
  • Necesito poder obtener todos los hijos (algún tipo de lista o matriz de cadenas) dada una cadena de entrada que representa un nodo determinado

¿Existe una estructura disponible para esto o debo crear la mía (si es así, las sugerencias de implementación serían excelentes)?


Aquí:

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

Esa es una estructura de árbol básica que puede usarse para String o cualquier otro objeto. Es bastante fácil implementar árboles simples para hacer lo que necesita.

Todo lo que necesita agregar son métodos para agregar, eliminar, atravesar y constructores. El Node es el bloque de construcción básico del Tree .


Dado que la pregunta solicita una estructura de datos disponible, se puede construir un árbol a partir de listas o matrices:

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

instanceof se puede usar para determinar si un elemento es un subárbol o un nodo terminal.


Debe comenzar por definir qué es un árbol (para el dominio); esto se hace mejor definiendo primero la interfaz . No todas las estructuras de árboles son modificables, la posibilidad de agregar y eliminar nodos debe ser una característica opcional, por lo que creamos una interfaz adicional para eso.

No es necesario crear objetos de nodo que contengan los valores , de hecho, veo esto como un defecto de diseño y una sobrecarga en la mayoría de las implementaciones de árbol. Si nos fijamos en Swing, TreeModel está libre de clases de nodos (solo DefaultTreeModel utiliza TreeNode ), ya que no son realmente necesarios.

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

Dadas estas interfaces, el código que utiliza árboles no tiene que preocuparse mucho por cómo se implementa el árbol. Esto le permite usar implementaciones genéricas y especializadas , donde se realiza el árbol delegando funciones a otra API.
Ejemplo: estructura de árbol de archivos.

public class MappedTreeStructure<N extends Serializable> implements MutableTree<N> { public static void main(String[] args) { MutableTree<String> tree = new MappedTreeStructure<String>(); 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<N, N>(); private final LinkedHashSet<N> nodeList = new LinkedHashSet<N>(); 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<N>(); 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); } } }


En el pasado acabo de usar un mapa anidado para esto. Esto es lo que uso hoy en día, es muy simple pero se ajusta a mis necesidades. Tal vez esto ayude a otro.

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


En la misma línea que la respuesta de Gareth, echa un vistazo a DefaultMutableTreeNode . No es genérico, pero por lo demás parece encajar a la perfección. Aunque está en el paquete javax.swing, no depende de ninguna clase de AWT o Swing. De hecho, el código fuente en realidad tiene el comentario // ISSUE: this class depends on nothing in AWT -- move to java.util?


En realidad, hay una estructura de árbol bastante buena implementada en el JDK.

Eche un vistazo a javax.swing.tree , TreeModel y TreeNode . Están diseñados para ser utilizados con JTreePanel pero, de hecho, son una implementación bastante buena del árbol y no hay nada que le JTreePanel utilizarlo sin una interfaz swing.

Tenga en cuenta que a partir de Java 9 es posible que desee no utilizar estas clases, ya que no estarán presentes en los "perfiles compactos" .


Escribí una biblioteca de árbol que funciona bien con Java8 y que no tiene otras dependencias. También proporciona una interpretación flexible de algunas ideas de la programación funcional y le permite mapear / filtrar / podar / buscar en todo el árbol o subárboles.

https://github.com/RutledgePaulV/prune

La implementación no hace nada especial con la indexación y no me aparté de la recursión, por lo que es posible que el rendimiento de los árboles grandes se deteriore y se pueda volar la pila. Pero si todo lo que necesita es un árbol sencillo de profundidad pequeña a moderada, creo que funciona lo suficientemente bien. Proporciona una definición de igualdad sana (basada en valores) y también tiene una implementación toString que le permite visualizar el árbol.


Escribí una pequeña clase de "TreeMap" basada en "HashMap" que admite agregar rutas:

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

Puede usarse para almacenar un árbol de cosas de tipo "T" (genérico), pero (aún) no admite el almacenamiento de datos adicionales en sus nodos. Si tienes un archivo como este:

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

Entonces puedes convertirlo en un árbol ejecutando:

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

Y obtendrás un bonito árbol. Debe ser fácil adaptarse a sus necesidades.


Hay un par de estructuras de datos de árbol en Java, como DefaultMutableTreeNode en JDK Swing, Tree en el paquete del analizador de Stanford y otros códigos de juguetes. Pero ninguno de estos es suficiente, pero lo suficientemente pequeño para propósitos generales.

Java-tree proyecto Java-tree intenta proporcionar otra estructura de datos de árbol de propósito general en Java. La diferencia entre esto y otros son

  • Totalmente libre. Puedes usarlo en cualquier lugar (excepto en tu tarea: P)
  • Pequeño pero bastante general. Pongo todo de la estructura de datos en un archivo de clase, por lo que sería fácil de copiar y pegar.
  • No sólo unos juguetes. Soy consciente de docenas de códigos de árbol de Java que solo pueden manejar árboles binarios u operaciones limitadas. Este TreeNode es mucho más que eso. Proporciona diferentes formas de visitar nodos, como preorden, postorden, primero, hojas, ruta a la raíz, etc. Además, los iteradores también se proporcionan para la suficiencia.
  • Se añadirán más utiles. Estoy dispuesto a agregar más operaciones para hacer este proyecto completo, especialmente si envía una solicitud a través de github.

Ninguna respuesta menciona código simplificado pero en funcionamiento, así que aquí está:

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


No hay una estructura de datos específica en Java que se adapte a sus necesidades. Sus requisitos son bastante específicos y para eso necesita diseñar su propia estructura de datos. Observando sus requisitos, cualquiera puede decir que necesita algún tipo de árbol n-ario con alguna funcionalidad específica. Puedes diseñar tu estructura de datos de la siguiente manera:

  1. La estructura del nodo del árbol sería como contenido en el nodo y lista de elementos secundarios como: clase Nodo {valor de cadena; Lista de niños;}
  2. Debe recuperar los hijos de una cadena dada, de modo que puede tener 2 métodos 1: Nodo searchNode (String str), devolverá el nodo que tiene el mismo valor que la entrada dada (use BFS para buscar) 2: Listar GetChildren (String str): este método llamará internamente al searchNode para obtener el nodo que tiene la misma cadena y luego creará la lista de todos los valores de cadena de los hijos y la devolución.
  3. También se le pedirá que inserte una cadena en el árbol. Tendrá que escribir un método, digamos void insert (cadena principal, valor de cadena): esto buscará nuevamente el nodo que tiene un valor igual al principal y luego puede crear un nodo con un valor dado y agregarlo a la lista de elementos secundarios del padre encontrado .

Yo sugeriría que escriba la estructura del nodo en una clase como Class Node {String value; Listar niños;} y todos los otros métodos como buscar, insertar y obtener Niños en otra clase de NodeUtils para que también pueda pasar la raíz del árbol para realizar una operación en un árbol específico como: clase NodeUtils {búsqueda pública de Nodos estática (raíz del nodo, valor de cadena) {// realiza BFS y devuelve el nodo}


Otra estructura de árbol má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 ... }

Uso de la muestra:

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

PRIMA
Ver árbol de pleno derecho con:

  • iterador
  • buscando
  • Java / C #

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


Por ejemplo :

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


Puede usar cualquier API XML de Java como Documento y Nodo ... ya que XML es una estructura de árbol con cadenas


Puede usar la clase HashTree incluida en Apache JMeter que forma parte del Proyecto Jakarta.

La clase HashTree está incluida en el paquete org.apache.jorphan.collections. Aunque este paquete no se publica fuera del proyecto JMeter, puede obtenerlo fácilmente:

1) Descargar las fuentes de JMeter .

2) Crear un nuevo paquete.

3) Copie en él / src / jorphan / org / apache / jorphan / collections /. Todos los archivos excepto Data.java

4) Copie también /src/jorphan/org/apache/jorphan/util/JOrphanUtils.java

5) HashTree está listo para usar.


Puedes usar la clase TreeSet en java.util. *. Está funcionando como árbol de búsqueda binario, por lo que ya está ordenado. La clase TreeSet implementa interfaces iterables, de colección y de conjunto. Puedes atravesar el árbol con iterador como un conjunto.

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

Puedes comprobarlo, Java Doc y algunos other .


Que hay de esto

import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; /** * @author [email protected] (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; } }


Si está haciendo codificación de pizarra, una entrevista, o simplemente planea usar un árbol, la verbosidad de estos es un poco demasiado.

Además, debe decirse que la razón por la que un árbol no está allí como, por ejemplo, un Pair (sobre el cual podría decirse lo mismo), es porque debería estar encapsulando sus datos en la clase que lo usa, y la implementación más simple parece :

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

Eso es realmente para un árbol de ancho arbitrario.

Si desea un árbol binario, a menudo es más fácil de usar con campos con nombre:

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

O si querías un trie:

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

Ahora dijiste que querias

para poder obtener todos los elementos secundarios (algún tipo de lista o matriz de cadenas) dada una cadena de entrada que representa un nodo determinado

Eso suena como tu tarea.
Pero como estoy razonablemente seguro de que ya ha pasado cualquier fecha límite ...

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

Esto te hace usar como:

$ 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 []


Verifique el código de abajo, donde he usado estructuras de datos de árbol, sin usar clases de colección. El código puede tener errores / mejoras, pero use esto solo como referencia

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


wrote una pequeña biblioteca que maneja árboles genéricos. Es mucho más ligero que el columpio. También tengo un proyecto maven para ello.


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


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

Tan simple como es y muy fácil de usar. Para usarlo, extiéndelo:

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


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

Obviamente, puede agregar métodos de utilidad para agregar / eliminar hijos.