Avatar billede anykey Nybegynder
21. januar 2005 - 16:18 Der er 21 kommentarer

Point's hashCode-metode

Jeg har lavet en klasse Cell, der på samme måde som Point-klassen gemmer en værdi x og y. Yderligere har jeg et HashSet, der som bekendt ikke tillader to objekter, der returnerer samme hashCode(), at være indeholdt i Set'et.

Problemet er nu følgende: Hvordan sikrer jeg at mit hashset ikke indeholder to cell-objekter, der har samme x og y værdi?.

Løsningen burde jo blot være at overskrive hashCode()-metoden i min Cell-klasse, men det kræver, at jeg finder en måde at beregne et unikt ID udelukkende ud fra cellens x og y værdier, velatmærke på en sådan måde, at ingen anden celle med andre x og y værdier kan have samme ID.
Naivt kunne man konstruere følgende hashCode()-metode:

public int hashCode(){
    return x+y;
}

Anvender vi denne metode, kan vi med få eksempler se, at den ikke duer. Beregner vi hashCode() får følgende punkter får vi så:
(2,3):5, (5,4):9, (1,3):4, (1,4):5

Vi ser straks, at hashCode()-værdien for det første og sidste punkt er den samme, selvom de har forskellige koordinatsæt.

Jeg efterlyser altså en hashCode()-metode, der fungerer, så ingen punkter med forskellige koordinatsæt kan give den samme hash-værdi!
Måske er løsningen enkel.. jeg har nemlig lagt mærke til, at Point-objekter, der har det samme koordinatsæt (x,y) returnerer den samme hashCode. Hvordan gør Point-klassen dette?
Avatar billede jakoba Nybegynder
21. januar 2005 - 16:39 #1
class Cell {
    private static int cellenummer = 0;
    private static final int MAX_ANTAL_CELLER = 1000;  // eller hvormange du synes
    private x, y;
    public Cell ( int x, int y ) {
        cellenummer++;        // ændres ingen andre steder
        this.x = zx;
        this.y = y;
    }
    public long hashcode() {
        return ((long)x*y*1000)+cellenummer;
    }
    ...

mvh JakobA
Avatar billede jakoba Nybegynder
21. januar 2005 - 16:41 #2
Ups. det skulle have været:
        return ((long)x*y*MAX_ANTAL_CELLER)+cellenummer;
Avatar billede anykey Nybegynder
21. januar 2005 - 16:42 #3
jakoba> Jeg har også tænkt på den metode, men programmet skal kunne håndtere et vilkårligt antal celler, og må derfor kun beregne hashCode()'en ud fra x og y...
Avatar billede anykey Nybegynder
21. januar 2005 - 16:44 #4
jakoba> Ved du, hvordan Point-klassen gør? Bruger den et MAX for objektantallet?
Avatar billede rasmusbg Nybegynder
21. januar 2005 - 16:46 #5
java.awt.Point:

public int hashCode() {
    long bits = java.lang.Double.doubleToLongBits(getX());
    bits ^= java.lang.Double.doubleToLongBits(getY()) * 31;
    return (((int) bits) ^ ((int) (bits >> 32)));
}
Avatar billede anykey Nybegynder
21. januar 2005 - 16:53 #6
rasmusbg: tak - umiddelbart forstår jeg dog ikke helt præcist, hvordan hashCode'en beregnes, men kan du forsikre mig om, at der ikke findes to koordinatsæt (x,y), der kan returnere den samme hashCode() med den metode?
Avatar billede rasmusbg Nybegynder
21. januar 2005 - 16:55 #7
Anykey: Nej - desværre...men jeg er lige igang med at udforske det lidt. ;)
Avatar billede anykey Nybegynder
21. januar 2005 - 17:02 #8
rasmusbg> Umiddelbart siger min intuition mig, at der GODT kan være to punkter, der returnerer den samme hashCode, men med de operationer, de laver på tallene x og y, ser det ud som om, at det er utroligt sjældent at det sker.... det vil jeg så overveje om jeg kan leve med .. hehe.. hvis du vil have nogle points må du lige smide et svar
Avatar billede jakoba Nybegynder
21. januar 2005 - 17:04 #9
det var egentlig også en fjoget måde at gøre det. En nemmere og enklere måde er:
class Cell {
    private static int cellenummer = 0;
    private x, y;
    public Cell ( int x, int y ) {
        cellenummer++;        // ændres ingen andre steder
        this.x = zx;
        this.y = y;
    }
    public long hashcode() {
        return cellenummer;
    }
    ...

nu kan du lave 2^32 celler og de vil allesammen have forskellig 'hashkode'.
Avatar billede anykey Nybegynder
21. januar 2005 - 17:09 #10
jakoba> Jeg tror, du har misforstået mig lidt.... det er ret væsentligt at to Celler, der har samme koordinatsæt ikke er indeholdt i mit HashSet. Din metode er jo ikke bedre end den hashCode()-metoden, der nedarves efter Object(), som jo beregner hash-værdien ud fra den enkelte instans adresse(mener jeg da), og derfor også gør alle celler unikke... Jeg håber, du forstår
Avatar billede rasmusbg Nybegynder
21. januar 2005 - 17:12 #11
Jakoba - den dur bare ikke så godt.

Man må formode, at hvis der laves to Celle objekter (kald dem celle1 og celle2), hvor de begge har (x,y) sat til det samme (f.eks. (2,3)), så er de ens, derfor burde celle1.equals(celle2) returnere true. Ifølge Java's definition af hashCode(), så SKAL celle1.hashCode() == celle2.hashCode().
Med din hashCode() vil dette ikke være tilfældet.

Desværre kan jeg ikke overbevise mig selv rent matematisk om, at Point's hashCode rent faktisk returnerer en unik hashkode hver eneste gang - der bliver jeg nødt til at stole på Sun's udvikler-team ;)
Avatar billede jakoba Nybegynder
21. januar 2005 - 17:19 #12
Ups, ja der var jeg helt gal på den.
så bliver det vel noget i retning af:
    public long hashcode() {
        return (long)x<<32 +(0xFFFFFFFFL & y);
    }
Avatar billede anykey Nybegynder
21. januar 2005 - 17:20 #13
rasmusbg: jeg stoler ikke på solskinsgutterne før jeg har set et matematisk bevis, men indtil videre forlader jeg mig på deres autoritet (Hehe). Jeg har dog stadig i sinde at sende problemet videre til min matematiklærer... Jeg takker dog stort alligevel (-:
Avatar billede anykey Nybegynder
21. januar 2005 - 17:21 #14
jakoba> vil den være unik for vilkårlige koordinatsæt?
Avatar billede erikjacobsen Ekspert
21. januar 2005 - 17:25 #15
Der skal gælde 2 ting for din klasse:

1) Din hashcode skal aflevere nogenlunde pænt fordelte tal. Der må gerne være ens
  hashværdier for forskellige x og y
2) Du *skal* også definere equals()-funktionen - den bliver nemlig kaldt hvis der
  er to hashværdier der er ens.

Det er naturligvis bedst at få fordelt hashværdierne så godt som muligt, men det
er ikke nødvendigt, og yderst sjældent at man kan sikre de er unikke.

...bare til evt. afklaring ...
Avatar billede jakoba Nybegynder
21. januar 2005 - 17:40 #16
men nu jeg læser grundigt så fatter jeg alligevel ikke.
Er du 100% på at et hashset ikke tillader 2 objekter med samme hashcode at være indeholdt i settet?
Hele fidusen med hashkoder er jo at de ikke behøver at være unikke, bare de er rimeligt spredt.
Avatar billede erikjacobsen Ekspert
21. januar 2005 - 17:52 #17
Det er også det jeg siger, jakoba ;)

3) Hashfunktionen skal hellere være effektiv, end sikre højst mulig spredning.
  Den kaldes tit!
Avatar billede anykey Nybegynder
21. januar 2005 - 21:44 #18
erikjacobsen> Jeg har skam overskrevet equals()-metoden i min Cell-klasse. hashCode() og equals-funktioner er som følger:

public boolean equals(Object o){
        if(o == this) return true;
        if(o == null) return false;
        if(getClass()!=o.getClass()) return false;
        Cell c = (Cell)o;
        return (c.x==x && c.y==y);
    }

public int hashCode() {
        long bits = java.lang.Double.doubleToLongBits(x);
        bits ^= java.lang.Double.doubleToLongBits(y) * 31;
        return (((int) bits) ^ ((int) (bits >> 32)));
}

Det, du siger omkring kravene til hashCode() er også enormt fornuftigt. Du har selvfølgelig ret i, at det er vigtigt, at den er spredt således, at equals() næsten aldrig bliver kaldt. Samtidig vil equals jo sikre, at der aldrig er nogen ens koordinatsæt i mit hashset, så det er jo alletiders. Jeg betragter mit problem som løst (-:

erikjacobsen og rasmusbq smid lige et svar, så deler jeg pointene ud...
Avatar billede anykey Nybegynder
21. januar 2005 - 21:49 #19
og med hensyn til, at den skal være effektiv betyder det ikke det store... mit codesnippet er nemlig ikke helt korrekt.. jeg tilskriver den som final i konstruktøren, da både x og y er final for hver celle... (-: Jeg takker endnu en gang
Avatar billede erikjacobsen Ekspert
21. januar 2005 - 21:56 #20
Fint nok du har styr på det - så håber jeg fremtidige læsere også kan få lidt gavn af det.
Men jeg samler slet ikke på point, tak.
Avatar billede rasmusbg Nybegynder
22. januar 2005 - 15:07 #21
Her kommer et svar.

Bedre sent end aldrig ;)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester