<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Diverse Operationen für eine Verkettete Liste]]></title><description><![CDATA[<p>Hi alle miteinander!<br />
Meine Frage ist folgende:<br />
Ich habe mir die Basis für eine einfach verkettete Liste erstellt (Liste, Kopfknoten, Knoten &amp; Endknoten), funktioniert auch alles (bisher nur einfügen &amp; anzeigen) und bisher auch ohne Templates. Nun möchte ich mir verschiedene Operationen hinzufügen, z.B. einen <code>operator[]</code> oder eine <code>find()</code> -Methode. Hier erstmal einige Ausschnitte:</p>
<pre><code class="language-cpp">class bNode
{
    public:
        virtual ~bNode() {}
        virtual bool insert(const Data&amp;) = 0;
        virtual void print() const = 0;
};

class Node : public bNode
{
    Data* _data;
    bNode* _next;

    public:
        Node(const Data&amp;, bNode*);

        Node(const Node&amp;);

        ~Node();

        const Node&amp; operator=(const Node&amp;);

        bool insert(const Data&amp;); //Inserts a new Element

        void print() const;
};
</code></pre>
<p>Data ist einfach eine Art Wrapper um einen einzelnen Integer. Wird noch durch Templates verallgemeinert. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /><br />
Der Startknoten delegiert nur die Aufgaben weiter und der Endknoten macht fast gar nichts. Jetzt hatte ich mir für die <code>find()</code> -Methode folgendes gedacht:</p>
<pre><code class="language-cpp">int Node::find(const Data&amp; dat, int counter) const
{
    if (dat.Value() == _data-&gt;Value())
        return counter;
    return _next-&gt;find(dat, ++counter);
}
</code></pre>
<p>...also das ich die ganze Liste durchgehe und direkt einen counter, der die momentane Stelle mitzählt durchreiche. Analog wäre das für alle anderen Arten von Operationen (Indexoperator, Sortierung, ...). Meine Frage jetzt: geht das noch besser? Ich finde es vom Style nicht so schön dort immer einen counter mitzugeben. Ich hätte gedacht, dass ich in jedem Knoten irgendwie seine Position speichere, aber dann müsste ich bspw. beim sortieren die ganze Liste durchgehen und nochmal alle Positionen neu setzen. Mir fehlt da grad ne Idee. Danke fürs lesen und ich würd mich über eure Antworten freuen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>PS: Wenn was unklar ist: fragen, ich wollte jetzt nicht mein ganzes Projekt hier reinkopieren...</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/306537/diverse-operationen-für-eine-verkettete-liste</link><generator>RSS for Node</generator><lastBuildDate>Fri, 07 Aug 2026 18:04:56 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/306537.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 31 Jul 2012 16:08:07 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Diverse Operationen für eine Verkettete Liste on Tue, 31 Jul 2012 16:08:07 GMT]]></title><description><![CDATA[<p>Hi alle miteinander!<br />
Meine Frage ist folgende:<br />
Ich habe mir die Basis für eine einfach verkettete Liste erstellt (Liste, Kopfknoten, Knoten &amp; Endknoten), funktioniert auch alles (bisher nur einfügen &amp; anzeigen) und bisher auch ohne Templates. Nun möchte ich mir verschiedene Operationen hinzufügen, z.B. einen <code>operator[]</code> oder eine <code>find()</code> -Methode. Hier erstmal einige Ausschnitte:</p>
<pre><code class="language-cpp">class bNode
{
    public:
        virtual ~bNode() {}
        virtual bool insert(const Data&amp;) = 0;
        virtual void print() const = 0;
};

class Node : public bNode
{
    Data* _data;
    bNode* _next;

    public:
        Node(const Data&amp;, bNode*);

        Node(const Node&amp;);

        ~Node();

        const Node&amp; operator=(const Node&amp;);

        bool insert(const Data&amp;); //Inserts a new Element

        void print() const;
};
</code></pre>
<p>Data ist einfach eine Art Wrapper um einen einzelnen Integer. Wird noch durch Templates verallgemeinert. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /><br />
Der Startknoten delegiert nur die Aufgaben weiter und der Endknoten macht fast gar nichts. Jetzt hatte ich mir für die <code>find()</code> -Methode folgendes gedacht:</p>
<pre><code class="language-cpp">int Node::find(const Data&amp; dat, int counter) const
{
    if (dat.Value() == _data-&gt;Value())
        return counter;
    return _next-&gt;find(dat, ++counter);
}
</code></pre>
<p>...also das ich die ganze Liste durchgehe und direkt einen counter, der die momentane Stelle mitzählt durchreiche. Analog wäre das für alle anderen Arten von Operationen (Indexoperator, Sortierung, ...). Meine Frage jetzt: geht das noch besser? Ich finde es vom Style nicht so schön dort immer einen counter mitzugeben. Ich hätte gedacht, dass ich in jedem Knoten irgendwie seine Position speichere, aber dann müsste ich bspw. beim sortieren die ganze Liste durchgehen und nochmal alle Positionen neu setzen. Mir fehlt da grad ne Idee. Danke fürs lesen und ich würd mich über eure Antworten freuen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<p>PS: Wenn was unklar ist: fragen, ich wollte jetzt nicht mein ganzes Projekt hier reinkopieren...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2237376</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2237376</guid><dc:creator><![CDATA[Ich bin Matrix...]]></dc:creator><pubDate>Tue, 31 Jul 2012 16:08:07 GMT</pubDate></item><item><title><![CDATA[Reply to Diverse Operationen für eine Verkettete Liste on Tue, 31 Jul 2012 18:09:31 GMT]]></title><description><![CDATA[<p>Wozu Vererbung? Die impliziert doch, dass beine gewisse Varianz bei der Ableitung möglich ist. Dein Interface in bNode ist aber speziell nur für die eine Art Ableitung geeignet.</p>
<p>Ansonsten evtl einfach zu kompliziert gedacht, z.B.</p>
<pre><code class="language-cpp">int Node::find(const Data&amp; dat) const
{
    return dat.Value() == _data-&gt;Value() ? 0 : _next == nullptr ? 1 : 1 + _next-&gt;find( dat );
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2237406</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2237406</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Tue, 31 Jul 2012 18:09:31 GMT</pubDate></item><item><title><![CDATA[Reply to Diverse Operationen für eine Verkettete Liste on Tue, 31 Jul 2012 17:58:26 GMT]]></title><description><![CDATA[<p>Hallo Matrix,</p>
<p>tja - die Vererbungsfrage wolte ich auch gerade stellen, da sehe ich campers Antwort. Ja - wozu soll das gut sein.</p>
<p>Weiter sagst Du, dass Du einen operator[] einbauen möchtest. Dieser suggeriert aber, dass ein Anwender Deiner Liste in der Form</p>
<pre><code class="language-cpp">DeineListe l;
    // l füllen
    for( int i=0; i &lt; n; ++i ) // n == ganzViele
        macheWasMit( l[i] );
</code></pre>
<p>über die Liste läuft. Dann rechne mal die Anzahl der Durchläufe auf, die von Node zu Node-&gt;next gemacht werden müssen. Das ist nämlich n^2/2. Und das ist bei großen Werten von n ganz schön viel mehr.<br />
Eine verkette Liste ist nicht dafür gedacht, einem sogenannten 'random access'-Zugriff zu implementieren.</p>
<p>Schlauer wäre es doch eine (hoffentlich Standard konformen) Iterator zu implementieren. Dann löst sich nicht nur das find-Problem sofort auf - das macht nämlich <a href="http://www.cplusplus.com/reference/algorithm/find" rel="nofollow">std::find</a> - sondern die Iteratoren ermöglichten auch allen anderen Standard-Algorithmen Zugriff auf die Liste.</p>
<p>Nächster Punkt. Was macht eigentlich Node::insert? Jetzt mal zurück gelehnt und überlegt - ein Knoten und da soll was eingefügt werden? Ist es nicht vielmehr so, dass in eine Liste etwas eingefügt wird? Und die Liste besteht aus einer Kette von Knoten - oder?</p>
<p>Und Rekursion ist auch eine prima Sache - aber irgendwann ist der Stack am Ende - viel schneller als der Heap.</p>
<p>Gruß<br />
Werner</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2237414</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2237414</guid><dc:creator><![CDATA[Werner Salomon]]></dc:creator><pubDate>Tue, 31 Jul 2012 17:58:26 GMT</pubDate></item><item><title><![CDATA[Reply to Diverse Operationen für eine Verkettete Liste on Tue, 31 Jul 2012 19:30:43 GMT]]></title><description><![CDATA[<blockquote>
<p>Wozu Vererbung? Die impliziert doch, dass beine gewisse Varianz bei der Ableitung möglich ist. Dein Interface in bNode ist aber speziell nur für die eine Art Ableitung geeignet.</p>
</blockquote>
<p>Ich hab Startnode und Endnode auch von bNode abgeleitet, damit ich in <code>Node::_next</code> nicht nur einen Verweis auf einen normalen Knoten, sondern auch auf einen Endknoten speichern kann. Bzw. im Startknoten auch einen Verweis auf den Endknoten speichern kann.</p>
<blockquote>
<p>Eine verkette Liste ist nicht dafür gedacht, einem sogenannten 'random access'-Zugriff zu implementieren.</p>
</blockquote>
<p>Ok, ich werds mir merken. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
<blockquote>
<p>Was macht eigentlich Node::insert?</p>
</blockquote>
<p>Ich weiß nicht, wie man das sonst machen kann, aber insert wird von der Liste aus aufgerufen und fügt, wenn der Benutzer es braucht bei Bedarf neue Knoten an die Liste an.</p>
<blockquote>
<p>Ist es nicht vielmehr so, dass in eine Liste etwas eingefügt wird? Und die Liste besteht aus einer Kette von Knoten - oder?</p>
</blockquote>
<p>Ist doch eine Verkettete Liste, oder hab ich da komplett was verpeilt?</p>
<blockquote>
<p>sondern die Iteratoren ermöglichten auch allen anderen Standard-Algorithmen Zugriff auf die Liste.</p>
</blockquote>
<p>Ja, das wäre eine Möglichkeit, aber mir dient das ganze eher zur Übung, weshalb ich mir diverse Funktionen, die es auch schon in &lt;algorithm&gt; u.ä. gibt selbst schreiben werde.<br />
Aber wenn eine solche Liste nicht für random-Access geeignet ist, wars das eigentlich schon mit der Frage <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2237433</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2237433</guid><dc:creator><![CDATA[Ich bin Matrix...]]></dc:creator><pubDate>Tue, 31 Jul 2012 19:30:43 GMT</pubDate></item><item><title><![CDATA[Reply to Diverse Operationen für eine Verkettete Liste on Tue, 31 Jul 2012 20:45:32 GMT]]></title><description><![CDATA[<p>Ich bin Matrix... schrieb:</p>
<blockquote>
<blockquote>
<p>Wozu Vererbung? Die impliziert doch, dass beine gewisse Varianz bei der Ableitung möglich ist. Dein Interface in bNode ist aber speziell nur für die eine Art Ableitung geeignet.</p>
</blockquote>
<p>Ich hab Startnode und Endnode auch von bNode abgeleitet, damit ich in <code>Node::_next</code> nicht nur einen Verweis auf einen normalen Knoten, sondern auch auf einen Endknoten speichern kann. Bzw. im Startknoten auch einen Verweis auf den Endknoten speichern kann.</p>
</blockquote>
<p>interessant - d.h., dass Start- und Endknoten von unterschiedlichem Typ sind. Ich unterstelle mal, dass der Endknoten keinen Data*-Pointer hat. Aber man kann trotzdem auf ihm z.B. insert aufrufen. Was soll dann passieren?</p>
<p>Ich bin Matrix... schrieb:</p>
<blockquote>
<blockquote>
<p>Was macht eigentlich Node::insert?</p>
</blockquote>
<p>Ich weiß nicht, wie man das sonst machen kann, aber insert wird von der Liste aus aufgerufen und fügt, wenn der Benutzer es braucht bei Bedarf neue Knoten an die Liste an.</p>
</blockquote>
<p>Das war eine rhetorische Frage - was ich meine ist, dass das insert eine Methode der Liste sein sollte. Wenn man ein neues Element in eine verkettet Liste einfügt, so muss man sich um den Vorgänger, den Nachfolger und den einzufügenden Knoten in irgendeiner Weise kümmern.<br />
Und dazu braucht man dann keine Methode Node::insert mehr, sondern vielmehr einen Zugriff auf die Verlinkung der Knoten untereinander.</p>
<p>Aber bevor ich weiter spekuliere - der Member next eines Knotens zeigt doch auf den Nachfolger des Knotens. Wo wird dann nach einem insert der neue Knoten eingefügt?</p>
<p>Ich bin Matrix... schrieb:</p>
<blockquote>
<blockquote>
<p>sondern die Iteratoren ermöglichten auch allen anderen Standard-Algorithmen Zugriff auf die Liste.</p>
</blockquote>
<p>Ja, das wäre eine Möglichkeit, aber mir dient das ganze eher zur Übung, weshalb ich mir diverse Funktionen, die es auch schon in &lt;algorithm&gt; u.ä. gibt selbst schreiben werde.</p>
</blockquote>
<p>das kannst Du ja gerne tun, aber warum nicht mit Hilfe von Iteratoren. Auch das ist eine prima Übung.<br />
Der Vorteil ist, dass Du verschiedene Container mit verschiedenn Algorithmen kombinieren kannst.</p>
<p>Im Übrigen ist das Konzept 'Iterator' ein sehr mächtiges und es lohnt sich, sich damit zu beschäftigen.</p>
<p>Gruß<br />
Werner</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2237449</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2237449</guid><dc:creator><![CDATA[Werner Salomon]]></dc:creator><pubDate>Tue, 31 Jul 2012 20:45:32 GMT</pubDate></item><item><title><![CDATA[Reply to Diverse Operationen für eine Verkettete Liste on Wed, 01 Aug 2012 01:56:05 GMT]]></title><description><![CDATA[<blockquote>
<p>interessant - d.h., dass Start- und Endknoten von unterschiedlichem Typ sind. Ich unterstelle mal, dass der Endknoten keinen Data*-Pointer hat. Aber man kann trotzdem auf ihm z.B. insert aufrufen. Was soll dann passieren?</p>
</blockquote>
<p>Sein insert liefert einfach false zurück, und weist somit den Knoten davor an, die Daten hinter sich zu plazieren, somit werden neue Daten immer bis zum Ende durchgereicht und hinter das letzte Element - also vor Endnode angebracht.</p>
<blockquote>
<p>Aber bevor ich weiter spekuliere - der Member next eines Knotens zeigt doch auf den Nachfolger des Knotens. Wo wird dann nach einem insert der neue Knoten eingefügt?</p>
</blockquote>
<p>Ganz einfach: Die Liste hat eine Methode insert und die Addresse des Startknotens gespeichert, welchem sie in ihrem Konstruktor erstellt - genauso wie den Endknoten, dessen Addresse beim Erstellen der Liste in _next vom Startknoten gespeichert werden. Am Anfang speichert also die Liste die Addy des Startknotens, welcher als Nachfolger den Endknoten hat - eine leere Liste. Auch die Liste hat natürlich eine Methode insert, welche wie gesagt vom Startknoten ausgehend die Daten bis zum Ende durchreicht. Hier mal ein wenig mehr Code, vllt wird es dir dann klarer, wie ich mir das gedacht hab. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<pre><code class="language-cpp">bool Node::insert(const Data&amp; dat)
{
    /*if (*_data &lt; dat) //if the current element is smaller then the given one, the function returns false
        return false; //which means that the element has to be put between this and the last Node
    if (!_next-&gt;insert(dat)) //which is done here -&gt; if insert is false for the current node, the element
        _next = new Node(dat, _next); // is smaller then the next one but bigger or equal this one
                                      // tho it is inserted as the new one relatively to the current node
                                      // or as the one before relatively to the next node
                                      //(which has returned false)
    return true;*/

    if (!_next-&gt;insert(dat)) //if insert returns false for the next node (can only happen if next node is
        _next = new Node(dat, _next/*, _position+1*/); // end node, because Node::insert always returns true) insert is
    return true; //called for the next node -&gt; all nodes are added directly before the end node
}
</code></pre>
<pre><code class="language-cpp">Node::Node(const Data&amp; dat, bNode* next/*, int pos*/)
        : _data(new Data(dat)), _next(next)//, _position(pos)
{
}
</code></pre>
<pre><code class="language-cpp">class List
{
    Startnode* _start;

    public:

        List();
        List(const List&amp;);
        ~List();
        const List&amp; operator=(const List&amp;);
        void insert(const Data&amp;);
        void print() const;
};
</code></pre>
<pre><code class="language-cpp">List::List()
    : _start(new Startnode(new Endnode))
{
}

void List::insert(const Data&amp; dat)
{
    _start-&gt;insert(dat);
}
</code></pre>
<pre><code class="language-cpp">class Startnode : public bNode
{
    bNode* _next;

    public:

        Startnode(bNode*);
        Startnode(const Startnode&amp;);
        ~Startnode();
        const Startnode&amp; operator=(const Startnode&amp;);
        bool insert(const Data&amp;);
        void print() const {_next-&gt;print();}
};
</code></pre>
<pre><code class="language-cpp">Startnode::Startnode(bNode* next)
           : _next(next)
{
}

bool Startnode::insert(const Data&amp; dat)
{
    if (!_next-&gt;insert(dat))
        _next = new Node(dat, _next);
    return true;
}
</code></pre>
<pre><code class="language-cpp">class Endnode : public bNode
{
    public:

        ~Endnode() {std::cout &lt;&lt; &quot;Destructor of class Endnode\n&quot;;}
        bool insert(const Data&amp; dat) {return false;}
        void print() const {}
};
</code></pre>
<p>Sry, wenns zuviel Code ist :x</p>
<blockquote>
<p>das kannst Du ja gerne tun, aber warum nicht mit Hilfe von Iteratoren. Auch das ist eine prima Übung.</p>
</blockquote>
<p>Gut, ok, das wäre dann mein nächster Schritt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2237486</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2237486</guid><dc:creator><![CDATA[Ich bin Matrix...]]></dc:creator><pubDate>Wed, 01 Aug 2012 01:56:05 GMT</pubDate></item></channel></rss>