Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » std::vector von doppelten cleanen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: [ 1 ] > 2 < [ 3 ]
010
21.05.2004, 13:14 Uhr
0xdeadbeef
Gott
(Operator)


Ich würde den Kram einfach direkt in ein set einlesen - was willste dich noch mit nem vector rumschlagen?
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
011
21.05.2004, 13:25 Uhr
Windalf
Der wo fast so viele Posts wie FloSoft...
(Operator)


hmm dann stehts im moment 3:2 (ich gewichte mal unwissenders stimmte mit 2 weil der immer nett zu mir ist und windowsuser ist ) für das set...
allerdings zählt für mich die stimmte des almächtigen virtuals mindestens 5 fach.. in sofern kann er das ganze natürlich noch kippen...
--
...fleißig wie zwei Weißbrote

Dieser Post wurde am 21.05.2004 um 13:25 Uhr von Windalf editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
012
21.05.2004, 13:37 Uhr
virtual
Sexiest Bit alive
(Operator)


ich denke es kommt darauf an, was du eigentlich machen willst:
Du suchst also einen Container, wo jedes Element nur einmal drin vorkommt. Dann wäre ein std::set die natürlichste Lösung. Allerdings hat std::set (und auch std::list) den Nachteil, daß Du da nicht mit dem []- Operator auf die Element zugreifen kannst. Dh wenn Du sehr oft vor der Fragestellung stehst "Wo lautet der Wert vom 4711. Element), dann sind sowohl set als auch list die eher falsche lösung.

Der Einwand, daß das Löschen aus einem std::vector inperformant sei, ist prinzipiell richtig, an dieser Stelle greift er aber nicht. Denn:

C++:
std::vector<std::string> data;
... //1 .
std::sort(data.begin(),data.end()); // 2.
std::vector<std::string>::iterator p = std::unique(data.begin(),data.end()); //3.
data.erase(p, data.end()); // 4.


Gehen wir mal Schritt für Schritt durch:
1. Im ersten Schritt wird der Container ja aufgebaut. Hier gilt vom Zeitbedarf des Aufbaus vermutlich list <= vector < set; dh set wird hier mit abstand das langsamste sein. Schwieriger wird es allerdings beim Unterschied vector/list: wenn Du ungefähr abschätzen kannst, wie groß der Vector wird, kannst du ein data.reserve machen und damit dürfte die Vectorlösung dann die schnellste sein (weil das umkopieren der Elemente entfällt und der eigentliche Einfügevorgang deutlich einfacher als bei einer List wäre).
2. Das sortieren entfällt bei set, dafür hat man eben im ersten Schritt bezahlen müssen. Hier ist die ungleichung set < vector < list, wobei das Sortieren einer list deutlich langsamer von Statten geht als von einem Vector.
3.Das unique kopiert die elemente um (!Es macht keine Löschoperation!). Hier sind je nach Klasse leichte vorteile für die list denkbar. Enthält der Container simple Objekte, so würde ich mal behaupten, der Zeitunterschied list/Vector wäre marginal.
4. Das entfernen wird beim Vector schneller sein als bei der List: beim vector brauchen nämlich, weil nur am Ende gelöscht wird, lediglich die Destruktoren des zu entfernenden Elemente aufgerufen zu werden, bei einer list muß hingegen auch die Verkettung nachgehalten werden, was je nach implemntierung mehraufwand bedeutet.

Folglich: list würde ich auf keinen fall nehmen, set genau dann, wenn kein Index-Zugriff erforderlich ist und vector, wenn mit Indexzugriff gearbeitet wird.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 21.05.2004 um 13:43 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
013
21.05.2004, 13:46 Uhr
0xdeadbeef
Gott
(Operator)


Ich denke, wenn man vor der Frage, welches das 4711. Element ist, stünde, wäre die Lösung mit std::sort auch nicht gerade sinnvoll, weil die Reihenfolge halt verändert wird. Kann zwar auch sein, dürfte aber eher selten der Fall sein.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
014
21.05.2004, 13:51 Uhr
Windalf
Der wo fast so viele Posts wie FloSoft...
(Operator)


Ich danke für diese ausführliche erklärung...
ich werd dann beim vector bleiben... über die dateigrösse kann ich eine gute abschätzung machen wieviele records ich in den vector ballern werde...
dazu noch eine frage... ist es dann besser den reserve tendenziell zu gross zu wählen (würd ich jetzt so machen) oder lieber zu klein?
--
...fleißig wie zwei Weißbrote
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
015
21.05.2004, 13:53 Uhr
virtual
Sexiest Bit alive
(Operator)


Jedes reserve kostet im Verhältnis unendlich viel Rechenzeit. Wenn Du es Dir vom Speicher her leisten kannst, reserviere im Zweifel zuviel.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
016
21.05.2004, 14:25 Uhr
virtual
Sexiest Bit alive
(Operator)


Hm, das finde ich dann aber schon recht deftig:

C++:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <set>
#include <list>
#include <vector>
#include <algorithm>

#define ANZAHL 1000000


// *** Zeitmessung - nicht portabel (Linux only)

#include <sys/time.h>
#include <unistd.h>

class StopWatch
{
    struct timeval start_time;
    struct timeval end_time;

public:
    StopWatch() { clear(); }
    void clear() { timerclear(&start_time); timerclear(&end_time); }
    void start() { gettimeofday(&start_time, NULL); }
    void stop() { gettimeofday(&end_time, NULL); }
    unsigned long elapsed_time() const { return end_time.tv_usec-start_time.tv_usec+(end_time.tv_sec-start_time.tv_sec)*1000000; }
};

// *** Set - test

void set_test()
{
    StopWatch stopWatch;
    std::set<int> c;

    stopWatch.start();
    for(int i=0; i<ANZAHL; ++i)
    {
        c.insert(rand());
    }
    stopWatch.stop();
    std::cout<<"set: "<<stopWatch.elapsed_time()<<std::endl;
}


void list_test()
{
    StopWatch stopWatch;
    std::list<int> c;

    stopWatch.start();
    for(int i=0; i<ANZAHL; ++i)
    {
        c.push_back(rand());
    }
    c.sort();
    c.erase(std::unique(c.begin(), c.end()), c.end());

    stopWatch.stop();
    std::cout<<"list: "<<stopWatch.elapsed_time()<<std::endl;
}

void vector1_test()
{
    StopWatch stopWatch;
    std::vector<int> c;

    stopWatch.start();
    for(int i=0; i<ANZAHL; ++i)
    {
        c.push_back(rand());
    }
    std::sort(c.begin(), c.end());
    c.erase(std::unique(c.begin(), c.end()), c.end());

    stopWatch.stop();
    std::cout<<"vector (ohne reserve): "<<stopWatch.elapsed_time()<<std::endl;
}

void vector2_test()
{
    StopWatch stopWatch;
    std::vector<int> c;

    stopWatch.start();
    c.reserve(ANZAHL);
    for(int i=0; i<ANZAHL; ++i)
    {
        c.push_back(rand());
    }
    std::sort(c.begin(), c.end());
    c.erase(std::unique(c.begin(), c.end()), c.end());

    stopWatch.stop();
    std::cout<<"vector (mit reserve): "<<stopWatch.elapsed_time()<<std::endl;
}


int main()
{
    set_test();
    list_test();
    vector1_test();
    vector2_test();
}



Ergibt bei mir:

Code:
set: 9205927
list: 11318925
vector (ohne reserve): 1674609
vector (mit reserve): 1786227


Also ich hätte auf einen geringeren Abstand zwischen set/list und vector getippt und vor allem hätte ich gedacht, daß das reserve was bringt.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
017
21.05.2004, 14:44 Uhr
0xdeadbeef
Gott
(Operator)


Hm. Das ist mal seltsam - set ist ja intern ein RB-Baum, sollte also beim einfügen mit log(n) skalieren; quicksort dagegen mit n*log(n). Macht das Umhängen der Pointer wirklich so viel aus?
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
018
21.05.2004, 15:35 Uhr
Windalf
Der wo fast so viele Posts wie FloSoft...
(Operator)


für die die es auch mal unter windows probieren wollen die stopuhr z.b. so abändern...
der schmeisst das jetzt in ms aus...

C++:
#include <windows.h>

class StopWatch
{
    LONGLONG CurrentTime, LastTime;
    double TimeScale;
    
public:
    StopWatch() { clear(); }
    void clear() {
        LONGLONG Frequency;
        QueryPerformanceFrequency( (LARGE_INTEGER*) &Frequency);
        TimeScale = 1.0/Frequency;
    }
    void start() { QueryPerformanceCounter( (LARGE_INTEGER*) &LastTime);}
    void stop() { QueryPerformanceCounter( (LARGE_INTEGER*) &CurrentTime); }
    unsigned long elapsed_time() const { return (CurrentTime-LastTime)*1000*TimeScale; }
};



auf nem amd 1200 komm ich auf folgendes

set: 8472
list: 51444
vector (ohne reserve): 2813
vector (mit reserve): 2215

werte wie gesagt in ms
--
...fleißig wie zwei Weißbrote
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
019
21.05.2004, 15:36 Uhr
Windalf
Der wo fast so viele Posts wie FloSoft...
(Operator)


was mich bei virtual stark wundert ist das der vector mit reserve langsamer ist *kopfkratz* kann mir das einer erklären?
--
...fleißig wie zwei Weißbrote
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: [ 1 ] > 2 < [ 3 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: