[STL] Vector iterator an Position springen
-
Klaus82 schrieb:
Einiges davon kann ich sogar schon mit ja beantworten. Führt das jetzt zu
im Sinne von 'ich kanns' oder
im Sinne von 'wenn du es weißt, wieso programmierst du es dann nicht so'
Ich wollte nur sicher gehen, dass du weißt, dass man das auch anders aufschreiben kann. Kannst natürlich sagen "nee, so wie ich das schreibe, finde ich das schöner" und dagegen ist auch nix einzuwenden -- also in diesem Fall.
Klaus82 schrieb:
Na ja, prinzipiell learning by doing. Ich habe hier schnell gemerkt, dass die Aussage "C++ können" einem ziemlich hohen Anspruch genügen muss.
Naja, wenn du sagen würdest "ich kann Turmspringen", dann gehe ich davon aus, dass du auch Salti und nicht nur gerade runterspringen kannst. Und wenn du es einfach so probierst, ohne dich intensiver mit der Technik auseinanderzusetzen, dann machste halt auch mal eher 'nen Bauchklatscher. Tut dann natürlich weh. Ich bereue die Entscheidung nicht, mir ein schlaues C++ Buch besorgt zu haben. Drauflos hacken, ohne zu verstehen, was ich da eigentlich tue, wäre für mich total unbefriedigend. Ich will mir ja auch relativ sicher sein, dass ich keinen Murks baue ...
Klaus82 schrieb:
Und ich selbst würde eben C++ gerne mehr verstehen, als lediglich ein Programm zusammenzustricken, dass 'irgendwie geht'.
Das ist doch schomma 'ne super Einstellung.
Klaus82 schrieb:
Und so pendle ich von Baustelle zu Baustelle, einmal hier etwas ausprobieren, dann gesagt bekommen wie es 'richtig' geht, das wieder nachvollziehen, dann wieder neu ausprobieren ...
Na, wenn es für dich funktioniert.
Klaus82 schrieb:
Und eigentlich ist das alles nur Nebensache, denn primär mache ich Physik und nicht Programmieren, da ist also von Cheffe kein Anspruch dahinter, dass es sauber programmiert ist, sondern die richtige Physik liefert.
Hmmm ... ich denke mal, das eine bedingt ein bisschen das andere.
Klaus82 schrieb:
Die C++-Standardbibliothek. Einführung und Nachschlagewerk
Nicht übel. Das ist doch eine super Quelle, um nachzuschauen, ob es sowas wie <utility> gibt.
-
SeppJ schrieb:
Verwechsele nicht den (ausgezeichneten) C++ Primer mit deinem C++ Primer Plus! Über letzteren kann ich nicht viel sagen.
Ach verdammt, verwechselt. Von diesem C++ Primer hatte ich schon viel gehört und habe mir den C++ Primer Plus zugelegt (nachdem ich das andere Buch schon hatte und es scheinbar 'Schrott' ist).
Jetzt wähnte ich mich auf der sicheren Seite; dann muss ich mich doch nochmal umsehen.
Hier stand Blödsinn
Gruß,
Klaus.
-
So,
heute kam der C++ Primer. Ich bin gespannt wie ein Flitzebogen. Fragen werden folgen.Viele Grüße,
Klaus.
-
So ihr Lieben,
314159265358979 schrieb:
1. Iterator auf das letzte Element holen.
2. Wenn ein Element gelöscht werden soll, Element mit *last tauschen.
3. Last erniedrigen
4. Remove & Erase Idiomausgehend davon habe ich jetzt ein kleines Programm zusammengestrickt, was die Anforderungen in abgewandelter Form erfüllt.
1. Das Programm prüft, ob ein Element gelöscht werden soll.
2. Das Programm vertauscht dieses Element mit dem letzten desvectors
3. Die Zählung bis und der Iterator auf das letzte Element werden erniedrigt.
4. Das geschieht jetzt dadurch, dass einfach vom Iterator bis zum Ende des Vectors alles Elemente gelöscht werden. Funktioniert, scheint aber nicht ganz dem Prinzip des erase remove idioms zu entsprechen.seldon schrieb:
Es wäre besser, einen Zufallszahlengenerator zu benutzen, der gleich Integer ausspuckt und ihn durch std::uniform_int_distribution zu pressen.
Ich hatte überlegt den Zufallsgenerator integers von 1 bis vector<T>.size() erstellen zu lassen, nur scheitert es dann am dem
std::uniform_int_distribution
.
Das scheint erst wieder mit C++11 zu gehen und zumindest hier auf der Arbeit mit Lenny scheint es nicht zu laufen.
Aber wir stellen jetzt ja auf Squeeze um.Gruß,
Klaus.
-
Dann nimm's halt aus Boost. Daher kommt der Kram ja ursprünglich.
-
Klaus82 schrieb:
ein kleines Programm zusammengestrickt, was die Anforderungen in abgewandelter Form erfüllt.
Das ist leider Murks.
Fehler:
- Du überspringst ggf ein Element, ohne es überprüft zu haben.
- Du dekrementierst einen Iterator, der ggf schon auf das erste Element zeigt.Komisch:
- swap bringt dir in deinem Fall gegenüber einer einfachen Zuweisung nichts.
- Wozu inkludierst du <iterator>?Schade. Du hast da mit dem Überspringen übrigens einen Fehler gemacht, vor dem ich auf Seite 4 schon am 23.5. um 10:57 Uhr gewarnt habe.
-
Ich möchte auch nocheinmal den Hinweis von Seite 4 von SeppJ und Seldon zu remove_if erneuern. Das macht genau das, was du versuchst, nur ohne Fehler.
Damit kannst du deine gesamte handgestrickte Schleife in Zeile 43 bis 54 durch einen Einzeiler ersetzen.
-
krümelkacker schrieb:
Fehler:
- Du überspringst ggf ein Element, ohne es überprüft zu haben.Oh ja! Ich war so auf das
move
fixiert, dass wir doch nicht benötigen, dass ich dachte es sei jetzt überholt und ich könnte getrosti
erhöhen.
Aber ich muss ja noch das Element prüfen, mit dem ich getauscht habe und dazu darf ich erstmal nicht erhöhen!krümelkacker schrieb:
- swap bringt dir in deinem Fall gegenüber einer einfachen Zuweisung nichts.
Das verstehe ich nicht. Was ist in diesem Zusammenhang
eine einfache Zuweisung
?Schlußendlich muss ich sagen, dass ich nicht mal mehr verstehe, warum wir
swappen
odermoven
[1] wollten. Es reicht doch wirklich folgendes:iter = v.begin(); for(unsigned int i = 0; i < num_ints;) { if(delete_element(v[i])) { l.push_back(v[i]); v.erase(iter+i); --num_ints; } else // do something else with the element v[i] ++i; }
Klappe zu, Affe tot.
Wobei ich hier nochmal konkret nachfragen muss, wie sich das mit dem Indexzugriff verhält. Wenn ich über einen Iterator zugreife, so steht ja zu erase, dass ein Iterator zurückgegeben wird, der auf das folgende Element zeigt.
Wenn ich jetzt aber ein Element lösche, dann müssen die anderen alle 'nach oben nachrücken', oder? D.h. ich habe eine Indexverschiebung
Wenn ich also i nicht bei jedem Schleifendurchlauf erhöhe, so wird i dadurch 'erhöht', dass ein Element gelöscht wird. Also das Element i+1 ist jetzt i und (ich erhöhe i nicht) so prüfe ich eben das nächste Element.Gruß,
Klaus.[1] Immer diese denglischen Begriffsbildungen.
-
Klaus82 schrieb:
krümelkacker schrieb:
- swap bringt dir in deinem Fall gegenüber einer einfachen Zuweisung nichts.
Das verstehe ich nicht. Was ist in diesem Zusammenhang
eine einfache Zuweisung
?int a = 23; int b = 42; //swap(a,b); // <- Vertauschung a = b; // <- Zuweisung
Da du b quasi nicht mehr brauchst, reicht die Zuweisung. In beiden Fällen bekommt a den Wert, den b hatte.
Klaus82 schrieb:
Schlußendlich muss ich sagen, dass ich nicht mal mehr verstehe, warum wir
swappen
odermoven
[1] wollten. Es reicht doch wirklich folgendes:iter = v.begin(); for(unsigned int i = 0; i < num_ints;) { if(delete_element(v[i])) { l.push_back(v[i]); v.erase(iter+i); --num_ints; } else // do something else with the element v[i] ++i; }
Klappe zu, Affe tot.
Klaus82 schrieb:
Wenn ich jetzt aber ein Element lösche, dann müssen die anderen alle 'nach oben nachrücken', oder?
Ja sicher. Deswegen ist das Löschen eines einzelnen Elements aus der Mitte auch eine doofe Idee und deswegen hast du ja auch Tipps bekommen, wie du es besser machen könntest!
-
Hi,
krümelkacker schrieb:
Klaus82 schrieb:
Wenn ich jetzt aber ein Element lösche, dann müssen die anderen alle 'nach oben nachrücken', oder?
Ja sicher. Deswegen ist das Löschen eines einzelnen Elements aus der Mitte auch eine doofe Idee und deswegen hast du ja auch Tipps bekommen, wie du es besser machen könntest!
Ich glaube das bringt bei mir zur Zeit noch nichts, da ich einfach zu wenig Ahnung von STL habe.
Ich kann z.B. überhaupt nicht abschätzen, wieviel Aufwand etwas darstellt. Wenn z.B. löschen in der Mitte eines Vektors eine doofe Idee ist, wieso ist es dann weniger umständlich das Element ans Ende zu verschieben und dann alle Elemente gesammelt am Ende zu löschen.
Sicher, das Löschen am Ende erscheint mir kompakter, aber allein das Verschieben ist doch auch Aufwand.Aus dem Grund muss ich erstmal viel lesen gehen ... hab ja jetzt den C++ Primer und laut Vorwort, wird auch direkt auf die STL eingegangen. Schließlich sei es unsinnig alles primitiv zu programmieren, nur um dann am Ende zu sagen: Wir müssen das Rad nicht neu erfinden, sondern uns lediglich der STL bedienen.
Vielleicht sehe ich dann klarer.
Momentan habe ich nur das Gefühl ich drehe mich im Kreis.
Auf jeden Fall danke an alle, die so lange durchgehalten haben.
Viele Grüße,
Klaus.
-
Klaus82 schrieb:
Ich kann z.B. überhaupt nicht abschätzen, wieviel Aufwand etwas darstellt. Wenn z.B. löschen in der Mitte eines Vektors eine doofe Idee ist, wieso ist es dann weniger umständlich das Element ans Ende zu verschieben und dann alle Elemente gesammelt am Ende zu löschen.
Ans Ende schieben sollst du sie gar nicht. Das war nur eine Idee vom Pi mit dem swap. Sagte ich ja, dass das unnötig ist. Das Ding ist, wenn du erase für ein einziges Element in der Mitte durchführst, müssen die dahinter liegenden nachrücken und das kostet. Da die Reihenfolge im Vektor bei dir aber gar nicht wichtig zu sein scheint, kannst du auch einfach das letzte Element an die Stelle kopieren, die du sonst gelöscht hättest. Also, statt
soll weg | V +---+---+---+---+---+ | H | e | l | l | o | +---+---+---+---+---+ / / / / / / / / / +---+---+---+---+ | H | l | l | o | +---+---+---+---+
machst du einfach
|<- gültig bis +---+---+---+---+---+ | H | e | l | l | o | +---+---+---+---+---+ | +-----------+ | V |<- gültig bis +---+---+---+---+---+ | H | o | l | l | o | +---+---+---+---+---+
Hinterher dann die Dinger am Ende, die eh nicht mehr gültig sind, mit einem Rutsch entfernen und fertig ist die Laube.
-
Hi,
krümelkacker schrieb:
Da die Reihenfolge im Vektor bei dir aber gar nicht wichtig zu sein scheint, kannst du auch einfach das letzte Element an die Stelle kopieren, die du sonst gelöscht hättest.
Ah, ich glaube jetzt verstehe ich was du meinst. Also nicht das Element im Vektor selbst verschieben, sondern lediglich den Inhalt des Elements kopieren.
Etwas in diesem Stil:
vecttor<int> v; // ... v wird gefüllt vector<int>::iterator iter = --(v.end()); // iterator auf letztes Element unsigned int num_v = v.size(); for(unsigned int i = 0; i < num_v;) { if('soll Element i gelöscht werde') { int last_position = std::distance(v.begin(),iter); v[i] = v[last_position]; --num_v; --iter; // <--- noch zu prüfen, falls iter zu v.begin() wird } else { ++i; } } v.erase(iter,v.end());
So ungefähr?
Gruß,
Klaus.P.S.: Danke für die schönenen ASCII Zeichnungen!
-
//Fehler .....
-
Das geht noch einfacher und "korrekter":
vector<int> v; // ... v wird gefüllt unsigned gueltig = v.size(); for (unsigned i=0; i<gueltig;) { if('soll i-tes Element gelöscht werden?') { --gueltig; v[i] = v[gueltig]; } else { ++i; } } v.erase(v.begin()+gueltig,v.end());
Für statistische Simulationen ist std::rand wohl auch keine gute Idee. Da gibt es qualitativ hochwertigere Pseudozufallszahlengeneratoren. Siehe Boost.Random