Hashing suche

Hallo zusammen,
hoffe ihr könnt mir helfen…

ich habe eine Hash klasse, die eine Methode hat die folgendes Tun soll :
Findet die Referenz zu dem Entry mit key oder gibt null zurueck.

Aber ich bin glaub ich in einer Endlosschleife gefangen und weiß nicht mehr weiter : D

hier die Methode :

        // TODO den richtigen Suchalgorithmus (direkte Verkettung) einsetzen.
    	/*if (key == null) {
            throw new NullPointerException();
        }
        
        int h = (key.hashCode() & 0x7FFFFFFF) & data.length;
        while (data[h] != null && !key.equals(data[h].key))
        { 
            h = (h+1) % data.length;
        }
        return data[h]  == null ? null : data[h];
        */
    	if(key == null)
    		throw new NullPointerException();
    	
    	int h = hash(key);
    	while(data[h] != null && !(key.equals(data[h].key)))
    		h = (h + 1) % data.length;
    	
    	return data[h];
    }```

und hier nocheinmal zum besseren verständnis die Klasse : 
```package util;

import util.Hashing.Entry;



/**
 * Die Klasse implementiert ein Verzeichnis, in dem nach
 * unter einem Schluessel gespeicherten Daten gesucht werden
 * kann.
 * <p>
 * Als Implementierungsmethode wird die Kollisionsbehandlung der
 * direkten Verkettung verwendet.
 */
public  class Hashing<K,V> implements IMap<K,V> {
	/**
     * Anzahl der gespeicherten Key-Value-Paare.
     */
    private int size = 0;
    
    /**
     * Feld mit den Daten.
     */
    @SuppressWarnings("unchecked")
    private Entry<K,V>[] data = new Entry[100];

    @Override
    public int size() {
		return size;
	}

    @Override
    public V put(K key, V value) {
		Entry<K,V> p = referenceOf(key);
		if (p == null) {
		    int index = hash(key);
			data[index] = new Entry<K,V>(key, value, data[index]);
		    size++;
			return null;
		}
		return p.setValue(value);
	}

    @Override
    public V get(K key) {
		Entry<K,V> p = referenceOf(key);
		return p == null ? null : p.value;
	}

    @Override
    public boolean containsKey(K key) {
        // TODO den richtigen Algorithmus einsetzen.
    	return referenceOf(key) != null;
    }    

    /**
     * Findet die Referenz zu dem Entry mit key oder gibt null zurueck.
     * @param key Suchschluessel
     * @return null oder Referenz auf gefundenen Entry.
     */
    private Entry<K,V> referenceOf(K key) {
        // TODO den richtigen Suchalgorithmus (direkte Verkettung) einsetzen.
    	/*if (key == null) {
            throw new NullPointerException();
        }
        
        int h = (key.hashCode() & 0x7FFFFFFF) & data.length;
        while (data[h] != null && !key.equals(data[h].key))
        { 
            h = (h+1) % data.length;
        }
        return data[h]  == null ? null : data[h];
        */
    	if(key == null)
    		throw new NullPointerException();
    	
    	int h = hash(key);
    	while(data[h] != null && !(key.equals(data[h].key)))
    		h = (h + 1) % data.length;
    	
    	return data[h];
    }

    private int hash(Object key) {
	    return key == null ? 0 : (key.hashCode() & 0x7fffffff) % data.length;
	}
	
	private static boolean safeEquals(Object a, Object b) {
        return a == null ? a == b : a.equals(b);
    }

    /**
	 * Klasse fuer die einzelnen Eintraege.
	 */
	static class Entry<K,V> {
	    private final K key;
	    private V value;
	    private Entry<K,V> link;

	    /**
	     * Konstruktor.
	     * 
	     * @param key Schluesselbegriff.
	     * @param value eigentlicher Inhalt.
	     */
	    Entry(K key, V value, Entry<K,V> link) {
	        this.key = key;
	        this.value = value;
	        this.link = link;
	        
	    }
	    
	    /**
	     * Veraendert den Inhalt des Eintrags und gibt den ueberschriebenen
	     * Inhalt zurueck.
	     * 
	     * @param value neuer Inhalt.
	     * @return vorhergehender Inhalt.
	     */
	    V setValue(V value) {
	        V oldValue = this.value;
	        this.value = value;
	        return oldValue;
	    }
	    
	    @Override
	    public String toString() {
	        return key + ":" + value;
	    }
	}
}```


hoffe jemand weiß rat

Tja, wenn nichts gefunden wird, dann ist das eine Endlosschleife…Warum gehst du da zyklisch vor? Warum nicht einfach von 1 bis data.length?

danke schon mal für die Antwort.

wie meinst du das genau?

einfach eine For-Schleife reinknallen die von 1 bis data.length läuft ?

[QUOTE=Unregistriert]danke schon mal für die Antwort.

wie meinst du das genau?

einfach eine For-Schleife reinknallen die von 1 bis data.length läuft ?[/QUOTE]
was spricht dategen? ich meinte übrigens 0…data.length-1

Meintest du das so :

    for (Entry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k))))
            return e;
    }
    return null;```

Ach entschuldigung falscher Code

meinte diesen hier : ```if(key == null)
throw new NullPointerException();

	int h = hash(key);
	/*while(data[h] != null && !(key.equals(data[h].key)))
		h = (h + 1) % data.length;
	*/
	for(int i = 0;i<data.length;i++)
	{
		h=i%data.length;
		if(data[h]!=null && !(key.equals(data[h].key)))
			return data[h];
	}
	return null;```

Der Witz an einer solchen HashMap ist ja, dass der Zugriff in O(1) erfolgt. Du brauchst gar keine Schleife. Berechne den Hashwert des angeforderten Keys, schaue in einem Array nach ob es da einen Eintrag gibt. Wenn ja gibst du den zurück, wenn nicht dann gibst du null zurück.

Jetzt Blick ich garnicht mehr durch ^^ überall wo ich geguckt habe benutzt jeder so eine While Schleife wie ich sie am anfang hatte…
sogar mit ähnlichen Argumenten. Aber irgendwie Funktioniert es nicht -.- Ich glaub der Hashwert stimmt ja aber wie ich weiter machen soll hab ich keine Ahnung : (

[QUOTE=tealino]Ach entschuldigung falscher Code

meinte diesen hier : ```if(key == null)
throw new NullPointerException();

	int h = hash(key);
	/*while(data[h] != null && !(key.equals(data[h].key)))
		h = (h + 1) % data.length;
	*/
	for(int i = 0;i<data.length;i++)
	{
		h=i%data.length;
		if(data[h]!=null && !(key.equals(data[h].key)))
			return data[h];
	}
	return null;```[/QUOTE]

Was soll die Zeile mit h=i%data.length, du sollst

if(data**!=null && !(key.equals(data**.key)))

schreiben

Achso ok aber irgendwie haut das immer noch nicht hin:

    	for(int i = 0;i<data.length;i++)
    	{
    		if(data**!=null && !(key.equals(data**.key)))
    			return data[h];
    		
    	}
    	return null;
    }

    private int hash(Object key) {
	    return key == null ? 0 : (key.hashCode() & 0x7fffffff) % data.length;
	}```

Umpf, sorry

Ich glaube ich kapier nicht ganz, wie die Suche genau ablaufen soll:

Also das data-Array ist ein int-Array, da können maximal 100 Einträge rein

du verwendest einen hash-code als index für das Array, der Array-Eintrag verweist auf einen [edit] VALUE

Jetzt hast du einen key gegeben.

Dann berechnest du h=hash(key)

dann ist entweder data[h] null (wenn noch nichts da)

oder data[h].key ist der key => dann sollst du data[h] zurückgeben

dazu brauchst du doch gar keine Schleife???

Ist das die Situation? Sorry das ich das vorher nicht ganz genau gelesen habe

ja klar muss natürlich bei return data** nehmen aber dann brauch ich ja nirgends das hash. Das muss doch irgendwie vorkommen : (

Ja genau so soll es sein. nur lese ich überall was anderes : ( Aber überall wird eine While Schleife benutzt deshalb weiß ich nicht ganz wie ich es ohne Schleife schreiben soll -.-

Was genau ist überall? Was ist das eigentlich für eine Aufgabe?

Ist eine Schulaufgabe wo ich angegebene Methoden Vervollständigen muss.
Bei Google oder Beispielen wird meistens eine Whileschleife benutzt…

Also die Klasse habe ich ja bereits oben gepostet ich muss halt nur diese referenceof Methode vervollständigen.
Aber ich bekomm es einfach nicht hin.

while(key == null ? key == data[h] : key.equals(data[h]))
    		h = (h+1)% data.length;
    	return data[h];
    }

    private int hash(Object key) {
	    return key == null ? 0 : (key.hashCode() & 0x7fffffff) % data.length;
	}

Soo bin jetzt schon mal weiter gekommen glaube ich ^^

aber die Kollisionsbehandlung ist noch nicht richtig …

du brauchst keine while schleife


        if (key == null) {throw new NullPointerException();} // kann man machen
       
        int h = (key.hashCode() & 0x7FFFFFFF) & data.length; // gut, genauso wird h berechnet

        if (null==data[h]) return null; // wenn nix da, nix zurück

        if(key.equals(data[h].key)) return data[h]; // treffer

        return null;

Hmm ja verstehe ich danke : )

Problem ist nur das ich immer noch eine Fehlermeldung bekomme: Collisionhandling NullPointerException -.-

Die Sache ist die das ein JUnit Test nebenbei läuft der so Aussieht:

        for (int i = 0; i < RANDOM_TESTS; i++)
            objTable.put(String.valueOf(i), Double.valueOf(i));
        for (int i = 0; i < 1000; i++)
            assertEquals(i, objTable.get(String.valueOf(i)).intValue());
    }

der meckert bei assertEquals(i,obj…

Aber danke für deine Mühe… Aber keine Ahnung warum der so Reagiert.
Heißt das das der nur eine Null bekommt und deshalb aussteigt?

Schreibe ich die Methode so wie beschrieben in meinem letzeren Post dann sagt er statt NullPointException : Expectet 0 but was 914

In deiner ersten Klasse war

new Entry[100];

das Array zu klein für 1000 Einträge…