INF 295 Algoritmer og datastrukturer Forelesning 10 Invarianter og Hashing Hans Fr. Nordhaug (Ola Bø)
Invarianter I mange algoritmer er det vilkår som forblir uforandret mens algoritmen kjøres Slike vilkår kalles invarianter Det er nyttig å kjenne igjen invarianter for å forstå algoritmen Invarianter kan også brukes under feilsøking For algoritmen som setter inn en ny node i et søketre er invarianten vilkåret for søketrær, nemlig at for hver node skal alle noder i dens venstre subtre ha lavere verdi og alle noder i dens høyre subtre ha høyere verdi
Invarianter Invarianten er ikke nødvendigvis sann for hver programsetning, men må stemme for hver gang programmet kommer til et gitt punkt.
Hash-tabell-ADT Færre operasjoner enn binært søketre Hashing er en teknikk for innsetting, søking og sletting i konstant tid Men findMin, findMax og printSorted støttes ikke i lineær tid Hashtabell kan implementeres på ulike måter Sammenlikning av implementeringer Vise applikasjoner Sammenlikning med binære søketrær
Hash-tabell Array med konstant størrelse Instansene vi søker etter lagres i tabellen Vanligvis blir søk basert på en eller flere instansvariable Det vi søker på kalles nøkkel Eksempel: Ansatt(Navn, Adresse, Fødselsnummer,Avd, Lønn,..) TableSize Fra nøkkelen beregnes et bestemt tall mellom 0 og TableSize-1. Dette tallet avgjør hvor instansen lagres Beregningen er en funksjon - en hash-funksjon
Hash-funksjonen Indeks=Hash(nøkkel) Bør være enkel (rask) å beregne Bør ideelt plassere instansene i hver sin celle Vanskelig å oppnå Vi søker funksjoner som gir jevn spredning av nøklene Hva vi må forholde oss til Hvordan velge hash-funksjonen Hva om to nøkler hashes til samme celle? Hvor stor bør Hash-tabellen være
Hash-funksjoner Standard hash-funksjon - der nøkkel er heltall Velge primtall som TableSize Hashfunksjonen er resten i divisjonen av nøkkel med TableSize. (nokkel%tableSize) Vanligvis er nøklene String Addere ascii (Unicode) verdiene for tegnene og deretter finne resten - ubrukelig Bruke bokstavverdiene som koeffisienter i et polynom og beregne verdien av polynomet for en gitt x Fungerer dårlig med bare de første bokstavene og x=27 Fungerer bra med alle bokstavene og x=29 Beregningen går fort med Horners regel
Hash-funksjoner
Java String sin Hash-funksjon
Kollisjonshåndtering med separat kjede Lage liste over alle elementer som hasher til samme celle Innsetting Finn nøkkel, Gjennomsøk lista, Duplikathåndtering Sett inn nye først - fordi sist innsatt ofte reaksesseres snart Andre alternativer: trær, ny hash - brukes vanligvis ikke Lastfaktor λ=elements/TableSize Gjennomsnittlig listelengde=lastfaktoren Regel: Ta sikte på lastfaktor=1 dvs: TableSize=antatt antall elementer
Kollisjonshåndtering med åpen adressering Ved kollisjon - prøv neste celle til du finner en ledig. Hva er neste celle? Avhenger av søkestrategien f(i) hi(x)=(hash(x)+f(i))%TableSize Alternativ til lenket liste: Kanskje raskere Enkelt med bare én datastruktur Lastfaktoren må være mindre: λ<0.5
Søkestrategier ved åpen adressering Lineær søking f(i) er en lineær funksjon. f. eks. f(i)=i Primær clustering av elementer kan føre til kostbare søk Kvadratisk søking f(i) er en kvadratisk funksjon f. eks. f(i)=i 2 Kan svikte totalt hvis λ>0.5 Må ha odde TableSize - ellers kan vi få svikt lenge før λ=0.5 Sekundær Clustering Dobbel hashing F.eks f(i)=i*hash 2 (x) NB hash 2 (x) skal ikke kunne bli 0 Forslag: hash 2 (x)=R-(x mod R), der R er prim<TableSize Dekning er viktig
Lineær versus kvadratisk søking
Mer om åpen adressering Sletteproblemet: Kan ikke slette elementer Rehashing Ved stor lastefaktor blir hashtabellen lite effektiv eller kan svikte helt (kvadratisk søk) Løsning: Lag ny, minst dobbelt så stor tabell og hash alle elementene inn i den nye tabellen Kostbar, men sjelden operasjon Problem hvis del av interaktivt system Når startes det? Halvfull tabell ved kvadratisk søking Når innsetting mislykkes På en bestem lastefaktor
Anvendelser Kompilatorer - symboltabeller Spill - transposisjonstabeller Stavekontroll I databaser
Konklusjon Hashtabell er bedre enn søketre på finn og sett inn Ved mistanke om sorterte inndata bør du absolutt velge Hashtabell - Hvorfor? Hashtabell er ubrukelig på traversering og findMin Viktige momenter for hashtabeller Hashfunksjonen må gi god spredning og full dekning med de aktuelle nøklene TableSize må være primtall Lastfaktoren λ er avgjørende for ytelsen Strategi for kollisjonshåndtering Åpen adressering er svært følsom for λ og kan få clustering-problemer Kjedet implementering tåler høyere λ, men er kanskje mer komplisert