Hallo,
ich soll in Java eine doppelt verkettete Liste erstellen und weiß nicht
recht wie.
Ich stelle mal den vorhandenen Code ein:
1
publicclassAufgabe10{
2
3
4
5
publicstaticvoidmain(String[]args)
6
7
{
8
9
//System.out.println("hello");
10
11
Natsetliste=newNatset();
12
13
14
15
16
17
}
18
19
20
21
22
23
}
24
25
26
27
publicclassMyNode{
28
29
30
31
privateintvalue;
32
33
privateMyNodenext;
34
35
privateMyNodeprevious;
36
37
38
39
40
41
publicMyNode()
42
43
{}
44
45
46
47
publicintgetValue()
48
49
{
50
51
returnvalue;
52
53
}
54
55
56
57
publicvoidsetValue(intm)
58
59
{
60
61
value=m;
62
63
}
64
65
66
67
publicMyNodegetNext()
68
69
{
70
71
returnnext;
72
73
}
74
75
76
77
publicMyNodegetPrevious()
78
79
{
80
81
returnprevious;
82
83
}
84
85
86
87
}
88
89
90
91
92
93
94
95
publicclassNatset{
96
97
98
99
privateMyNodestart;
100
101
privateintsize;
102
103
104
105
publicNatset(){}
106
107
108
109
publicintgetSize()
110
111
{
112
113
returnsize;
114
115
}
116
117
118
119
120
121
}
Ein Teil war bereits vorgegeben, und ich soll es "fertigstellen".
Ein bisschen was habe ich schon gemacht, aber es reicht nicht um
weiterzukommen.
Erstmal habe ich gedacht, ich erzeuge ein neues Objekt liste, das muss
ich ja.
Jetzt stellt sich mir die Frage, wie weiße ich start seinen Wert zu?
Erzeuge ich da einfach ein neues Objekt aus MyNode? Und wie erzeuge ich
dann neue Listeneinträge? Ich muss von einem Vorhandenen Listeneintrag
auf den neuen Zeigen. In C habe ich das schon erfolgreich mit Pointern
Programmiert, aber diese Objektorientierung macht mir ziemlich zu
schaffen.
Wäre nett wenn mir jemand einen kleinen Hinweiß geben könnte, damit ich
weiter dran arbeiten kann.
Danke schonmal
Das Objekt, welches ein Element der Liste repräsentieren soll, benötigt
zusätzlich noch eine Referenz auf seinen Vorgänger und seinen
Nachfolger.
In dem Objekt, welches die Liste als Ganzes darstellen soll, nimmt man
sinnigerweise eine Referenz auf das erste und letzte Element mit auf.
Nennen wir sie mal 'Kopf' und 'Arsch'. Zunächst ist Kopf=Arsch=null und
die Liste damit leer. Bist du so weit?
java schrieb:> Jetzt stellt sich mir die Frage, wie weiße ich start seinen Wert zu?
einfach ein neues MyNode Objekt mit new erzeugen und zuweisen
> Erzeuge ich da einfach ein neues Objekt aus MyNode? Und wie erzeuge ich> dann neue Listeneinträge?
vorhandenerKnoten.next = new MyNode
> auf den neuen Zeigen. In C habe ich das schon erfolgreich mit Pointern> Programmiert,
na dann.
Funktioniert doch in Java auch nicht anders, nur dass es keine Pointer
Syntax gibt und du Pointer zuweist, in dem du stattdessen die Objekte
rumreichst und Java unter der Hand nur Pointer umkopiert.
> aber diese Objektorientierung macht mir ziemlich zu> schaffen.
Das heist in deinem Fall nichts anderes als das eine Funktion "anhängen"
nichts anderes als eine Funktion des Objektes ist und nicht einfach eine
freistehende Funktion. Aber mehr ist das nicht.
Einfach 'Beamtendenken" einsetzen: Wer ist dafür zuständig, dass eine
Operation gemacht wird.
Nicht die Liste ist in letzter Konsequenz dafür zuständig, dass an das
Ende der List ein neuer Knoten angehängt wird und macht sich die Finger
schmutzig. Die Liste identifiziert wer der letzte Knoten ist und
beauftragt dann diesen Knoten den neuen Knoten an sich drann zu hängen.
Das ist sein Job, da soll sich mal der Knoten die Finger damit schmutzig
machen.
Soweit bin ich, dass die Liste leer ist.
Jetzt ist eher meine Frage, wie bekomme ich ein neues Objekt da hinein.
Und wie greife ich darauf zu, über start? Wie soll das gehen, ich steh
ziemlich auf dem Schlauch
java schrieb:> Soweit bin ich, dass die Liste leer ist.>>> Jetzt ist eher meine Frage, wie bekomme ich ein neues Objekt da hinein.
indem du es erzeugst.
die Liste hat eine Referenz, die nennt sich start
also wird der erste Knoten erzeugt mittels
start = new MyNode;
ferig.
> Und wie greife ich darauf zu, über start?
ja.
> Wie soll das gehen,
Indem du einfach das Objekt (über seine Referenz) benutzt
start.getValue();
> ich steh> ziemlich auf dem Schlauch
du denkst viel zu komplizert.
Nun ja, dein Objekt 'Liste' könnte doch unter Umständen eine Methode a
la 'addToHead(Node N)' besitzen. Von außen dann etwa so aufzurufen:
myList = new List();
myList.addToHead(new ListItem());
Klemmts im Detail oder in der Übersicht?
Hi,
in der Übersicht klemmt es, das was Karl Heinz gesagt hat bringt mich
schon weiter, ich habe echt zu kompliziert gedacht.
und wenn ich jetzt den nächsten eintrag machen will, mache ich dann
start.next = new MyNode(); oder?
Danke
java schrieb:> und wenn ich jetzt den nächsten eintrag machen will, mache ich dann> start.next = new MyNode(); oder?
Nein... Du benötigst eine append/prepend Funktion da auf private
Elemente nicht jeder zugreifen kann bzw. soll!
Überleg dir doch erst ohne Java prinzipiell wie es ablaufen soll. Und
in der Aufgabe steht bestimmt auch drinn welche Operationen zu
implementieren sind...
java schrieb:> Hi,>> in der Übersicht klemmt es, das was Karl Heinz gesagt hat bringt mich> schon weiter, ich habe echt zu kompliziert gedacht.>> und wenn ich jetzt den nächsten eintrag machen will, mache ich dann> start.next = new MyNode(); oder?
IM Prinzip ja.
Aber du machst es nicht so. Du machst es objektorientiert.
Du gibst dem Knoten start den Auftrag einen neuen Knoten an sich hinten
drann zu hängen. Denn der Liste ist das schnurzegel, wie das genau geht.
Das geht die Liste nichts an sondern das ist das Bier vom Knoten
start.append( new MyNode() );
und die append Methode der Klasse MyNode (weil start ja eine Referenz
auf ein MyNode Objekt ist) macht dann erst den Klimbim mit den
'Pointern'.
Eines noch.
Du machst natürlich nicht
start.append( new MyNode() );
Die Liste soll sich den neuen Knoten nicht selbst erzeugen, sondern den
kriegt sie wiederrum von main. Dort wird der Knoten erzeugt und an eine
append Methode der Liste weitergegeben, die ihn an die Liste anhängt,
indem sie den letzten Knoten der Liste beauftragt, den Knoten
anzuhängen. Natürlich nur wenn es schon einen letzten Knoten gab. Wenn
nicht, dann ist der übergebene Knoten der neue letzte Knoten (und auch
erster Knoten klarerweise, denn die Liste muss dann leer gewesen sein,
wenn es keinen letzten Knoten gab)
1
publicclassNatset{
2
3
privateMyNodefirst;
4
privtaeMyNodelast;
5
6
publicvoidappend(MyNodenewNode)
7
{
8
if(this.last==null)
9
this.first=newNode;
10
else
11
this.last.append(newNode);
12
13
this.last=newNode;
14
}
15
}
und den Member Variable size schmeisst du am besten gleich wieder raus.
Wenn jemand wissen will, wieviele Elemente in der List sind, dann zählst
du die Knoten.
Also ich habs mal selber nochmal versucht und habe es zwar "geschafft"
aber ich habe hier glaube ich zwei Variablen, die ich mir irgendwie
schenken könnte, ich weiß nur noch nicht wie. Ich lasse im Moment Natset
die Listenverwaltung machen, was ich für sinnvoll halte:
Hier mal der derzeitige Code:
1
publicclassAufgabe10{
2
3
publicstaticvoidmain(String[]args)
4
{
5
//System.out.println("hello");
6
7
//Neue Liste erzeugen
8
Natsetliste=newNatset();
9
10
//Startpunkt erstellen
11
liste.setStart();
12
13
//Listenelemente hinzufügen
14
liste.append(1);
15
liste.append(2);
16
liste.append(3);
17
liste.append(4);
18
liste.append(5);
19
20
//in Liste auf und abgehen und Elemente ausgeben
21
System.out.println(liste.nextItem());
22
System.out.println(liste.nextItem());
23
System.out.println(liste.nextItem());
24
System.out.println(liste.nextItem());
25
System.out.println(liste.nextItem());
26
System.out.println(liste.nextItem());
27
28
System.out.println(liste.previousItem());
29
30
31
32
}
33
34
35
36
37
38
39
}
40
41
42
publicclassNatset{
43
44
privateMyNodestart;
45
privateMyNodelast;
46
privateMyNodeaddress;
47
privateMyNodebuffer;
48
privateintsize;
49
50
publicNatset(){}
51
52
publicvoidsetStart()
53
{
54
//Start festlegen
55
start=newMyNode();
56
last=start;
57
address=start;
58
}
59
60
publicvoidappend(inta)
61
{
62
//next auf neu erzeugtes Element zeigen lassen
63
last.setNext(newMyNode());
64
//Reverenz auf altes Element speichern
65
buffer=last;
66
//letzer Wert
67
last=last.getNext();
68
//Reverenzen und Werte setzen
69
last.setNext(null);
70
last.setPrevious(buffer);
71
last.setValue(a);
72
size++;
73
}
74
75
publicintnextItem()
76
{
77
//Wenn es ein nächstes Element gibt
78
if(address.getNext()!=null)
79
{
80
//Ein Element weiter springen
81
address=address.getNext();
82
returnaddress.getValue();
83
}
84
else
85
{
86
return0;
87
}
88
89
}
90
91
publicintpreviousItem()
92
{
93
if(address.getPrevious()!=null)
94
{
95
//Ein Element zurückspringen
96
address=address.getPrevious();
97
returnaddress.getValue();
98
}
99
else
100
{
101
return0;
102
}
103
104
}
105
106
107
108
publicintgetSize()
109
{
110
returnsize;
111
}
112
113
}
114
115
publicclassMyNode{
116
117
privateintvalue;
118
privateMyNodenext;
119
privateMyNodeprevious;
120
121
122
publicMyNode()
123
{}
124
125
126
publicintgetValue()
127
{
128
returnvalue;
129
}
130
131
publicvoidsetValue(intm)
132
{
133
value=m;
134
}
135
136
publicMyNodegetNext()
137
{
138
returnnext;
139
}
140
141
publicMyNodegetPrevious()
142
{
143
returnprevious;
144
}
145
publicvoidsetNext(MyNoden)
146
{
147
next=n;
148
}
149
150
publicvoidsetPrevious(MyNodep)
151
{
152
previous=p;
153
}
154
155
156
}
Wäre nett wenn nochmal jemand drüber schauen würde und mir noch ein paar
Tipps gibt.
Danke euch soweit schonmal :)
Also, eine doppeltverkettete Liste sollte man aufm Papier aufmalen und
in irgendeiner Sprache hinschreiben koennen. Im Schlaf. Das ist Teil des
Eintrittstickets in den Beruf. Zum Glueck gibt's Debugger, da kann man
Singlesteppen bis die Ohren wackeln. Sinnvoll zur Liste ist auch noch
eine Membervariable 'count' die die Anzahl Elemente zaehlt.
Mach mal.
Sorry, dass ich sowas erst jetzt in meinem Studium versuche lerne, aber
woher soll ich sowas können? Ich versuche mich gerade darin und verstehe
deinen Kommentar nicht. Wenn du es kannst, dann hilf mir dabei.
Außerdem zähle ich die Anzahl der Elemente.
Also. Mach's mal auf dem Papier. Welche Pointer muessen wohin zeigen.
Und werden in welcher Reihenfolge wohin verschoben ?
Die Liste hat die Membervariablen : Erster & Letzter und beide zeigen
auf Knoten.
Die Knoten haben die Membervariablen : Vorheriger & Naechster, und
zeigen auf Knoten.
Mal das mal auf Papier.
Wie wird der erste, zweite & N-te Knoten angefuegt ?
Wie wird der n-te, zweitletzte & letzte Knoten geloescht ?
Mal das mal auf.
Das habe ich bereits aufgemalt, aber hast du eigentlich meinen Code
gelesen?
Er funktioniert schon, nur frage ich mich, ob es ohne die Variablen
Buffer und address geht.
Danke
java schrieb:> Das habe ich bereits aufgemalt, aber hast du eigentlich meinen Code> gelesen?> Er funktioniert schon, nur frage ich mich, ob es ohne die Variablen> Buffer und address geht.
natürlich
kein Mensch sagt, dass alle Variablen Member einer Klasse sein müssen.
Man kann wie in jeder Programmiersprache, auch in Java funktionslokale
Variablen anlegen
Aber Milli hat schon recht: Zum Einfügen braucht man die eigentlich
nicht. Mal dir auf dem Papier 2 Knoten auf, die korrekt verpointert
sind. Jetzt kommt ein 3.ter Knoten dazu und wird angehängt. In welcher
Reihenfolge musst du welchen Pointer wohin zeigen lassen, damit sich das
alles ausgeht und du keinen Hilfspointer brauchst? Da muss man dann eben
ein wenig rumprobieren.
Soweit zu "buffer"
Deine "address", bzw. die Funktionen nextItem und previousItem, sind
genau in der Art gemacht, wie man es nicht macht. Aber keine Angst, du
bist da in guter Gesellschaft. Ich hab auch schon erfahrene
Programmierer gesehen, die es genau so gemacht haben und das Kopfkratzen
war dann groß wie man wohl gleichzeitig unabhängig voneinander 2
Iterationen durch die Liste macht.
Teil des Problems ist es, dass du die Warnung objektorientiert zu
programmierern über Bord geschmissen hast. Es ist nicht Aufgabe der
LIste den Nachfolger eines Knotens festzustellen, sondern das macht der
Knoten gefälligst selber. Deine address Variable muss da raus. Der
Verwender der Liste muss das selber verwalten. d.h. er befragt die
Liste: welches ist dein erster Knoten? Und dann befragt er den Knoten
selber: Welches ist dein Nachfolger. SOlange, bis ein Knoten kommt, der
von sich sagt: Ich hab keinen Nachfolger mehr.
Der Verwender in main befragt also nicht die Liste mittels "Ich brauche
den Nachfolger", sondern er befragt die Liste mittels "Ich brauche den
Nachfolger VON"
java schrieb:> @Karl Heinz,>> mit dem was du mir gepostet hast bin ich übrigends auf keinen grünen> Zweig gekommen, ich habe es nicht so recht verstanden.
Was genau hast du daran nicht verstanden?
Du willst das alles so benutzen können (in main())
1
Natsetliste=newNatset();
2
3
//Listenelemente hinzufügen
4
liste.append(newMyNode(1));
5
liste.append(newMyNode(2));
6
liste.append(newMyNode(3));
7
liste.append(newMyNode(4));
8
liste.append(newMyNode(5));
9
10
MyNodeloop=liste.first();
11
while(loop!=null){
12
System.out.println(loop);
13
loop=liste.next(loop);
14
}
Ich denke, du hast schon mal eine Liste geschrieben? Dann musst du doch
wissen, wie man sowas benutzt.
Karl Heinz Buchegger schrieb:> Deine address Variable muss da raus. Der> Verwender der Liste muss das selber verwalten. d.h. er befragt die> Liste: welches ist dein erster Knoten? Und dann befragt er den Knoten> selber: Welches ist dein Nachfolger. SOlange, bis ein Knoten kommt, der> von sich sagt: Ich hab keinen Nachfolger mehr.
Ich sag jetz mal "jein" ;)
Dafür wurde in Java die Collection API erfunden insbesondere der
Iterator/Enumeration.
http://download.oracle.com/javase/6/docs/api/java/util/Enumeration.html
Eine solche Liste sollte also idealerweise eine Methode:
1
Iterator<MyNode>getIterator()
2
Iterator<MyNode>getReverseIterator()
Soviel erstmal zur allgemeinen Verwirrung ;)
Karl Heinz Buchegger schrieb:> Ich denke, du hast schon mal eine Liste geschrieben? Dann musst du doch> wissen, wie man sowas benutzt.
Deshalb hab ich ja vorher gefragt welche Operationen den implementiert
werden sollen...
> public int nextItem()> public int previousItem()
weshalb int ? Da moechte man den pointer auf den Knoten bekommen.
Das Item zieht man aus dem knoten selbst. Nur dan kann man in einem Loop
weitermachen.
> public void append(int a)> public void setStart()
weshalb void ? Da moechte man den pointer auf den Knoten bekommen.
Also jetzt habe ich es komplett ohne Hilfsvariablen gemacht.
Jeder Knoten gibt seinen nächsten zurück.
Und jeder Knoten erzeugt seinen Nachfolger, wobei nur der letzte Knoten
einen erzeugen sollte. Der Startknoten könnte das zwar auch, ist aber
nicht gerade sinnvoll.
Soviel erstmal zur
> allgemeinen Verwirrung ;)
Ich wollte ihn nicht auch noch mit Iteratoren verwirren. Klar sind
Iteratoren die bessere Lösung.
> Der Startknoten könnte das zwar auch, ist aber nicht gerade sinnvoll.
Ich kann der Idee noch nichts abgewinnen, dass eine leere Liste aus
einem sonst nicht weiter benutzten Startknoten besteht nicht. Aber ok,
damit kann man leben und manche Dinge werden dann tatsächlich einfacher.
Viel lästiger finde ich allerdings, wenn ich explizit setStart aufrufen
muss. Wozu soll das gut sein? Ohne kann ich die Liste sowieso nicht
verwenden, also kann auch gleich der Konstruktor die Liste so
herrichten, dass ich keinen Fehler (setStart aufrufen vergessen) machen
kann. Deswegen gibt es Konstruktoren, die ein Objekt erst mal in einen
benutzbaren Zustand bringen, damit sich ein Verwender nicht mit
'Kleinigkeiten', wie dem Aufrufen von Initialisierungsfunktionen,
beschäftigen müssen. Der Unterschied: Der Konstruktur wird IMMER
aufgerufen, wenn ein Objekt erzeugt wird, das kann ich als Verwender
daher nicht vergessen. setStart ist daher so nicht notwendig, was
allerdings nicht heißt, das sie sinnlos wäre. Aber in einem anderen
Zusammenhang. Durch die Garbage Collection von Java übernimmt dein
'setStart' die Funktionalität: lösche die komplette Liste. Also nenne
die Funktion auch entsprechend und sorge dafür, dass clear immer
aufgerufen werden kann und das richtige vollständig macht.
Soweit mal Danke,
ich habe die Methode addElement() mal geändert:
1
publicvoidaddElement(inta){
2
if(size==0){
3
start=newMyNode();
4
last=start;
5
start.setValue(a);
6
}else{
7
last=last.append(a);
8
}
9
size++;
10
}
Jetzt gibt es nur dann einen Knoten, wenn wirklich ein Element
hinzugefügt wird.
Und den Konstruktor hätte ich vorher tatsächlich verwenden können, aber
ich bin noch nicht so fit mit Java, aber danke für den Hinweis.