Suchfunktion optimieren?



  • An BorisDieKlinge:
    Ups, mit dem boFound hast du Recht.



  • an der eigentlich structur kann ich nicht ändern..wenn ich sie ändere, werden es genausviel iterationen bzw. vergleiche sein! Der Flaschenhals liegt an dem strcmp..

    vll. merk ich mir bei jedem eintrag noch die länge des eintrags und versuchem mal memcmp... vll. ist das dann schneller..



  • BorisDieKlinge schrieb:

    an der eigentlich structur kann ich nicht ändern..wenn ich sie ändere, werden es genausviel iterationen bzw. vergleiche sein! Der Flaschenhals liegt an dem strcmp..

    vll. merk ich mir bei jedem eintrag noch die länge des eintrags und versuchem mal memcmp... vll. ist das dann schneller..

    Naja, es gibt auch sortierte Baumstrukturen, wo bei jeder Iteration eine ganze Reihe von alternativen Pfaden wegfallen, wodurch die Suche ordentlich beschleunigt wird. Man kann also durch strukturänderungen schon ordentlich was ereichen.



  • BorisDieKlinge schrieb:

    was mir aufgefallen ist, das die erste suche in den tabel 25ms geht, wenn ich dann wieder neu beginne gehst unter <1ms.. ?? kann es sein das er sich durch die erste suche erst die tabellen im speicher anlegt?

    testest du das ganze etwa unter unter windoofs? wenn ja, dann brauchst du dich wegen der falschen messwerte nicht zu wundern. das OS mit multitasking, virtual memory und paging/caching etc. verhindern jede genaue messung.
    wenn strcmp die bremse ist, dann such anders. erzeuge vorher eine eindeutige ID für jeden string und speichere diese sortiert ab usw.
    btw, das mit dem flag ist doof. die goto-variante ist besser.
    🙂



  • erzeuge vorher eine eindeutige ID für jeden string und speichere diese sortiert ab usw.

    wie soll das funktionieren?



  • BorisDieKlinge schrieb:

    erzeuge vorher eine eindeutige ID für jeden string und speichere diese sortiert ab usw.

    wie soll das funktionieren?

    Schon mal was von Hashing-Algorithmen gehört?



  • BorisDieKlinge schrieb:

    erzeuge vorher eine eindeutige ID für jeden string und speichere diese sortiert ab usw.

    wie soll das funktionieren?

    ok, 'eindeutig' war etwas übertrieben, aber fast eindeutig, mit sogenannten hashwerten. dann brauchst du nur zwei integers zu vergleichen und nicht mehr mit strcmp die bytes einzeln absuchen.
    http://www.cse.yorku.ca/~oz/hash.html
    🙂



  • ist das sowas wie checksummenberechnung? durch nen algo. nen wert für nen string berechnen.. aber diese werte sind ja nich unbeding eindeutig;)



  • BorisDieKlinge schrieb:

    aber diese werte sind ja nich unbeding eindeutig

    aber fast. http://en.wikipedia.org/wiki/Hash_collision
    🙂



  • @fricky: darf ich fragen wie lange du schon programmierst, und wie alt du bist?



  • BorisDieKlinge schrieb:

    @fricky: darf ich fragen wie lange du schon programmierst, und wie alt du bist?

    äääh ja, äääh nein, äääh wieso?
    🙂



  • ja nur so, weil du es anscheinend drauf hast;)



  • mmh, und wenn Du vor dem strcmp einfach das erste byte prüfst?

    char *str = "Hallo";
    char *vgl = "welt";
    
    if(str[0]==vgl[0]) {
    
    if(strcmp(str,vgl)) {
    
    }
    
    }
    

    Damit hast Du schonmal eine Menge strcmp rausgenommen. Wenn Du die ersten 2 Bytes testest, sind es noch weniger usw.



  • BorisDieKlinge schrieb:

    ja nur so, weil du es anscheinend drauf hast

    danke, aber das ist zuviel der ehre. den tip mit dem hashwert hätte dir jeder zweite, regelmässige forenuser hier geben können.

    fdsfsafa schrieb:

    mmh, und wenn Du vor dem strcmp einfach das erste byte prüfst?

    strcmp wird wohl auch abbrechen, wenn das erste byte nicht stimmt. das spart höchstens den funktionsaufruf.

    @boris: aber mach doch mal 'nen profilerlauf. vielleicht liegts ja gar nicht am strcmp.
    🙂



  • nene, es an strcmp.. ist ja die einzigste funktion welche "was tut" der sind ja nur verschachtelte schleifen..1 Aber das zufrieden bist : Ohne strcmp oder memcmp geht im faktor 20 schneller.. 😉



  • Naja an strcmp an sich liegt es aber nicht. Wenn du halt Strings verlgeichen musst, dann musst du Strings vergleichen, und das dauert eben.
    Wie schon gesagt, du könntest über Hashing und dem Vergleichen der Hash-Werte bestimmt noch was rausholen an Performanz. Ansonsten wie auch schon gesagt, evtl. nochmal die ganzen Strukturen irgendwie umändern.

    Bei strcmp wäre die einzigste Möglichkeit die ich sehe, dass du dir evtl. deine eigene strcmp-Funktion als Makro schreibst und da halt auf jede Sicherheitsüberprüfung verzichtest. Wobei ich glaube, dass das bei strcmp auch nicht anders ist und das schon hochperformant implementiert ist. Aber ka, ewig lang her, dass ich was mit C Funktionen gemacht hab 😉
    Und da bezweifle ich mal stark, dass du überhaupt nen Unterschied wirst messen können.



  • Als Anreiz, lässt sich ja nach C übertragen, war mir jetzt aber zuviel Arbeit:

    char createRandomChar()
    {
    	// 40 - 125
    	return 40 + (rand()%86);
    }
    
    string createRandomString()
    {
    	int len = rand() % 100;
    	string s( len, 'a' );
    	for ( int i=0; i<len; i++ )
    		s[i] = createRandomChar();
    	return s;
    }
    
    class Container1
    {
    	public:
    		bool hasElem( const string& s ) const
    		{
    			for ( size_t i=0; i<arr.size(); i++ )
    				if ( arr[i] == s )
    					return true;
    			return false;
    		}
    
    		void operator+=( const string& s )
    		{
    			arr.push_back( s );
    		}
    
    	private:
    		vector<string> arr;
    };
    
    class Container2
    {
    	public:
    		bool hasElem( const string& s ) const
    		{
    			std::map<unsigned int,vector<string>>::const_iterator i = arr.find( hash(s) );
    			if ( i == arr.end() )
    				return false;
    			for ( size_t j=0; j<i->second.size(); j++ )
    				if ( i->second[j] == s )
    					return true;
    			return false;
    		}
    
    		void operator+=( const string& s )
    		{
    			arr[hash(s)].push_back( s );
    		}
    
    	protected:
    		static unsigned int hash( const string& s )
    		{
    			// algo von http://www.cse.yorku.ca/~oz/hash.html
    			unsigned long hash = 5381;
    			int c;
    			const char* str = s.c_str();
    			while (c = *str++)
    				hash = ((hash << 5) + hash) + c;
    			return hash;
    		}
    
    	private:
    		std::map< unsigned int, vector<string> > arr;
    };
    
    int main()
    {
    	srand( time(NULL) );
    
    	Container1 c1;
    	Container2 c2;
        // Beide Container mit 1 Mio strings füllen
    	for ( int i=0; i<1000000; i++ )
    	{
    		string s = createRandomString();
    		c1 += s;
    		c2 += s;
    	}
    
        // 100 mal linear suchen => 9 sec
    	time_t t = time( NULL );
    	for ( int i=0; i<100; i++ )
    		cout << c1.hasElem( createRandomString() ) << " ";
    	cout << endl << time(NULL)-t << endl;
    
        // 50.000 mal suchen => 3 sec
    	t = time( NULL );
    	for ( int i=0; i<50000; i++ )
    		cout << c2.hasElem( createRandomString() ) << " ";
    	cout << endl << time(NULL)-t << endl;
    
        // edit: das meiste der Zeit geht eins drüber die Ausgabe drauf, deshalb mal ohne viel Ausgabe:
        t = time( NULL );
    	int v = 0;
        // edit 2: Mit 5.000.000 Durchläufen 14 sec
    	for ( int i=0; i<5000000; i++ )
    	{
    		if ( c2.hasElem( createRandomString() ) )
    			v++;
    	}
    
    	cout << v << endl << time(NULL)-t << endl;
    }
    

    In "Container2" wird auf jeden vorkommenden hash-Wert ein string-Array gemappt. Zuerst wird der Hashwert vom zu suchenden String ermittelt, dann in dem entsprechenden Container (wo nur Strings mit diesem Hashwert sitzen) gesucht.

    edit3: In Container2 wirkt sich die Hashfunktion auch maßgeblich auf den Speicherverbraucht aus, bei mir bei obigen Werten zwischen 100 MB und 250 MB Verbrauch - ist ja auch logisch, sitzt beinahe jeder String einzeln in einem vector, wird eine Ecke mehr Speicher benötigt weil es eben mehr vectoren gibt..



  • Badestrand schrieb:

    std::map<unsigned int,vector<string>>::const_iterator i = arr.find( hash(s) );
    

    igitt, das ist ja gruselig. mach das weg!
    🙂



  • fricky schrieb:

    Badestrand schrieb:

    std::map<unsigned int,vector<string>>::const_iterator i = arr.find( hash(s) );
    

    igitt, das ist ja gruselig. mach das weg!
    🙂

    Joar, schön sieht das nicht aus. Ohne die Zeile funktioniert's aber nicht und ich hatte keine Lust zu typedef'en.



  • Badestrand schrieb:

    fricky schrieb:

    Badestrand schrieb:

    std::map<unsigned int,vector<string>>::const_iterator i = arr.find( hash(s) );
    

    igitt, das ist ja gruselig. mach das weg!
    🙂

    Joar, schön sieht das nicht aus. Ohne die Zeile funktioniert's aber nicht und ich hatte keine Lust zu typedef'en.

    hehe, ich meinte eigentlich das ganze programm. im c++ forum wärst du damit der held, aber hier kann man fast nix mit anfangen. wozu überhaupt lauter 'vectors' in der map? würde es nicht auch mit 'string' gehen?
    ansonsten: einfach mal googlen: hashmap filetype:c. da findeste einiges, ganz ohne dieses c++ geraffel, was wahrscheinlich noch schneller ist.
    🙂


Anmelden zum Antworten