Variable zurücksetzen (Java)?
Guten Tag,
habe hier eine Datenstruktur in dem ich Verwandtschaftsbeziehungen abbilde. (Teil der Aufgabe ist es die Datenstruktur selber zu erstellen).
https://paste.ofcode.org/q4VSbxZweKH9MuqPtiVdsW
Nun habe ich zwei Funktionen die als Eingabeparameter (node) benötigen.
Wenn ich nun die erste Funktion aufrufe wird dieser Parameter verändert wofür er für die zweite Funktion unbrauchbar wird.
Dies ist nun meine Frage wie kann ich root zurücksetzen oder die Sache auf lokaler Ebene gestalten?
Vielen Dank im Voraus
2 Antworten
Hallo Dieter,
ich versuche mal möglichst wenig zu ändern:
package algorithmen;
class Node {
private String data;
private Node child = null;
public Node(String data){
this(data, null);
}
public Node(String data, Node child) {
this.data = data;
this.child = child;
}
public void addChild(Node node) {
if (this.child == null) {
this.child = node;
} else {
this.child.addChild(node);
}
}
public void printChildren(Node node) {
int i = 0;
Node child = node.getChild();
while (child != null) {
System.out.println("\t"+child.getData());
child = child.getChild();
i++;
}
System.out.printf("Anzahl Kindern und Kindeskindern: %d\n", i);
}
public void printNextGeneration(Node node) {
Node child = node.getChild();
while (child != null) {
System.out.println("\t"+child.getData());
child = child.getChild();
}
}
public static void main(String[] args) {
Node root = new Node("1");
root.addChild(new Node("1. Kind von 1"));
root.addChild(new Node("2. Kind von 1"));
root.addChild(new Node("3. Kind von 1"));
root.addChild(new Node("4. Kind von 1"));
root.getChild().addChild(new Node("Kind von 1.Kind von 1"));
System.out.println("Methode Kinder");
root.printChildren(root);
System.out.println("Methode zeige naechste Generation");
root.printNextGeneration(root);
}
private String getData() {
return this.data;
}
private Node getChild() {
return this.child;
}
}
Zunächst mal habe ich die Klasse Child entfernt, da diese nichts tut, was nicht auch die Klasse Node schon tun würde. Nodes sind Kinder, wenn sie Nodes als Eltern haben. Du brauchst keine extra Klasse "Kind".
Dann habe ich alle Member der Klasse Node private gemacht. Somit kann ich auch nicht "versehentlich" die Member manipulieren so wie Du das gemachst hast.
Ich bin bei deiner Implementierung nicht sicher ob ein Node nicht beliebig viele Kinder haben kann. Es sieht etwas so aus. Wenn Du das erreichen möchtest, dann musst Du mit Listen, Arrays, oder ähnlichen Strukturen arbeiten. Bei der aktuellen Implementierung hat jeder Node maximal ein Kind. Dieses Kind kann selbst wieder maximal ein Kind besitzen.
Bei der Iteration, also wenn ich die Kinder und Kindeskinder ausgebe, verwende ich nun jeweils eine Hilfsvariable
Node child = node.getChild();
Damit verändere ich die Kinder nicht mehr so wie Du das zuvor gemacht hast. Es wäre mir nicht mal möglich, da ich die Member privat gemacht habe. Selbstverständlich könnte ich noch die addChild Methode aufrufen, aber diese sorgt dafür, dass ich keine Kinder überschreiben kann.
Um es ganz klar zu sagen, dein Problem ist das hier:
node.children=node.children.next;
children ist ein öffentliches Member von Node und Du überschreibst dieses Member mit dem Nachfolger von children. Das machst Du einmal für alle Kinder/Kindeskinder und damit ist die Struktur dann hin.
Gruß
Hallo Dieter,
ich haber hier mal ein Beispiel mit Listen gebaut. Ich vermute mal, dass Du Streams noch nicht gelernt hast, aber die sind einfach zu schön, darum habe ich sie benutzt.
Außerdem habe ic noch ein parent hinzugefügt, weil ich gerne eine Einrückung nach Anzahl der Elterngenerationen haben möchte.
Insgesamt kann man sicherlich noch eine Menge optimieren, aber für den Start schon brauchbar.
package algorithmen;
import com.google.inject.internal.util.ImmutableList;
import java.util.LinkedList;
import java.util.List;
class Node {
private String data;
private List<Node> children = new LinkedList<>();
private Node parent = null;
public Node(String data) {
this(data, null);
}
public Node(String data, Node child) {
this.data = data;
if (child != null) {
this.children.add(child);
}
}
public void addChild(Node node) {
node.setParent(this);
this.children.add(node);
}
public void printChildren() {
List<Node> children = getChildren();
children.forEach(Node::printNode);
}
public void printNode() {
int ancestorCount = this.getAncestorCount();
while (ancestorCount>0){
System.out.print("\t");
ancestorCount--;
}
System.out.println(this.getData());
}
public void printNextGeneration() {
List<Node> children = this.getChildren();
children.stream()
.peek(Node::printChildren)
.forEach(Node::printNextGeneration);
}
public static void main(String[] args) {
Node root = new Node("1");
Node firstChild = new Node("1. Kind von 1");
root.addChild(firstChild);
root.addChild(new Node("2. Kind von 1"));
root.addChild(new Node("3. Kind von 1"));
root.addChild(new Node("4. Kind von 1"));
Node childOfChild = new Node("Kind von 1.Kind von 1");
firstChild.addChild(childOfChild);
Node grandChild = new Node("Enkelkind von 1");
childOfChild.addChild(grandChild);
Node greatGrandChild = new Node("Urenkelkind von 1");
grandChild.addChild(greatGrandChild);
System.out.println("Methode Kinder");
root.printChildren();
System.out.printf("Anzahl Kindern: %d\n", root.getChildCount());
System.out.println("Methode zeige naechste Generationen");
root.printNextGeneration();
}
private String getData() {
return this.data;
}
private List<Node> getChildren() {
return ImmutableList.copyOf(this.children);
}
private int getChildCount() {
return children.size();
}
private void setParent(Node parent) {
this.parent = parent;
}
private Node getParent() {
return parent;
}
private int getAncestorCount() {
Node parent = getParent();
int ancestorCount =0;
while (parent!=null){
ancestorCount++;
parent = parent.getParent();
}
return ancestorCount;
}
}
Ausgabe:
Methode Kinder
1. Kind von 1
2. Kind von 1
3. Kind von 1
4. Kind von 1
Anzahl Kindern: 4
Methode zeige naechste Generationen
Kind von 1.Kind von 1
Enkelkind von 1
Urenkelkind von 1
printChildren gibt nun nur noch die direkten Kinder aus und wird von printNextGeneration benutzt. printNextGeneration geht nun in die Tiefe und gibt alle Generationen aus.
Die addChild Methode ist nun etwas interessanter, denn sie setzt mit
node.setParent(this);
gleich die richtige Eltern-Kind Beziehung. So kann man gar nicht erst vergessen den parent korrekt zu setzen.
printNode ist nur dafür Zuständig eine Ausgabe zu erzeugen und macht dabei die gewünschte Einrückung nach Anzahl der Vorfahren. Da müsste man dann überlegen ob man das bei einem printNode wirklich will, oder ob das nicht eher in die printNextGeneration gehört.
Gruß und viel Spaß, evtl. bringt es dich ja auf Ideen.
Wenn Du mir sagst welche Datenstruktren Du kennst, dann könnte ich damit eine Lösung implementieren.
Arrays vielleicht? Vectoren?
Irgendetwas um mehrere Referenzen aufzunehmen.
Gruß
Wissen Sie, eigentlich muss ich eine Aufgabe in ABAP umsetzen, es soll ein "Weihnachtsbaum" generiert werden. Bei dem durch Benutzereingabe von Tiefe des Baumes und Anzahl der maximalen Knoten ein entsprechender Baum generiert wird. Zunächst wollte ich die Datenstruktur in Java realisieren um erstmal eine Grundlage zu haben.
Die Anzahl der Kinder muss am Ende zufällig für jeden Elternknoten erzeugt werden. Ist dies mit Arrays möglich in Java? Kenne mich mit Java nicht aus, habe bis jetzt eher viel in C gemacht, da ABAP aber auch objektorientiert ist wollte ich es erstmal in Java umsetzen.
Wenn eine entsprechende Lösung für Arrays möglich ist bezüglich der zufälligen Anzahl dann würde ich mich darüber freuen.
Mit Arrays funktioniert das natürlich auch.
Dabei ist etwas schade, dass man eine dynamisch erweiterbare Struktur implementiert, nämlich den Baum, und dann auf eine statische Struktur wie einem Array zurückgreifen soll. Eine dynamisch verkettete Liste (Nodes mit Kind-Nodes) wäre viel sinnvoller.
Greift man auf Arrays zurück, dann muss man das Array unweigerlich irgendwann in ein größeres Array kopieren. Ich implementiere das hier so, dass ich bei einem neuen Child ein komplett neues Array erzeuge welches genau ein Element mehr fasst. Dann kopiere ich das alte Array in das neue Array und referenziere das neue Element an der letzten Stelle des Arrays. Für die Aufgabe sicherlich völlig ausreichend. Wenn man effizienter sein möchte, dann erweitert man das Array gleich um mehrere Elemente und merkt sich, welcher Index der zuletzt benutzte war. Beliebt ist hier die Array-Größe zu verdoppeln. Wenn man solchen Aufwand betreibt, dann kann man aber auch gleich über eine verkettete Liste nachdenken.
package algorithmen;
import java.util.Arrays;
class Node {
private String data;
private Node[] children = new Node[0];
private Node parent = null;
public Node(String data) {
this(data, null);
}
public Node(String data, Node child) {
this.data = data;
if (child != null) {
this.addChild(child);
}
}
public void addChild(Node node) {
node.setParent(this);
Node[] newChildren = copyArrayWithOneExtra(children);
newChildren[newChildren.length - 1] = node;
this.children = newChildren;
}
public void printChildren() {
Node[] children = getChildren();
Arrays.stream(children)
.forEach(Node::printNode);
}
public void printNode() {
int ancestorCount = this.getAncestorCount();
while (ancestorCount > 0) {
System.out.print("\t");
ancestorCount--;
}
System.out.println(this.getData());
}
public void printNextGeneration() {
Arrays.stream(children)
.peek(Node::printChildren)
.forEach(Node::printNextGeneration);
}
public static void main(String[] args) {
Node root = new Node("1");
Node firstChild = new Node("1. Kind von 1");
root.addChild(firstChild);
root.addChild(new Node("2. Kind von 1"));
root.addChild(new Node("3. Kind von 1"));
root.addChild(new Node("4. Kind von 1"));
Node childOfChild = new Node("Kind von 1.Kind von 1");
firstChild.addChild(childOfChild);
Node grandChild = new Node("Enkelkind von 1");
childOfChild.addChild(grandChild);
Node greatGrandChild = new Node("Urenkelkind von 1");
grandChild.addChild(greatGrandChild);
System.out.println("Methode Kinder");
root.printChildren();
System.out.printf("Anzahl Kindern: %d\n", root.getChildCount());
System.out.println("Methode zeige naechste Generationen");
root.printNextGeneration();
}
private String getData() {
return this.data;
}
private Node[] getChildren() {
return this.children;
}
private int getChildCount() {
return children.length;
}
private void setParent(Node parent) {
this.parent = parent;
}
private Node getParent() {
return parent;
}
private int getAncestorCount() {
Node parent = getParent();
int ancestorCount = 0;
while (parent != null) {
ancestorCount++;
parent = parent.getParent();
}
return ancestorCount;
}
private static Node[] copyArrayWithOneExtra(Node[] children) {
Node[] newChildren = new Node[children.length + 1];
System.arraycopy(children, 0, newChildren, 0, children.length);
return newChildren;
}
}
Lustig, dass Du Java wählst. SAP kann ja inzwischen auch Java. ABAP ist dann noch ein anderes Thema.
Gruß und viel Spaß
Vielen Dank für Ihre Bemühungen! Frohes Weihnachtsfest!
ich vermute, du beziehst dich auf deine zwei Print-Methoden.
Du veränderst die globale Variable des Objekts darin, wodurch du Knoten möglicherweise unwiederruflich löschst.
Zur Lösung des Problems kannst du lokale Variablen nutzen, die du verwendest, um durch die Knoten zu iterieren, statt die globale Variable zu verändern.
Also müsste man in den print Methoden eine neues Objekt erzeugen vom Typ Node und dann zuweisen (nodetwo=node) sowie nodetwo für die Iterierung verwenden?
Ja, soinetwa. Nur dass du kein neues Objekt erzeugst, sondern lediglich eine Variable, die auf dein Node-Objekt zeigt. Das kommt aber schlußendlich auf dasselbe raus.
Habe nun die Variable erzeugt folgendermaßen:
public void printchildren(Node node)
{
Node nodetwo=node;
int i=0;
while(nodetwo.children!=null) {
System.out.println(nodetwo.children.node.data);
nodetwo.children=nodetwo.children.next;
i++;
}
System.out.printf("Anzahl Kinder: %d\n",i);
}
Was ist mit der Variable in der Mainmethode muss dies auch geändert werden?
An sich nicht. Kommt halt darauf an, was du machen willst, das hat jetzt nichts mit den Print_Methoden zu tun.
Vielen Dank! Ja, die Anzahl der Kinder ist beliebig da muss ich dann einmal sehen wie ich das am besten mache.