W postaci konsolowej możemy zapisać jego strukturę tak:
Adam Ewa Jurek Max Iza Jarek Iwona Marta Rafał Olalub tak:
Adam(Ewa(Jurek, Max, Iza), Jarek(Iwona), Marta(Rafał, Ola))W obu przypadkach odczytujemy: Adam jest korzeniem i ma trójkę "dzieci" (Ewa, Jarek oraz Marta), Ewa ma trójkę "dzieci" (Jurek, Max oraz Iza), Jarek ma jedno "dziecko" (Iwona), Marta ma dwójkę "dzieci" (Rafał i Ola).
Jak utworzyć metody, które wyświetlą nam odpowiednią kolejność elementów oraz zapewnią formatowanie? Przyjrzyjmy się najpierw kolejności elementów....tak dokładnie to jest kolejność preorder. Wystarczy teraz tylko odpowiednio dokonać formatowania oraz wyświetlić zawartość elementów. Pierwszy sposób wymaga dopisania metody, która będzie dla danego elementu zwracać jego poziom (odległość od korzenia drzewa). Napiszemy w klasie Tree<T> prostą metodę rekurencyjną getLevel():
public int getLevel(Node<T> n) { if (n == root) return 0; else return 1 + getLevel(n.getParent()); }Dodatkowo dodamy do naszej klasy pole output typu StringBuilder (taki dynamiczny String). W tej zmiennej będziemy przechowywać widok naszego drzewa. Metoda, która przygotuje nam ten widok działa bardzo podobnie jak metoda trawersująca typu preorder. Jedyne modyfikacje to pobieranie poziomu węzła i dodawanie odpowiedniej ilości znaków tabulacji (symulacja kolumn).
private void makeTreeStringOutline(Node<T> n) { for(int i=0; i < getLevel(n); i++) output.append("\t"); output.append(n + "\n"); Node<T> temp = n.getLeftMostChild(); while (temp != null) { makeString(temp); temp = temp.getRightSibling(); } }Drugi sposób prezentacji drzewa zostanie zrealizowany bardzo podobnie. Opieramy się na trawersowaniu preorder oraz wstawiamy w odpowiednie miejsca znaki nawiasów (otwierające i zamykające).
private void makeTreeStringBrackets(Node<T> n) { output.append(n); Node<T> temp = n.getLeftMostChild(); if( temp != null) output.append("("); while (temp != null) { makeStringPar(temp); temp = temp.getRightSibling(); if (temp != null) output.append(", "); else output.append(")"); } }Wywołanie tych metod możemy umieścić w dowolnej metodzie. Najlepiej będzie wykorzystać do tego celu metodę toString(). Przesłonięta wersja tej metody poniżej (prezentacja drzewa możliwa jest na dwa sposoby, jeden jest ujęty w komentarz).
public String toString() { output = new StringBuilder(); makeTreeStringOutline(root); // wersja "drzewiasta" //makeTreeStringBrackets(root); // wersja z nawiasami return output.toString(); }Pozostaje tylko sprawdzenie czy nasz kod działa. Utwórzmy drzewo i wyświetlmy je na konsoli.
Node<String> korzen = new Node<String>(null, "Adam"); Node<String> n1 = korzen.addChild("Ewa"); Node<String> n2 = korzen.addChild("Jarek"); Node<String> n3 = korzen.addChild("Marta"); n1.addChild("Jurek"); n1.addChild("Max"); n1.addChild("Iza"); n2.addChild("Iwona"); n3.addChild("Rafał"); n3.addChild("Ola"); Tree<String> drzewo = new Tree<String>(korzen); System.out.println (drzewo);Efekt działania:
Adam Ewa Jurek Max Iza Jarek Iwona Marta Rafał OlaPoniżej cały kod drzewa wraz ze wszystkimi klasami i metodami.
import java.util.*; /** * Klasa Node<T> - węzeł drzewa * @author kodatnik.blogspot.com */ class Node<T> { private T data; private Node<T> parent; private LinkedList<Node<T>> children; public Node() { parent = null; children = new LinkedList<Node<T>>(); } public Node(Node<T> parent) { this(); this.parent = parent; } public Node(Node<T> parent, T data) { this(parent); this.data = data; } public Node<T> getParent(){ return parent; } public void setParent(Node<T> parent) { this.parent = parent; } public T getData() { return data; } public void setData(T data) { this.data = data; } public int getDegree() { return children.size(); } public boolean isLeaf(){ return children.isEmpty(); } public Node<T> addChild(Node<T> child) { child.setParent(this); children.add(child); return child; } public Node<T> addChild(T data) { Node<T> child = new Node<T>(this, data); children.add(child); return child; } public Node<T> getChild(int i){ return children.get(i); } public Node<T> removeChild(int i) { return children.remove(i); } public void removeChildren() { children.clear(); } public LinkedList<Node<T>> getChildren() { return children; } public Node<T> getLeftMostChild() { if (children.isEmpty()) return null; return children.get(0); } public Node<T> getRightSibling() { if (parent != null) { LinkedList<Node<T>> parentsChildren = parent.getChildren(); int pos = parentsChildren.indexOf(this); if (pos < (parentsChildren.size()-1)) return parentsChildren.get(pos+1); } return null; } public String toString() { return data.toString(); } } /** * Klasa Tree<T> - drzewo * @author kodatnik.blogspot.com */ class Tree<T> { private Node<T> root; private StringBuilder output; public Tree() { root = null; } public Tree(Node<T> root) { this.root = root; } public Node<T> getRoot() { return root; } public void preOrder() { preOrder(root); } public void postOrder() { postOrder(root); } public void inOrder() { inOrder(root); } // metoda wyświetla węzły w kolejności preorder public void preOrder(Node<T> n) { //najpierw korzeń System.out.print(n + " "); // potem lewe skrajne poddrzewo, a później prawe Node<T> temp = n.getLeftMostChild(); while (temp != null) { preOrder(temp); temp = temp.getRightSibling(); } } // metoda wyświetla węzły w kolejności postorder public void postOrder(Node<T> n) { // najpierw lewe skrajne poddrzewo, potem prawe Node<T> temp = n.getLeftMostChild(); while (temp != null) { postOrder(temp); temp = temp.getRightSibling(); } // na końcu korzeń System.out.print(n + " "); } // metoda wyświetla węzły w kolejności inorder public void inOrder(Node<T> n) { if (n.isLeaf()) System.out.print(n + " "); else { // najpierw lewe skrajne poddrzewo Node<T> temp = n.getLeftMostChild(); inOrder(temp); // potem korzeń System.out.print(n + " "); // potem prawe temp = temp.getRightSibling(); while (temp != null) { inOrder(temp); temp = temp.getRightSibling(); } } } // metoda zwraca poziom węzła public int getLevel(Node<T> n) { if (n == root) return 0; else return 1 + getLevel(n.getParent()); } private void makeTreeStringOutline(Node<T> n) { for(int i=0; i < getLevel(n); i++) output.append("\t"); output.append(n + "\n"); Node<T> temp = n.getLeftMostChild(); while (temp != null) { makeTreeStringOutline(temp); temp = temp.getRightSibling(); } } private void makeTreeStringBrackets(Node<T> n) { output.append(n); Node<T> temp = n.getLeftMostChild(); if( temp != null) output.append("("); while (temp != null) { makeTreeStringBrackets(temp); temp = temp.getRightSibling(); if (temp != null) output.append(", "); else output.append(")"); } } public String toString() { output = new StringBuilder(); makeTreeStringOutline(root); // reprezentacja drzewiasta //makeTreeStringBrackets(root); // reprezentacja z nawiasami return output.toString(); } } public class NaszeDrzewo { public static void main(String args[]) { // tworzymy węzeł będący korzeniem Node<String> korzen = new Node<String>(null, "Adam"); // dodajemy do niego kolejne węzły Node<String> n1 = korzen.addChild("Ewa"); Node<String> n2 = korzen.addChild("Jarek"); Node<String> n3 = korzen.addChild("Marta"); n1.addChild("Jurek"); n1.addChild("Max"); n1.addChild("Iza"); n2.addChild("Iwona"); n3.addChild("Rafał"); n3.addChild("Ola"); // tworzymy drzewo i wskazujemy, który węzeł jest korzeniem Tree<String> drzewo = new Tree<String>(korzen); System.out.println(drzewo); } }
2 Komentarze - Wyświetlanie drzewa na konsoli
Świetny wpis, dziękuję!
Drobiazg:
W opisie deklaracji metod makeTreeStringOutline i makeTreeStringBrackets jest błąd.
jest: makeString(temp); powinno być: makeTreeStringOutline(temp);
jest: makeStringPar(temp); powinno być: makeTreeStringBrackets(temp);
naprawde cenne rady
Prześlij komentarz
Możesz użyć niektórych tagów HTML, takich jak <b>, <i>, <u>, <a> Nie spamuj :)