Autor Beitrag
Talemantros
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 09:57 
Guten Morgen,
nachdem ich in einem anderen Forum mit meiner Frage gescheitert bin, erhoffe ich mir hier Hilfe.
Ich bin ganz neu hier im Forum und auch ganz neu in der C# Welt und hoffe ich halte jetzt alle gängigen Regeln ein. Sollte ich das falsche Unterforum gewählt haben bitte ich einen Mod dieses zu verschieben. Ein reines Anfängerforum oder ähnliches habe ich nicht gefunden.

Zur Zeit versuche ich mir C# ganz neu beizubringen.
Ich habe eine Einfach verkettete Liste erstellt, die in einer Konsolenanwendung am Ende die Daten ausgibt.

Nun würde ich gern diese schon bestehende Liste in eine Doppelt verkettete Liste packen um sie auch rückwärts ausgeben lassen zu können.
Ich habe mittlerweile dafür auch einen Ansatz gefunden und würde gern hier fragen, ob dies richtig ist damit ich es von Anfang an richtig lerne.

Hier der Code meiner Einfach verketteten Liste
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
 {
     class Program
     {
         //Die Klasse für die Listenelemente
         //jetzt auch mit Methoden
         class Listenelement
         {
             string daten;
             Listenelement naechster;

             //Die Methode zum Setzen der Daten
             public void SetDaten(string datenNeu)
             {
                 //die Zeichenketten setzen
                 daten = datenNeu;
                 //das Ende markieren
                 naechster = null;
             }

             //die Methode zum Anhängen eines neuen Elements
             //Die Methode ruft sich rekursiv auf, bis das Ende erreicht ist
             public void Anhaengen(string datenNeu)
             {
                 //wenn das Ende erreicht ist, ein neues Element erzeugen
                 //ansonsten ruft es sich wieder selber auf
                 if (naechster == null)
                 {
                     naechster = new Listenelement();
                     naechster.SetDaten(datenNeu);
                 }
                 else
                 {
                     naechster.Anhaengen(datenNeu);
                 }
             }

             //die Methode zur Ausgabe der Liste
             //sie ruft sich ebefalls rekursiv auf, bis das Ende erreicht ist
             public void Ausgeben()
             {
                 Console.WriteLine(daten);
                 if (naechster != null)
                     naechster.Ausgeben();
             }
         }

         static void Main(string[] args)
         {
             //ein neues Listenelement erzeugen
             Listenelement listenAnfang = new Listenelement();

             //die Daten im ersten Listenelement setzen
             listenAnfang.SetDaten("Element 1");

             //weitere Elemente in einer Schleife anfügen
             for (int element = 2; element <= 10; element++)
             {
                 listenAnfang.Anhaengen("Element " + element);
             }

             //Ausgeben
             listenAnfang.Ausgeben();
         }
     }
 }


Um hier raus eine doppelte verkette Liste zu erstellen habe ich einen Zeiger auf das vorherige Element generiert und diesen über This in der Methode "anhaengen" übergeben.

Wenn ich mir das auf der Console ausgeben lasse, scheint die Referenz auch gesetzt zu sein. Weiterhin habe ich die Methode "SetDatenFirst" gemacht, damit beim ersten setzen der Zeiger auf "null" bleibt um das Ende/Anfang zu definieren.

Hier der veränderte Code
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
{
    class Program
    {
        //Die Klasse für die Listenelemente
        //jetzt auch mit Methoden
        class Listenelement
        {
            string daten;
            Listenelement naechster;
            Listenelement vorige;
            Listenelement hilfsKonstrukt;
            
            //Die Methode zum Setzen der Daten beim ersten Aufruf
            public void SetDatenFirst(string datenNeu)
            {
                //die Zeichenketten setzen
                daten = datenNeu;
                //das Ende markieren
                naechster = null;
            }

            //Die Methode zum Setzen der Daten ab dem 2ten Aufruf
            public void SetDaten(string datenNeu, Listenelement Ref)
            {
                //Die Referenz auf den vorherigen setzen
                vorige = Ref;
                //die Zeichenketten setzen
                daten = datenNeu;
                //das Ende markieren
                naechster = null;
            }

            //die Methode zum Anhängen eines neuen Elements
            //Die Methode ruft sich rekursiv auf, bis das Ende erreicht ist
            public void Anhaengen(string datenNeu)
            {
                //wenn das Ende erreicht ist, ein neues Element erzeugen
                //ansonsten ruft es sich wieder selber auf
                if (naechster == null)
                {
                    hilfsKonstrukt = this;
                    naechster = new Listenelement();
                    naechster.SetDaten(datenNeu, hilfsKonstrukt);
                }
                else
                {
                    naechster.Anhaengen(datenNeu);
                }
            }

            //die Methode zur Ausgabe der Liste
            //sie ruft sich ebefalls rekursiv auf, bis das Ende erreicht ist
            public void Ausgeben()
            {
                Console.WriteLine(daten);
                if (naechster != null)
                    naechster.Ausgeben();
            }

            //die Methode zur Ausgabe der Liste rückwärts
            //sie ruft sich ebefalls rekursiv auf, bis der Anfang erreicht ist
            public void AusgebenRueckwaerts()
            {
                Console.WriteLine(daten);
                if (vorige != null)
                    vorige.Ausgeben();
            }
        }

        static void Main(string[] args)
        {
            //ein neues Listenelement erzeugen
            Listenelement listenAnfang = new Listenelement();

            //die Daten im ersten Listenelement setzen
            listenAnfang.SetDatenFirst("Element 1");

            //weitere Elemente in einer Schleife anfügen
            for (int element = 2; element <= 10; element++)
            {
                listenAnfang.Anhaengen("Element " + element);
            }


            //Ausgeben
            listenAnfang.Ausgeben();           
        }
    }
}


Was ich nun leider nicht in meinen Kopf bekomme!
Wenn ich das Ganze rückwärts ausgeben lassen möchte benötige ich ein "listenEnde" mit der letzten Referenz.
Wie generiere ich dieses, um am Ende sagen zu können in Main "listenEnde.ausgebenRueckwaerts()"

Wenn ich in Main "Listenelement listenEnde = new Listenelement()" generiere kann ich dies in der Klasse nicht auf die letzte Referenz setzen.

Ich wäre über eine Lösung oder Denkansatz um es einmal zu verstehen sehr glücklich.

Vielen Dank

Gruß
Daniel

Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 10:45 
Zitat:
Wie generiere ich dieses, um am Ende sagen zu können in Main "listenEnde.ausgebenRueckwaerts()"


Zum Beispiel in dem du dem Listenelement ein Funktion/Property gibst die dir quasi rekursiv immer das nächste Element liefert solange es ein nächstes Eleement gibt oder sich selbst.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public Listenelement LastElement
{
   get 
   {
       if (naechster == null)
          return this;
       else
          return naechster.LastElement;
   }
}


Dann geht ein listenAnfang.LastElement.AusgebenRueckwaerts();
Über deine AusgebenRueckwaerts Methode solltest du aber nochmal scharf nachdenken. Die wird so nicht funktionieren.

Wenn das für dich Funktioniert solltest du dir auch über die Sichtbarkeiten (private,public etc.) der benutzten Konstrukte Gedanken machen. Was nutzt es wenn du veröffentlichte Methoden hast um die Klasse zu ändern aber jeder kann auch auf die enthaltenen Felder direkt zugreifen an den Methoden vorbei.
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 11:40 
Hallo Ralf,
erst mal vielen vielen Dank für deine Antwort.
Freut mich sehr, dass ich überhaupt Hilfe bekomme um mich weiter zu bilden.

Ich habe da noch 2-3 Fragen.

Ich habe nun die Felder der Klasse als private deklariert, damit von außen keiner dran kommt. Ich dachte, wenn man es nicht ausdrücklich public macht, wäre es private.

Des weiteren habe ich meinen Fehler in der AusgebenRueckwaerts gefunden :-) ! Blödes Copy & Paste! so dass diese auch funktioniert.

Wenn ich deinen Quellcode einfüge läuft jetzt alles. Leider verstehe ich es noch nicht ganz da ich mit dem GET noch nicht gearbeitet habe.

Könnte man das ganze auch ohne das Get bauen, ich glaube das kommt hier in dem Lernfeld erst später dran.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
public Listenelement LastElement()
{
       if (naechster == null)
          return this;
       else
          naechster.LastElement();
}

Wenn sowas in der Art gehen würde, wie müsste ich diese dann aufrufen.
Vielen Dank. Habe endlich mal das Gefühl, dass sich im Kopf was tut :-)

lg
Daniel

Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 12:10 
Ja so geht das natürlich auch. Ist auch nicht schlechter oder so sondern nur anders;)
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 15:34 
Hallo nochmal,
also ich habe nun noch mal einiges umgebaut, da ich gesehen habe, dass die Hilfskonstruktion überflüssig war.
Ich versuche nun in der Methode "anhaengen" die Referenz auf naechster.vorige = this zu setzen und dort auch listenEnde = naechtser um das Ende der Liste zu markieren.

Im Moment ist mir noch unklar wie ich nun aus MAIN heraus die Rückwärtsausgabe der Liste vom listenEnde an beginnend ausgeben kann.

Wenn ich nur in der Methode der Klasse aus "Daten" "listenEnde.daten" mache passiert nicht das richtige.

Hat nochmal jemand einen Rat für mich?

Mein aktueller Code:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
{
    class Program
    {
        //Die Klasse für die Listenelemente
        //jetzt auch mit Methoden
        class Listenelement
        {
            private string daten;
            private Listenelement naechster;
            private Listenelement vorige;
            private Listenelement listenEnde;
            
            //Die Methode zum Setzen der Daten beim ersten Aufruf
            public void SetDaten(string datenNeu)
            {
                //die Zeichenketten setzen
                daten = datenNeu;
                //das Ende markieren
                naechster = null;
            }

            //die Methode zum Anhängen eines neuen Elements
            //Die Methode ruft sich rekursiv auf, bis das Ende erreicht ist
            public void Anhaengen(string datenNeu)
            {
                //wenn das Ende erreicht ist, ein neues Element erzeugen
                //ansonsten ruft es sich wieder selber auf
                if (naechster == null)
                {
                    naechster = new Listenelement();
                    naechster.vorige = this;
                    listenEnde = naechster;
                    naechster.SetDaten(datenNeu);
                }
                else
                {
                    naechster.Anhaengen(datenNeu);
                }
            }

            //die Methode zur Ausgabe der Liste
            //sie ruft sich ebefalls rekursiv auf, bis das Ende erreicht ist
            public void Ausgeben()
            {
                Console.WriteLine(daten);
                if (naechster != null)
                    naechster.Ausgeben();
            }

            //die Methode zur Ausgabe der Liste rückwärts
            //sie ruft sich ebefalls rekursiv auf, bis der Anfang erreicht ist
            public void AusgebenRueckwaerts()
            {
                Console.WriteLine(daten);
                if (vorige != null)
                    vorige.AusgebenRueckwaerts();
            }
        }

        static void Main(string[] args)
        {
            //ein neues Listenelement erzeugen
            Listenelement listenAnfang = new Listenelement();

            //die Daten im ersten Listenelement setzen
            listenAnfang.SetDaten("Element 1");

            //weitere Elemente in einer Schleife anfügen
            for (int element = 2; element <= 10; element++)
            {
                listenAnfang.Anhaengen("Element " + element);
            }

            //Ausgeben
            listenAnfang.Ausgeben();            
        }
    }
}


Danke

lg
Daniel

Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 16:13 
Veröffentliche listenEnde so das du dran kommst (Du erinnerst dich an Properties? ;) ). Und rufe dann daran deine AusgebenRueckwaerts Methode auf.

Edit: Ok ich sprechs doch an. Sich listenEnde zu merken mag erstmal charmant aussehen ist aber nicht wirklich hilfreich. Wenn du nicht nur an anhängen an die Liste denkst sondern vieleicht auch an Operationen wie Elemente entfernen, Listen teilen, Listen zusammenführen etc. wird es hakelig weil du dann anfängst in allen/vielen Listenelementen das listenEnde zu korrigieren. Verkette Listen sind ja gerade für Anwendungsfälle gedacht wo es reicht das man seine direkten Nachbarn kennt. Da zu optimieren und sich bestimmte Elemente so zu merken schafft mehr Probleme als es löst. Sich bis zum Ende der Liste durchhangeln zu müssen dauert vielleicht länger als der direkte Sprung über die Variable ist aber deutlich stabiler wenn du weitere Funktionalität der verketteten Liste hinzufügst. Wenn es um die Performance geht bestimmte Elemente schnell zu finden wäre ja auch die Wahl verkettete Liste schon falsch und man würde einen anderen Konstrukt wählen. Wenn du doch die listenEnde Variable verwenden möchtest solltest du die auch überall verwenden. Deine Anhaengen Methode zum Beispiel hangelt sich immer noch zum Listenende durch anstatt einfach zu listenEnde zu springen ;)
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 16:35 
Hi,
Also ich habe nun aus "Listenelement listenEnde" ein "public Listenelement listenEnde" gemacht um von außen an diesen Wert zu kommen.

Danach habe ich über die Instanz und das Feld verscuht sie Methode aufzurufen.
"listenanfang.listenEnde.ausgebenRueckwaerts();

Er wirft zwar keinen Fehler aus, aber zeigt nicht die richtigen Daten an.

Ergebnis bei ihm ist

Element 1
Element 2 ... 10 und dann statt rückwärts steht da nur 2 und 1 statt von 10 zu zählen

Danke

Ich hoffe demnächst wenn der Knick aus dem Kopf einmal weg ist wird es "leichter"

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
{
    class Program
    {
        //Die Klasse für die Listenelemente
        //jetzt auch mit Methoden
        class Listenelement
        {
            private string daten;
            private Listenelement naechster;
            private Listenelement vorige;
            public Listenelement listenEnde;
            
            //Die Methode zum Setzen der Daten beim ersten Aufruf
            public void SetDaten(string datenNeu)
            {
                //die Zeichenketten setzen
                daten = datenNeu;
                //das Ende markieren
                naechster = null;
            }

            //die Methode zum Anhängen eines neuen Elements
            //Die Methode ruft sich rekursiv auf, bis das Ende erreicht ist
            public void Anhaengen(string datenNeu)
            {
                //wenn das Ende erreicht ist, ein neues Element erzeugen
                //ansonsten ruft es sich wieder selber auf
                if (naechster == null)
                {
                    naechster = new Listenelement();
                    naechster.vorige = this;
                    listenEnde = naechster;
                    naechster.SetDaten(datenNeu);
                }
                else
                {
                    naechster.Anhaengen(datenNeu);
                }
            }

            //die Methode zur Ausgabe der Liste
            //sie ruft sich ebefalls rekursiv auf, bis das Ende erreicht ist
            public void Ausgeben()
            {
                Console.WriteLine(daten);
                if (naechster != null)
                    naechster.Ausgeben();
            }

            //die Methode zur Ausgabe der Liste rückwärts
            //sie ruft sich ebefalls rekursiv auf, bis der Anfang erreicht ist
            public void AusgebenRueckwaerts()
            {
                Console.WriteLine(daten);
                if (vorige != null)
                    vorige.AusgebenRueckwaerts();
            }
        }

        static void Main(string[] args)
        {
            //ein neues Listenelement erzeugen
            Listenelement listenAnfang = new Listenelement();

            //die Daten im ersten Listenelement setzen
            listenAnfang.SetDaten("Element 1");

            //weitere Elemente in einer Schleife anfügen
            for (int element = 2; element <= 10; element++)
            {
                listenAnfang.Anhaengen("Element " + element);
            }

            //Ausgeben
            listenAnfang.Ausgeben();
            listenAnfang.listenEnde.AusgebenRueckwaerts();
        }
    }
}


Danke

lg
Daniel

Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 16:42 
Weil dein Anhaengen nicht funktioniert/nicht funktionieren kann ;)

Wenn du dem ersten Element ein zweites anhängst zeigt das 1.te Element auf das 2.te. Soweit ok. Wenn du dem 2.ten ein 3.tes anhängst zeigt das 2.te auf das 3.te. Immer noch ok. Aber dein erstes Element zeigt natürlich weiterhin auf das 2.te. Das 2.te ist dann aber nicht mehr das letzte Element;) Im Moment ist bei dir listenEnde immer das gleiche wie nächster, steht ja auch so in deiner Anhaengen MEthode drin ;) listenEnde = naechster;

Darum hatte ich meinen Beutrag nochmal ergänzt um zu erklären wie unglücklich dein Ansatz ist. Um das zu korrigieren müßtest du in der anhängen Methode durch alle Elemente rennen und alle listenEnde Felder passend nachziehen.
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Do 05.09.13 17:47 
Ich würde mir erstmal zwei Klassen definieren statt nur einer: Ein Listenelement und eine Liste. Und dann kann man doch innerhalb der Liste sehr wohl einen Verweis auf den Anfang und einen Verweis auf das Ende halten. Das sollte dann auch bei komplexeren Operationen machbar sein.

Ein Listenelement hätte dann quasi nur zwei Verweise (Nachbarn) und ein Feld für Daten.
Die Liste bekommt dann die ganzen Methoden wie Anhängen, Suche oder Löschen.


Zuletzt bearbeitet von jfheins am Do 05.09.13 18:27, insgesamt 1-mal bearbeitet
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 18:10 
Also ich raffe gerade eigentlich gar nichts mehr wenn ich ehrlich bin und fange an genervt zu sein :-(
Ich quäle mich damit seit 2 Tagen und auch wenn ich das nicht gern mache würde ich gern mal fragen wollen, ob mir jemand mal einen solchen code posten kann. Vielleicht raffe ich es dann eher.

Das einzige was ich noch weiß ist, dass ich das Listenende aus dem Element ermitteln soll, welches vor dem Anhängen eines neuen aktiv war.

Ich dachte ich hätte mit den vielen Hinweisen Fortschritte gemacht.
Fühlt sich aber gerade nicht so an :-(

Gruß
Daniel
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 05.09.13 19:30 
Hallo Talemantros,

lass die Variable listenEnde mal weg und benutze dann dafür die von dir vorher schon gepostete Methode LastElement(). Das Problem bei der Variablen ist, daß dann jedes Listenelement sein eigenes listenEnde hätte (und du dann - wie Ralf und jfheins schon geschrieben haben - diese dann bei jeder Änderung synchronisieren müßtest). Wenn dann darf es ja nur genau ein Listenende geben. Ich hoffe, jetzt ist der Knoten in deinem Kopf wieder ein wenig entwirrt ;-)
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 20:15 
Hi,
ich soll das Ende nicht durch eine Methode erreichen, sondern immer beim Einfügen eine Referenz dazu speichern.
Ich habe jetzt mal versucht mit meinem rudimentären Wissen den Ansatz von jfheins zu verfolgen stehe jetzt aber vor dem Problem, dass ich nicht genau weiß, wie ich aus der Klasse Listenelemet in die Klasse Pointer den Wert speichern könnte trotz public.

Weiterhin bekomme ich es auch nicht ausgelesen :-(
Vielleicht sollte ich C# lassen.

Hier der aktuelle Code für alle die noch Lust haben :-)

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
{
    class Program
    {
        public class Pointer
        {
            public Listenelement last;
        }

        public class Listenelement
        {
            private string daten;
            private Listenelement naechster;
            private Listenelement vorige;
            
            public void SetDaten(string datenNeu)
            {
                daten = datenNeu;
                naechster = null;
            }

            public void Anhaengen(string datenNeu)
            {
                if (naechster == null)
                {
                    naechster = new Listenelement();
                    naechster.vorige = this;
                    naechster.SetDaten(datenNeu);
                }
                else
                {
                    naechster.Anhaengen(datenNeu);
                }
            }

            public void Ausgeben()
            {
                Console.WriteLine(daten);
                if (naechster != null)
                    naechster.Ausgeben();
            }

            public void AusgebenRueckwaerts()
            {
                Console.WriteLine(daten);
                if (vorige != null)
                    vorige.AusgebenRueckwaerts();
            }
        }

        static void Main(string[] args)
        {
            Pointer MyList = new Pointer();
            Listenelement listenAnfang = new Listenelement();

            listenAnfang.SetDaten("Element 1");

            for (int element = 2; element <= 10; element++)
            {
                listenAnfang.Anhaengen("Element " + element);
            }

            listenAnfang.Ausgeben();
        }
    }
}


EDIT: Ich habe nun die Instanz der Klasse Pointer in der Klasse Listenelement erzeugt.
Somit kann ich in der Methode "anheangen" mit Mylist.last = naechtser.this die Referenz zuweisen (also vermute ich)

Aber Rückwärts ausgegeben bekomme ich es noch nicht :-(

Gruß
Daniel

P.S.: Danke, dass ihr eure Zeit für mich opfert!
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 20:29 
Dann aktualisiere bitte auch den gezeigten Code. Damit wir dich da abholen können wo du stehst. Dein Edit ist sehr missverständlich und je nachdem wie ich das verstehen sollte ist das vielleicht Unsinn ;)

Wenn alle Listenelement Instanzen die gleiche Pointer Instanz benutzen kann das funktionieren. Wenn jede ihre eigene hat bist du nicht weeiter als vorher.

PS. jfheins meinte was anderes. Heißt aber nicht das dein Weg nicht funktioniert.
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 20:33 
Zur Zeit stehe ich hier

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
{
    class Program
    {
        public class Pointer
        {
            public Listenelement last;
        }

        public class Listenelement
        {
            private string daten;
            private Listenelement naechster;
            private Listenelement vorige;

            Pointer MyList = new Pointer();
            
            public void SetDaten(string datenNeu)
            {
                daten = datenNeu;
                naechster = null;
            }

            public void Anhaengen(string datenNeu)
            {
                if (naechster == null)
                {
                    naechster = new Listenelement();
                    naechster.vorige = this;
                    MyList.last = this.naechster;
                    naechster.SetDaten(datenNeu);
                }
                else
                {
                    naechster.Anhaengen(datenNeu);
                }
            }

            public void Ausgeben()
            {
                Console.WriteLine(daten);
                if (naechster != null)
                    naechster.Ausgeben();
            }

            public void AusgebenRueckwaerts()
            {
                Console.WriteLine(daten);
                if (vorige != null)
                    vorige.AusgebenRueckwaerts();
            }
        }

        static void Main(string[] args)
        {
            Listenelement listenAnfang = new Listenelement();

            listenAnfang.SetDaten("Element 1");

            for (int element = 2; element <= 10; element++)
            {
                listenAnfang.Anhaengen("Element " + element);
            }

            listenAnfang.Ausgeben();
            
        }
    }
}


Irgendwie schon bitter wie schwer ich mich tue eine Liste rückwärts ausgeben zu lassen nur weil ich die Methode nicht nutzen kann :-(
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 20:44 
So hilft Pointer nicht. Da jedes Element wieder seine eigene Pointer Instanz hat. Du würdest also wieder genauso viele Listenende Variablen speichern wie vorher und hättest nur n Pointer Klassen dazwischen geschaltet die wieder alle angepasst werden müssen wenn sich das Listenende ändert. Also keinerlei Gewinn.

Hast du eventuell die genaue Aufgabenstellung? Dein Problem klingt wieder so wie das jemand der schon weiß wie das geht dich zu einem bestimmten Sprachfeature hinlenken will ohne es zu benennen. Ehrlich gesagt sieht man das häufiger und es funktioniert (fast) nie wenn man nicht selbst schon weiß wo es hingehen soll(aka weil man zum Beispiel nachguckt wie der Titel des nächsten Kapitels im Buch/Vorlesung/Kurs lautet)

Bevor wir dir irgendwas raten wäre es also besser den Wortlaut der Aufgabenstellung zu kennen um dich nicht am Thema (lerne Sprachfeature X) vorbeizulenken.
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 21:10 
Hi,
der Ausgangspunkt war eine "Einfach verkettete Liste"

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
{
    class Program
    {
        //Die Klasse für die Listenelemente
        //jetzt auch mit Methoden
        class Listenelement
        {
            string daten;
            Listenelement naechster;

            //Die Methode zum Setzen der Daten
            public void SetDaten(string datenNeu)
            {
                //die Zeichenketten setzen
                daten = datenNeu;
                //das Ende markieren
                naechster = null;
            }

            //die Methode zum Anhängen eines neuen Elements
            //Die Methode ruft sich rekursiv auf, bis das Ende erreicht ist
            public void Anhaengen(string datenNeu)
            {
                //wenn das Ende erreicht ist, ein neues Element erzeugen
                //ansonsten ruft es sich wieder selber auf
                if (naechster == null)
                {
                    naechster = new Listenelement();
                    naechster.SetDaten(datenNeu);
                }
                else
                {
                    naechster.Anhaengen(datenNeu);
                }
            }

            //die Methode zur Ausgabe der Liste
            //sie ruft sich ebefalls rekursiv auf, bis das Ende erreicht ist
            public void Ausgeben()
            {
                Console.WriteLine(daten);
                if (naechster != null)
                    naechster.Ausgeben();
            }
        }

        static void Main(string[] args)
        {
            //ein neues Listenelement erzeugen
            Listenelement listenAnfang = new Listenelement();
            
            //die Daten im ersten Listenelement setzen
            listenAnfang.SetDaten("Element 1");

            //weitere Elemente in einer Schleife anfügen
            for (int element = 2; element <= 10; element++)
            {
                listenAnfang.Anhaengen("Element " + element);
            }

            //Ausgeben
            listenAnfang.Ausgeben();

        }
    }
}


Im Heft selber steht:
Unsere Liste kann man immer nur von vorne nach hinten durchlaufen werden, da wir ja nur das Nachfolge-Element kennen, aber nicht das Vorgänger-Element. Um die Liste in beide Richtungen durchlaufen zu können, müssten Sie also noch dafür sorgen, dass auch der Vorgänger im aktuellen Element gespeichert werden kann. Solche Listen werden doppelt verkettete Listen genannt.
Weiterhin könnten Sie aber auch die rückwärts-Ausgabe durch eine Rekursion ausführen lassen, die am Ende der Liste beginnt.

Durch meine Unterhaltungen mit dem Fernlehrer, der nett und hilfsbereit ist, aber nicht viel zu sagen darf habe ich noch die Info:

"Auch das Listenende lässt sich sehr einfach aus dem Element ermitteln, das vor dem Anhängen eines neuen Elemets das aktuelle ist"

Für mich klingt dies nach einem speichern innerhalb der Methode "anhaengen" ohne die Liste nochmal zu durchlaufen.

Ich bin zwar noch innerhalb des Heftes in einem Lernprozess, aber dadurch, dass dies am Ende in abgewandelter Form in der Einsendeaufgabe dran kommt kann er wenig dazu erklären. Finde dies zwar ziemlich blöd, da ich eigentlich erwarten kann etwas erklärt zu bekomme, aber vielleicht ist damit mehr eigenlernerei erwartet als ich dachte. Keine Ahnung, ob meine Ansprüche da zu hoch sind.

Schade, dass ich das Zertifikat am Ende brauche. Aber das war definitv das letzte Mal. dann lieber selber über Bücher ist genauso effetkiv

Ich habe ja nun etliche Versuche unternommen. Leider ohne Erfolg.

lg
Daniel
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 21:30 
Zitat:
"Auch das Listenende lässt sich sehr einfach aus dem Element ermitteln, das vor dem Anhängen eines neuen Elemets das aktuelle ist"


Das stimmt nur wenn das aktuelle Element immer das letzte Element ist. Du hast aber eine Logik in deiner Main Methode verbaut die immer vom Listenstart ausgeht.
Du solltest dir also in deiner Main Methode wenn du anhängst einfach das gerade eingehängte Element merken. Nicht in Listenelement sondern genauso wie der Listenanfang in der Main Methode.

Um deinen jetzigen Code ungefähr beizubehalten und die vermutliche Aufgabe zu erfüllen würde ich folgendes vorschlagen.
a.) Entferne Pointer das hilft nicht.
b.) Lass die von der Anhaengen Methode das Erstellte neue Listenelement zurückgeben (was dann ja das letzte ist) und merke sie dir in einer Variablen deiner Main Methode.
c.) An diesem aktuellen (letzten) Element kannst du dann AusgebenRueckwaerts aufrufen.Sollte dann eigentlich ohne weitere Codeänderung funktionieren.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 05.09.13 21:47 
Hallo zusammen,

diese Aufgabe gab es schon mal hier im Forum: Probleme mit einer verketteten Liste. Und dort wurde es dann wohl auch genau so gelöst, wie Ralf es jetzt vorgeschlagen hat ;-)
Talemantros Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 444
Erhaltene Danke: 2

Win7 Proff 64bit
C# (VS2013)
BeitragVerfasst: Do 05.09.13 21:59 
Nicht nur das ich dachte ich bin zu blöd, jetzt weiß ich es auch, dass derjenige es gleich hat lösen können :-(

Ich bin nämlich immer noch nicht am Ziel

Ich habe den Pointer entfernt
Ich habe in Main eine neue Instanz erzeugt listenEnde
Habe die forschleife um diese Instanz erweitert und
in der Methode anhaengen von void auf listenelement umgebaut und return this.naechster als Referenz zurück geben wollen

Auch dies ergibt wieder was falschen.
Ich glaube ich habe von Anfang an so kompliziert gedacht, dass dies jetzt völlig quer ist.

Mein Stand
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Einfache_Liste_2
{
    class Program
    {
        public class Listenelement
        {
            private string daten;
            private Listenelement naechster;
            private Listenelement vorige;
                        
            public void SetDaten(string datenNeu)
            {
                daten = datenNeu;
                naechster = null;
            }

            public Listenelement Anhaengen(string datenNeu)
            {
                if (naechster == null)
                {
                    naechster = new Listenelement();
                    naechster.vorige = this;
                    naechster.SetDaten(datenNeu);
                }
                else
                {
                    naechster.Anhaengen(datenNeu);
                }
                return this.naechster;
            }

            public void Ausgeben()
            {
                Console.WriteLine(daten);
                if (naechster != null)
                    naechster.Ausgeben();
            }

            public void AusgebenRueckwaerts()
            {
                Console.WriteLine(daten);
                if (vorige != null)
                    vorige.AusgebenRueckwaerts();
            }
        }

        static void Main(string[] args)
        {
            Listenelement listenAnfang = new Listenelement();
            Listenelement listenEnde = new Listenelement();

            listenAnfang.SetDaten("Element 1");

            for (int element = 2; element <= 10; element++)
            {
                listenEnde = listenAnfang.Anhaengen("Element " + element);
            }

            listenAnfang.Ausgeben();
            listenEnde.AusgebenRueckwaerts();
            
        }
    }
}


Sorry, dass ich mich so schwer tue

EDIT:
Ich glaube zu verstehen warum das Ergebnis falsch ist.
Der rekursive Aufruf ist eine Art Stapelverarbeitung und am Ende überschreibt er return this.naechster mit der letzten gefüllten Referenz von dem 2ten Objekt.

Die Preisfrage :-) wie behebe ich das, falls ich überhaupt richtig liege
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 05.09.13 22:23 
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
else
{
    /*hier auch return*/ naechster.Anhaengen(datenNeu);
}
return this.naechster;


naechster.Anhaengen liefert dir ein naechstes das du aber im else Zweig ignorierst und ins Nirvana schickst. Die Methode liefert also immer this.naechster des Elements an dem du die Methode aufgerufen hast also den Nachfolger und nicht das letzte Element der Liste. Du mußt die Rückgabe des quasi rekursiven Anhaengen Methodenaufrufs auch zurückgeben.

@Th69 : Das Netz ist voll von diesem Code. Was so ein Drecksbeispiel doch für ein Eigenleben entwickelt kann. Das findet man so oft das der Unbedarfte fast glauben könnte es wäre das Standard vorgehen. Absolut deprimierend.

Edit:
Zitat:
EDIT:
Ich glaube zu verstehen warum das Ergebnis falsch ist.
Der rekursive Aufruf ist eine Art Stapelverarbeitung und am Ende überschreibt er return this.naechster mit der letzten gefüllten Referenz von dem 2ten Objekt.


Es wird nicht überschrieben aber du ignorierst halt die Rückgabe der Rekursion ( es ist keine richtige Rekursion du rufst ja die gleiche Methode eines anderen Objekts auf und nicht wirklich sich selbst). Du liegst nur fast richtig ;)