char array mit Seperator alphabetisch sortieren
-
Ja und sie braucht auch nur einmal sortiert warden.
-
Werner Salomon schrieb:
.. und wie erklärt sich dann die Anforderung, dass da mehrere dieser wordList's pro Sekunde sortiert werden sollen. Das ist doch erst mal nur eine?
Oder das überhaupt sortiert werden muss, wo man das doch schon zur Compilezeit haben könnte?
Klingt so, als wäre hier noch sehr viel Optimierungspotential durch Benutzung passenderer Datenstrukturen. Selbst, wenn es nur std::string ist.
-
Ja schon, die Start-Liste müsste theoretisch nur einmal bzw. gar nicht sortiert werden, da es immer die selbe ist und man diese vorab sortieren könnte.
Warum ich das (bis jetzt) nicht gemacht habe:
Während dem Programmablauf wird die Wortliste dynamisch und nicht vorhersehbar erweitert/reduziert und das sehr oft. Hier muss die Wortliste sowieso ständig sortiert werden, da immer eine sortierte Version davon verfügbar sein muss.
Die Liste vorab zu sortieren hab ich deswegen nicht gemacht da der eine Sortiervorgang eh nicht ins Gewicht fällt und weil ich so schnell und einfach überprüfen kann ob der Sortieralgorithmus so funktioniert wie er soll.
SeppJ schrieb:
Werner Salomon schrieb:
Klingt so, als wäre hier noch sehr viel Optimierungspotential durch Benutzung passenderer Datenstrukturen. Selbst, wenn es nur std::string ist.
Ist std::string schneller als ein char array?? Ich dachte immer recht viel schneller gehts nicht...
-
happystudent schrieb:
Während dem Programmablauf wird die Wortliste dynamisch und nicht vorhersehbar erweitert/reduziert und das sehr oft. Hier muss die Wortliste sowieso ständig sortiert werden, da immer eine sortierte Version davon verfügbar sein muss.
Wie machst du das denn bei einem char-Array? Wo kommen diese Änderungen her? Wo kommen die Daten her?
Ist std::string schneller als ein char array?? Ich dachte immer recht viel schneller gehts nicht...
Nicht per se schneller, aber damit sind eben Sachen möglich, die mit einem char-Array gar nicht oder nur sehr umständlich möglich sind. Zum Beispiel "die Wortliste dynamisch und nicht vorhersehbar erweitern". Wie machst du das bisher?
-
SeppJ schrieb:
Wo kommen diese Änderungen her? Wo kommen die Daten her?
Also die Änderungen kommen von Benutzereingaben. Diese können prinzipiell beliebig sein, solange sie den Anforderungen entsprechen werden sie zur Wortliste hinzugefügt. Falls der Benutzer sie löschen will kann er das auch tun.
SeppJ schrieb:
Nicht per se schneller, aber damit sind eben Sachen möglich, die mit einem char-Array gar nicht oder nur sehr umständlich möglich sind. Zum Beispiel "die Wortliste dynamisch und nicht vorhersehbar erweitern". Wie machst du das bisher?
Ja, das wäre wahrscheinlich dann das nächste Problem, soweit bin ich noch gar nicht.
Bis jetzt hab ich ja C# verwendet, da hab ich das ungefähr so gemacht:
wortListe += " " + "neuesWort"; // Dann .Split und .Sort
-
happystudent schrieb:
SeppJ schrieb:
Wo kommen diese Änderungen her? Wo kommen die Daten her?
Also die Änderungen kommen von Benutzereingaben. Diese können prinzipiell beliebig sein, solange sie den Anforderungen entsprechen werden sie zur Wortliste hinzugefügt. Falls der Benutzer sie löschen will kann er das auch tun.
SeppJ schrieb:
Nicht per se schneller, aber damit sind eben Sachen möglich, die mit einem char-Array gar nicht oder nur sehr umständlich möglich sind. Zum Beispiel "die Wortliste dynamisch und nicht vorhersehbar erweitern". Wie machst du das bisher?
Ja, das wäre wahrscheinlich dann das nächste Problem, soweit bin ich noch gar nicht.
Bis jetzt hab ich ja C# verwendet, da hab ich das ungefähr so gemacht:
wortListe += " " + "neuesWort"; // Dann .Split und .Sort
Da schreit mich geradezu ein vector<string> als Datenstruktur an. Vielleicht auch (multi-)set<string>, kommt drauf an, warum du überhaupt sortieren möchtest. Ebenso für den C#-Code das entsprechende Äquivalent. Du hast doch schon alle Information, die du jemals haben willst: Eine Liste einzelner Wörter. Dann schmeißt du alles weg, indem du die Wörter hintereinander in das Array schreibst. Dann fummelst du das Array wieder auseinander, um eine Liste einzelner Wörter zu erhalten und diese zu sortieren. Dann schmeißt du wieder alles in das Array.
Lass das Array einfach weg! Wozu ist das überhaupt da? Wenn du für den dll-Call unbedingt einen char* brauchst, dann machst du dir im allerletzten Schritt aus der sortierten Wortliste einen passenden string.P.S.: So zum Beispiel:
#include <set> #include <string> #include <iostream> using namespace std; int main() { // Unsere Wörterliste. Schon sortiert. multiset<string> words; // Primitiver Datenbanksimulator, hier kommt deine Benutzerinteraktion hin cout << "Wörter eingeben bis Ende\n"; string word; while (cin >> word) words.insert(word); // Ausgabe in einen string: string result; for(string const& word: words) { result += word; result += ' '; } // Benutze den String in einer Funktion, die const char* erwartet: cout << result.c_str() << '\n'; }
Ist doch schon gleich viel einfacher.
-
Hallo,
danke für den Vorschlag. Ich hab es jetzt (ein wenig anders) hingekriegt, da dem Compiler die for Schleife nicht gefallen hat (error : missing ',' before ':') und die word variable hat ihm auch nicht gepasst (error C2530: 'word' : references must be initialized).
Habs jetzt mal so probiert:
std::vector<std::string> vec; vec.push_back("aaaaa"); vec.push_back("bbb"); vec.push_back("ccccc"); std::string result = join(vec, " "); // übergeben als result.c_str() funktioniert tatsächlich
mit folgender join Funktion:
std::string join(const std::vector<std::string>& vec, const char* delim) { std::stringstream res; copy(vec.begin(), vec.end(), std::ostream_iterator<std::string>(res, delim)); return res.str(); }
Ist das so gut?
Ich komm leider noch gar nicht klar mit diesen ständigen Typ-Problemen in C++, in C# ging das immer alles so einfach und problemlos
Schöne Grüße,
hs
-
Deine join-Funktion ist "umständlich".
da dem Compiler die for Schleife nicht gefallen hat
Kein C++11. Hast du VC++?
Ändere das ab zu etwas wie
std::string join(std::vector<std::string> const& vec, const char* delim) { std::string str; for( std::vector<std::string>::const_iterator it = vec.begin(); it != vec.end(); ++it ) *it += s + delim; return str; }
(ungetestet)
, das ist nicht kürzer, aber direkter.
-
Arcoth schrieb:
Deine join-Funktion ist "umständlich".
Dito.
Gabs hier nicht mal jemand, der sich beschwert hatte, dass std::accumulate bei den C++-Programmieren noch nicht angekommen ist?
std::string join(std::vector<std::string> const& vec, const char* delim) { return std::accumulate(vec.begin(), vec.end(), std::string(), [=](std::string const& r, std::string const& s){return r + s + delim;}); }
-
Genau daran habe ich auch gedacht. (Nur natürlich richtig, deine Version hat einen Fehler)
Nur leider ein wenig fehl am Platz, da kein C++11 erlaubt ist.
-
Arcoth schrieb:
Genau daran habe ich auch gedacht. (Nur natürlich richtig, deine Version hat einen Fehler)
Hoho, ein überheblicher Klugscheisser.
Na, im Gegensatz zu deinem Code ist meiner wenigstens korrekt.
-
akkum schrieb:
Arcoth schrieb:
Deine join-Funktion ist "umständlich".
Dito.
Gabs hier nicht mal jemand, der sich beschwert hatte, dass std::accumulate bei den C++-Programmieren noch nicht angekommen ist?
std::string join(std::vector<std::string> const& vec, const char* delim) { return std::accumulate(vec.begin(), vec.end(), std::string(), [=](std::string const& r, std::string const& s){return r + s + delim;}); }
Quadratische Laufzeit?
-
Arcoth schrieb:
Deine join-Funktion ist "umständlich".
da dem Compiler die for Schleife nicht gefallen hat
Kein C++11. Hast du VC++?
Äh, ich hab Visual Studio 2008 Professional Edition. Hab zwar auch VS 2010 aber da gibt es ja kein Intellisense mehr für C++
Arcoth schrieb:
Ändere das ab zu etwas wie
std::string join(std::vector<std::string> const& vec, const char* delim) { std::string str; for( std::vector<std::string>::const_iterator it = vec.begin(); it != vec.end(); ++it ) *it += s + delim; return str; }
(ungetestet)
, das ist nicht kürzer, aber direkter.Ok, was heißt "direkter"? Schneller? Oder besserer Programmier-Stil?
EDIT:
akkum schrieb:
Na, im Gegensatz zu deinem Code ist meiner wenigstens korrekt.
volkard schrieb:
Quadratische Laufzeit?
Hm, was stimmt jetzt hier?
-
happystudent schrieb:
Hab zwar auch VS 2010 aber da gibt es ja kein Intellisense mehr für C++
Das trifft auf C++/CLI zu, nicht C++.
2008 ist schon ein halbes Jahrzehnt her... Vor allem kannst du damit nicht mal C++11-Features der ersten Generation benutzen.
Aber Range-Based For ist nicht was fundamental Neues,
BOOST_FOREACH
gibts schon ewig. Ist nur schön, dass man es jetzt ohne Makros sauber in die Sprache integriert hat.
-
happystudent schrieb:
Hm, was stimmt jetzt hier?
Bisher wenig. Denke, Du solltest die chars in einem vector<char> erst sammeln und dann Schwuppdiwupps in den Zielstring kopieren oder erst die Zeichen zählen (endlich accumulate), den Zielstring mit dieser Zeichenanzahl anlegen und dann die Quellstrings alle reinkopieren.
edit: Mit http://www.cplusplus.com/reference/string/string/reserve/ vorher genug Platz reservieren, dann ist die Laufzeit von join/accumulate/schleife optimal.
Beim String steht nämlich nicht http://www.cplusplus.com/reference/vector/vector/push_back/
std::string schrieb:
Complexity
Constant (amortized time, reallocation may happen).If a reallocation happens, the reallocation is itself up to linear in the entire size.
-
akkum schrieb:
Na, im Gegensatz zu deinem Code ist meiner wenigstens korrekt.
Tatsächlich, er ist korrekt! Ich hätte schwören können, dass er nur alle zwei Strings den Delimitter setzt! Wenn ich mal genau hinschaue, dann ist es aber völlig korrekt...
Nun, ich habe nichts getestet.Meine Variante ist falsch, ich habe aus Versehen die Bezeichner alle verwurschtelt.
Das soll natürlichfor( std::vector<std::string>::const_iterator it = vec.begin(); it != vec.end(); ++it ) str += *it + delim;
heißen.
was heißt "direkter"? Schneller?
Ja. Es nimmt nicht einen unnötigen Umweg.
Quadratische Laufzeit?
Wieso das
-
Gabs hier nicht mal jemand, der sich beschwert hatte, dass std::accumulate bei den C++-Programmieren noch nicht angekommen ist?
ranged-based for ist sehr viel kuerzer zu schreiben, deswegen wird accumulate selten genutzt. Meine "Beschwerde" war weiter gefasst.
Quadratische Laufzeit?
Wahrscheinlich. Vielleicht schafft es der Compiler trotzdem zu optimieren. Ach koennte das const weggelassen werden, was es etwas leichter fuer den Compiler machen sollte.
-
knivil schrieb:
Quadratische Laufzeit?
Wahrscheinlich. Vielleicht schafft es der Compiler trotzdem zu optimieren.
Nö, sehe da keine Anker, wo der Optimierer greifen könnte. Er wird nicht res.reserve(wordlist.count()+accumulate(wordlist.begin(),wordlist.end(),[]...)) herausfinden.
Aber es kann sein, daß die Implementierung von std::string den Speicher bei += geometrisch wachsen läßt. An sich eine Unsitte. Aber halt sinnvoll für Normalprogrammierer, die die quadratische Laufzeit nicht direkt sehen. Dafür wünschte ich mir ein +=, das direkt und minimal wirkt und eine andere append-Methode, die geometischg wachsen läßt.
#include <iostream> #include <string> #include <algorithm> using namespace std; int main(){ string word="hello"; string res; size_t oldCapacity=0; for(int i=0;i<1000000;++i){ res+=word+" "; if(res.capacity()!=oldCapacity){ cout<<res.capacity()<<'\n'; oldCapacity=res.capacity(); } } }
Ausgabe
6 12 24 48 96 192 384 768 1536 3072 8163 16355 32739 65507 131043 262115 524259 1048547 2097123 4194275 8388579
Ok, gcc verdoppelt immer (ungefähr) bei +=.
Woher mögen die krummen Zahlen kommen?
-
volkard schrieb:
Woher mögen die krummen Zahlen kommen?
Ausrichtung an 4kB-Seiten - free-storeverwaltungsoverhead - 1 Byte Terminator schätze ich mal. Vermutlich mag default-new Speicheranforderungen, die (fast) Vielfache von 4kB sind.
-
GCC 4.9.0, basic_string.tcc
append(const basic_string& __str) { const size_type __size = __str.size(); if (__size) { const size_type __len = __size + this->size(); if (__len > this->capacity() || _M_rep()->_M_is_shared()) this->reserve(__len); _M_copy(_M_data() + this->size(), __str._M_data(), __size); _M_rep()->_M_set_length_and_sharable(__len); } return *this; }
Wo ist hier die Verdopplung versteckt?