Hashing Bakom kulisserna på Pythons dictionary Innehåll Några förenklingar Leta i listor Olika ideer om hashing I python förr Och nu DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 1 / 32
Några förenklingar I början av den här diskussionen kommer jag titta enbart på listor som innehåller numeriska värden. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 2 / 32
Några förenklingar I början av den här diskussionen kommer jag titta enbart på listor som innehåller numeriska värden. I normalfallet håller ingen reda på en massa tal utan snarare en informationspost som identifieras av ett nyckelvärde, där nyckelvärdet kan vara alltifrån ett tal till vilken komplicerad struktur som helst, bara nyckelvärdet är unikt i sammanhanget (eller nästan unikt i vissa fall) DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 2 / 32
Några förenklingar I början av den här diskussionen kommer jag titta enbart på listor som innehåller numeriska värden. I normalfallet håller ingen reda på en massa tal utan snarare en informationspost som identifieras av ett nyckelvärde, där nyckelvärdet kan vara alltifrån ett tal till vilken komplicerad struktur som helst, bara nyckelvärdet är unikt i sammanhanget (eller nästan unikt i vissa fall) Exemplen handlar om hur man letar i listor med meningsfull information men för enkelhetens skull reduceras de till att leta efter numeriska nyckelvärden. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 2 / 32
Några förenklingar I början av den här diskussionen kommer jag titta enbart på listor som innehåller numeriska värden. I normalfallet håller ingen reda på en massa tal utan snarare en informationspost som identifieras av ett nyckelvärde, där nyckelvärdet kan vara alltifrån ett tal till vilken komplicerad struktur som helst, bara nyckelvärdet är unikt i sammanhanget (eller nästan unikt i vissa fall) Exemplen handlar om hur man letar i listor med meningsfull information men för enkelhetens skull reduceras de till att leta efter numeriska nyckelvärden. Senare i diskussionen kommer vi titta på par nyckel, värde men inte mer komplicerat än så. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 2 / 32
Några förenklingar I början av den här diskussionen kommer jag titta enbart på listor som innehåller numeriska värden. I normalfallet håller ingen reda på en massa tal utan snarare en informationspost som identifieras av ett nyckelvärde, där nyckelvärdet kan vara alltifrån ett tal till vilken komplicerad struktur som helst, bara nyckelvärdet är unikt i sammanhanget (eller nästan unikt i vissa fall) Exemplen handlar om hur man letar i listor med meningsfull information men för enkelhetens skull reduceras de till att leta efter numeriska nyckelvärden. Senare i diskussionen kommer vi titta på par nyckel, värde men inte mer komplicerat än så. I verkligheten kan informationsposterna vara mycket komplicerade men det förändrar ingenting i sak i diskussionen DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 2 / 32
Osorterade listor Vi har redan tittat på hur man letar i listor (i Scheme). Leta i en osorterad lista (L) i Python(3): def unsortedsearch(key, L): Pre: L är en lista med bara heltal och key är ett heltal. Post: find återsänder platsen där key finns eller None om key inte finns i listan L for index in range(len(l)): if L[index] == key: return index return None DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 3 / 32
Osorterade listor Vi har redan tittat på hur man letar i listor (i Scheme). Leta i en osorterad lista (L) i Python(3): def unsortedsearch(key, L): Pre: L är en lista med bara heltal och key är ett heltal. Post: find återsänder platsen där key finns eller None om key inte finns i listan L for index in range(len(l)): if L[index] == key: return index return None En enkel algoritm, O (n) om n är listans längd. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 3 / 32
Sorterade listor Leta i en sorterad lista (L) i Python(3): def sortedsearch(key, L): Pre: L är en lista med bara heltal och key är ett heltal. Post: find återsänder platsen där key finns eller None om key inte finns i listan L for index in range(len(l)): if L[index] > key: return None elif L[index] == key: return index return None DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 4 / 32
Sorterade listor Leta i en sorterad lista (L) i Python(3): def sortedsearch(key, L): Pre: L är en lista med bara heltal och key är ett heltal. Post: find återsänder platsen där key finns eller None om key inte finns i listan L for index in range(len(l)): if L[index] > key: return None elif L[index] == key: return index return None Fortfarande en enkel algoritm, O (n) om n är listans längd. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 4 / 32
Sorterade listor Leta i en sorterad lista (L) i Python(3): def sortedsearch(key, L): Pre: L är en lista med bara heltal och key är ett heltal. Post: find återsänder platsen där key finns eller None om key inte finns i listan L for index in range(len(l)): if L[index] > key: return None elif L[index] == key: return index return None Fortfarande en enkel algoritm, O (n) om n är listans längd. Men om sökning är väldigt vanlig är det ändå en viktig förbättring. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 4 / 32
Jämförelse osorterad/sorterad lista Båda metoderna är O (n) så vi måste titta närmare. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 5 / 32
Jämförelse osorterad/sorterad lista Båda metoderna är O (n) så vi måste titta närmare. Om det man letar efter oftast finns i listan är det, i genomsnitt, ingen skillnad. Man tittar i genomsnitt igenom halva listan. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 5 / 32
Jämförelse osorterad/sorterad lista Båda metoderna är O (n) så vi måste titta närmare. Om det man letar efter oftast finns i listan är det, i genomsnitt, ingen skillnad. Man tittar i genomsnitt igenom halva listan. Om det man letar efter oftast inte finns i listan närmar man sig n i fallet med den osorterade listan medan man fortfarande ligger kvar på n/2 i en sorterad lista, förutsatt att det man letar efter är jämt fördelat i indexmängden. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 5 / 32
Jämförelse osorterad/sorterad lista Båda metoderna är O (n) så vi måste titta närmare. Om det man letar efter oftast finns i listan är det, i genomsnitt, ingen skillnad. Man tittar i genomsnitt igenom halva listan. Om det man letar efter oftast inte finns i listan närmar man sig n i fallet med den osorterade listan medan man fortfarande ligger kvar på n/2 i en sorterad lista, förutsatt att det man letar efter är jämt fördelat i indexmängden. Så om vi letar ofta efter nyckelvärden som kanske inte finns representerade i vår lista är det bättre att sortera. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 5 / 32
Leta i listor Metoder för sökning i sorterad lista Om listan är tillräckligt kort kan vi använda binärsökning (min variant): def binarysearch(key, L): left = 0 right = len(l) - 1 while left < right: mid = (left + right + 1) // 2 if key < L[mid]: right = mid - 1 else: left = mid if L[left] == key: return left else: return None DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 6 / 32
Leta i listor Metoder för sökning i sorterad lista... Ofta ser man följande variant, som är bra om det man söker efter oftast finns: def binarysearch(key, L): left = 0 right = len(l) - 1 while left < right: mid = (left + right + 1) // 2 if key == L[mid]: return mid if key < L[mid]: right = mid - 1 else: left = mid + 1 if L[left] == key: return left else: return None DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 7 / 32
Metoder för sökning i sorterad lista... Den första varianten är alltid O (2 log n ), den andra max 2 log n eftersom man då och då avbryter vid träff. Skillnaden är marginell men kan vara viktig i sökintensiva program. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 8 / 32
Metoder för sökning i sorterad lista... Den första varianten är alltid O (2 log n ), den andra max 2 log n eftersom man då och då avbryter vid träff. Skillnaden är marginell men kan vara viktig i sökintensiva program. Men..., listorna kan vara för långa, så långa att de inte ryms i minnet. De kan då splittras så att man i den första listan har adresser till andra listor, där man går vidare tills man hittar rätt. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 8 / 32
Leta i listor Metoder för sökning i sorterad lista... Den första varianten är alltid O (2 log n ), den andra max 2 log n eftersom man då och då avbryter vid träff. Skillnaden är marginell men kan vara viktig i sökintensiva program. Men..., listorna kan vara för långa, så långa att de inte ryms i minnet. De kan då splittras så att man i den första listan har adresser till andra listor, där man går vidare tills man hittar rätt. Här skissas endast idén som kommer från AI-området. Idén är genialisk och en sådan struktur (som kallas B-träd) hålls i balans (= alltid lika många operationer oavsett vad man söker efter), är sorterade och är extremt snabba att söka i. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 8 / 32
Skiss av B-träd... Den grundläggande idén är att det mest effektiva är att hantera listor som ryms i ett block på sekundärminnet och som organiseras så att DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 9 / 32
Leta i listor Skiss av B-träd... Den grundläggande idén är att det mest effektiva är att hantera listor som ryms i ett block på sekundärminnet och som organiseras så att listorna innehåller nyckelvärden och adresser till motsvarande informationspost: 56 87 96 till nästa löv till post med nyckel 56 till post med nyckel 87 till post med nyckel 96 Lövnod DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 9 / 32
Skiss av B-träd... 27 56 103 K < 27 27 <= K < 56 56 <= K < 103 K >= 103 Inre nod Eftersom lagom längd på en lista är så mycket som ryms i ett sekundärminnesblock kan man lätt räkna ut hur mycket som ryms. Adressen till ett minnesblock är (med 64-bits-ord) 8 byte lång och antar man att en nyckel är 8 byte lång (räcker t.ex. för ett personnummer) så får man antalet nycklar i en nod till n 8 + (n + 1) 8 4096 och n = 256 DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 10 / 32
Leta i listor Skiss av B-träd... 27 56 103 K < 27 27 <= K < 56 56 <= K < 103 K >= 103 Inre nod Eftersom lagom längd på en lista är så mycket som ryms i ett sekundärminnesblock kan man lätt räkna ut hur mycket som ryms. Adressen till ett minnesblock är (med 64-bits-ord) 8 byte lång och antar man att en nyckel är 8 byte lång (räcker t.ex. för ett personnummer) så får man antalet nycklar i en nod till n 8 + (n + 1) 8 4096 och n = 256 En lista som bara består av ett block kan alltså hålla 256 nyckelvärden. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 10 / 32
Leta i listor Skiss av B-träd... 13 7 23 31 43 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 Exempel på B + -träd med tre nivåer DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 11 / 32
Skiss av B-träd... En inre nod innehåller 256 adresser till andra listor så med två nivåer kan listan bli 256 257 = 65 792 element lång och med tre nivåer 16 908 544 element lång. Mer än nog för Sveriges befolkning... DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 12 / 32
Skiss av B-träd... En inre nod innehåller 256 adresser till andra listor så med två nivåer kan listan bli 256 257 = 65 792 element lång och med tre nivåer 16 908 544 element lång. Mer än nog för Sveriges befolkning... Fordonsregistret registrerar alla svenska fordon och nycklarna är 6 tecken långa. En nod i en sådan lista kan innehålla n 6 + (n + 1) 8 4096 och n = 292 nycklar. Tre nivåer ger en lista som kan vara 25 067 908 fordon lång och räcker mer än väl för Sveriges drygt 16 millioner fordon. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 12 / 32
Skiss av B-träd... En inre nod innehåller 256 adresser till andra listor så med två nivåer kan listan bli 256 257 = 65 792 element lång och med tre nivåer 16 908 544 element lång. Mer än nog för Sveriges befolkning... Fordonsregistret registrerar alla svenska fordon och nycklarna är 6 tecken långa. En nod i en sådan lista kan innehålla n 6 + (n + 1) 8 4096 och n = 292 nycklar. Tre nivåer ger en lista som kan vara 25 067 908 fordon lång och räcker mer än väl för Sveriges drygt 16 millioner fordon. Sökningen blir extremt snabb. Antalet nivåer gånger tiden för binärsökning i noderna = O (2 log n ) och tittar man på inläsningar från sekundärminnet, som är det långsammaste vi kan hitta på förutom nätverkskommunikation så kan vi summera: Fyra läsningar och 3 2 log 292 = 24 jämförelser är rasande snabbt för att hitta en av upp till 25 millioner informationsposter. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 12 / 32
Leta i listor Skiss av B-träd... En inre nod innehåller 256 adresser till andra listor så med två nivåer kan listan bli 256 257 = 65 792 element lång och med tre nivåer 16 908 544 element lång. Mer än nog för Sveriges befolkning... Fordonsregistret registrerar alla svenska fordon och nycklarna är 6 tecken långa. En nod i en sådan lista kan innehålla n 6 + (n + 1) 8 4096 och n = 292 nycklar. Tre nivåer ger en lista som kan vara 25 067 908 fordon lång och räcker mer än väl för Sveriges drygt 16 millioner fordon. Sökningen blir extremt snabb. Antalet nivåer gånger tiden för binärsökning i noderna = O (2 log n ) och tittar man på inläsningar från sekundärminnet, som är det långsammaste vi kan hitta på förutom nätverkskommunikation så kan vi summera: Fyra läsningar och 3 2 log 292 = 24 jämförelser är rasande snabbt för att hitta en av upp till 25 millioner informationsposter. Men det räcker inte alltid. I vissa situationer behövs ännu högre fart. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 12 / 32
Snabbare än B-träd Om vi betraktar just personnummer kan vi se att vi alltid har 12 siffror (om vi har med århundradet). DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 13 / 32
Snabbare än B-träd Om vi betraktar just personnummer kan vi se att vi alltid har 12 siffror (om vi har med århundradet). Om nycklarna alltid är av samma längd kan vi trolla lite. Vi kan ta de fyra första siffrorna och bara titta på de två som vi brukar använda 45 i 1945, 93 i 1993, 12 i 2012 o.s.v. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 13 / 32
Snabbare än B-träd Om vi betraktar just personnummer kan vi se att vi alltid har 12 siffror (om vi har med århundradet). Om nycklarna alltid är av samma längd kan vi trolla lite. Vi kan ta de fyra första siffrorna och bara titta på de två som vi brukar använda 45 i 1945, 93 i 1993, 12 i 2012 o.s.v. En lista med 100 platser räcker då. Där lagrar vi en lista med 12 platser, en för varje månad och i varje månadslista lägger vi en lista med 31 platser, en för varje dag i månaden. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 13 / 32
Snabbare än B-träd Om vi betraktar just personnummer kan vi se att vi alltid har 12 siffror (om vi har med århundradet). Om nycklarna alltid är av samma längd kan vi trolla lite. Vi kan ta de fyra första siffrorna och bara titta på de två som vi brukar använda 45 i 1945, 93 i 1993, 12 i 2012 o.s.v. En lista med 100 platser räcker då. Där lagrar vi en lista med 12 platser, en för varje månad och i varje månadslista lägger vi en lista med 31 platser, en för varje dag i månaden. I varje daglista lägger vi tre listor med 334 platser. Vi behöver ju 2 byte för 3 sista siffrorna och utrymme för adressen = 10 byte som ger 409 poster per block men det är mindre än 500 så jag tar 3 listor eftersom jag behöver 1000 olika adresser. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 13 / 32
Snabbare än B-träd Om vi betraktar just personnummer kan vi se att vi alltid har 12 siffror (om vi har med århundradet). Om nycklarna alltid är av samma längd kan vi trolla lite. Vi kan ta de fyra första siffrorna och bara titta på de två som vi brukar använda 45 i 1945, 93 i 1993, 12 i 2012 o.s.v. En lista med 100 platser räcker då. Där lagrar vi en lista med 12 platser, en för varje månad och i varje månadslista lägger vi en lista med 31 platser, en för varje dag i månaden. I varje daglista lägger vi tre listor med 334 platser. Vi behöver ju 2 byte för 3 sista siffrorna och utrymme för adressen = 10 byte som ger 409 poster per block men det är mindre än 500 så jag tar 3 listor eftersom jag behöver 1000 olika adresser. Nu har vi fyra nivåer men vi kommer åt informationsposterna utan binärsökning. Låt oss leta efter mig. Jag har personnumret 194512115306. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 13 / 32
Snabbare än B-träd Om vi betraktar just personnummer kan vi se att vi alltid har 12 siffror (om vi har med århundradet). Om nycklarna alltid är av samma längd kan vi trolla lite. Vi kan ta de fyra första siffrorna och bara titta på de två som vi brukar använda 45 i 1945, 93 i 1993, 12 i 2012 o.s.v. En lista med 100 platser räcker då. Där lagrar vi en lista med 12 platser, en för varje månad och i varje månadslista lägger vi en lista med 31 platser, en för varje dag i månaden. I varje daglista lägger vi tre listor med 334 platser. Vi behöver ju 2 byte för 3 sista siffrorna och utrymme för adressen = 10 byte som ger 409 poster per block men det är mindre än 500 så jag tar 3 listor eftersom jag behöver 1000 olika adresser. Nu har vi fyra nivåer men vi kommer åt informationsposterna utan binärsökning. Låt oss leta efter mig. Jag har personnumret 194512115306. Sista siffran är bara kontrollsiffra, den skippar vi likaväl som de två första. Vi använder 45 för att gå till årslista 46 (man börjar ju på 0!), 11 (eller 11-1) för att där titta i månadslista 11, 12 för att titta i dagslista 12. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 13 / 32
Snabbare än B-träd... Slutligen använder vi 035 = 35. Tag nu x,y = divmod(35,334) som ger x = 0 och y = 35 så vi använder lista nr 0 och där, på plats 35 hittar vi informationsposten för 451211530 (platsen kan innehålla två poster om vi är nära den gräns där det kan finnas en nyligen född och en drygt hundraåring). DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 14 / 32
Leta i listor Snabbare än B-träd... Slutligen använder vi 035 = 35. Tag nu x,y = divmod(35,334) som ger x = 0 och y = 35 så vi använder lista nr 0 och där, på plats 35 hittar vi informationsposten för 451211530 (platsen kan innehålla två poster om vi är nära den gräns där det kan finnas en nyligen född och en drygt hundraåring). Så, utan binär sökning, med fyra enkla uppslagningar har vi hittat bland alla levande personer i Sverige (eller alla personer som någonsin funnits i Sverige sedan nuvarande bokföringsmetod infördes). Idén är så bra att det bara finns en möjlighet att utveckla den: minska antalet uppslagningar. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 14 / 32
Snabbare än B-träd... Acceptera personnummer på alla former 194512115306, 4512115306, 194512115306, 4512115306, 19451211-5306 och 451211-5306 : def normalize(pnr): pnr = str(pnr) parts = pnr.split("-") res = "" for p in parts: res += p if len(res) == 12: res = res[2:12] return res Det som kommer ut från funktionen är strängen 4512115306 DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 15 / 32
Snabbare än B-träd... Kontrollera att det är ett personnummer: def checkpnr(pnr): checkpnr, checksiffra = divmod(pnr, 10) double = True summa = 0 mod = 100000000 while checkpnr > 0: x, checkpnr = divmod (checkpnr, mod) mod = mod // 10 if double: x = 2*x x1,x2 = divmod(x,10) summa = summa + x1 + x2 double = not double return(summa + checksiffra) % 10 == 0 Om vi matat in ett korrekt personnummer på heltalsform returneras True annars False DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 16 / 32
Leta i listor Snabbare än B-träd... Räkna fram alla nycklar för att slå upp informationsposten: def findkeys(pnr): remember = pnr try: pnr = normalize(pnr) if len(pnr)!= 10: raise intpnr = int(pnr) if checkpnr(intpnr): år, intpnr = divmod(intpnr, 100000000) månad, intpnr = divmod(intpnr, 1000000) dag, intpnr = divmod(intpnr, 10000) personlista, plats = divmod (intpnr // 10, 334) return { år :år, månad :månad, dag :dag, personlista :personlista, plats :plats} else: raise except Exception: return " " + remember + " är inte ett korrekt personnummer!" DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 17 / 32
Leta i listor Snabbare än B-träd... Leta med fyra uppslagningar:... 44 45... 10 11 12 13... 46... 47... 11 12... 034 035 036 037... 13 14... (nästan) direkt-åtkomst DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 18 / 32
Leta i listor Hashing... Idealet är naturligtvis att vi kan hitta en informationspost på en uppslagning:... 451112034 451112035 451112036 451112037... Så... vad gör vi? direkt-åtkomst DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 19 / 32
Leta i listor Hashing... Om vi slår samman uppslagningstabellerna till en så får vi flera problem. Vi kan inte ha tillräckligt stora tabeller. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 20 / 32
Leta i listor Hashing... Om vi slår samman uppslagningstabellerna till en så får vi flera problem. Vi kan inte ha tillräckligt stora tabeller. Vi kan åtgärda det genom att krympa tabellstorleken och hitta på en funktion som räknar om nyckeln till en lagom stor nyckel (en som hamnar inom tabellen) men då kan flera poster hamna på samma plats (få samma nyckel). DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 20 / 32
Leta i listor Hashing... Om vi slår samman uppslagningstabellerna till en så får vi flera problem. Vi kan inte ha tillräckligt stora tabeller. Vi kan åtgärda det genom att krympa tabellstorleken och hitta på en funktion som räknar om nyckeln till en lagom stor nyckel (en som hamnar inom tabellen) men då kan flera poster hamna på samma plats (få samma nyckel). Vi kan åtgärda detta på ett antal olika sätt. Alla dessa har använts i datorprogram. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 20 / 32
Hashing... hashfunktionen Skapa en funktion h(key) som ger en hygglig spridning i adressrymden, d.v.s. som sprider de beräknade nyckelvärdena jämt över listan. h(key) = f(key) % len(list) där f beräknar, på ett enkelt sätt, ett nyckelvärde Beräkningen måste vara snabb och ge stora tal som resultat, t.ex. ger personnummer med - borttaget en i det närmaste perfekt spridning. Långa nycklar kan vikas i 32-bitars-längder. Korta nycklar kan kompletteras med ett salt för att få lagom längd. Hur vi än bär oss åt kan flera nycklar ge samma hash-värde. Man talar då om kollisioner. Det är viktigt att hantera dessa kollisioner så att man får snabb åtkomst av lagrade data. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 21 / 32
Hashing... hashfunktionen Ett sätt att beräkna ett nyckelvärde som blir tillräckligt stort och som är snabbt i en dator är def hash1(x): y, z, n = 0, 0, 0 while x > 0: x, r = divmod(x, 10) z = z + r * (32**n) n += 1 return z 32 är en jämn multipel av 2 så det hanteras effektivt i datorn. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 22 / 32
Hashing... hashfunktionen Man kan förenkla algoritmen (och få helt andra nyckelvärden) med def hash2(x): y = 10 z = 0 while x > 0: x, r = divmod(x, y) z = z * 32 + r return z Skulle men inte få tillräckligt stora värden eller dålig spridning kan man salta på många olika sätt. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 23 / 32
Leta i listor Hashing... hashfunktionen Har man teckensträngar kan man göra likadant men ta teckenkoden: def hash3(s): k = 0 for i in s: k = ord(i) + k * 32 return k eller slå ihop koderna för varje tecken som om det vore strängar: def hash4(x): x = str(x) k = for i in x: k += str(ord(i)) return int(k) Man måste väga programspråkets egenskaper mot enkelhet i beräkningen. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 24 / 32
Leta i listor Hashing... linjär sondering Vid kollision kan vi hitta närmaste lediga plats. Kallas linjär sondering (linear probing). def rehash(key, hashtable): i = 1 s = len(hashtable) while hashtable[(key + i) % s]: i += 1 return i Fördel: man hittar alltid en plats. Nackdel: vid hopklumpningar försämras åtkomsttiden snabbt DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 25 / 32
Leta i listor Hashing... linjär sondering DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 26 / 32
Hashing... kvadratisk sondering En bättre idé kan vara kvadratisk sondering (quadratic probing): def rehash(key, hashtable): i = 1 s = len(hashtable) while hashtable[(key + i * i) % s]: i += 1 return i som ju kan varieras: ((key + i) * i) % s Fördel: minimerar hopklumpningar Nackdel: tabellen måste vara minst dubbelt så stor som antalet värden som förväntas lagras och ha primtalsstorlek eftersom metoden bara garanterar genomgång av halva tabellen och bara om storleken är ett primtal. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 27 / 32
Leta i listor Hashing... kvadratisk sondering DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 28 / 32
Hashing... andra ideer Man kan använda vilken funktion som helst för kollisionshantering men bör hålla beräkningen enkel. Man kan testa C 1 x 2 + C 2 x + C 3 där man varierar konstanterna tills man får en, för den aktuella applikationen, bra fördelning. Hur man än bär sig åt är kollisionshantering arbetsamt. Trots att det går fort vill man i vissa fall ha en ännu snabbare uppslagning. En kombination av hashing med de tidigare idéerna kan vara bra. Vi kunde i den ursprungliga idén med uppslagning få två personposter på samma plats om en var precis hundra år äldre än en annan. Det kan man hantera genom att ha plats för mer än en post. Varför inte en kort lista? Tittar man på statistik över kollisioner men inte gör något åt dem ser man att det inte blir så många. 5-6, kanske upp till 20 om vi krymper hashlistan. Vi är framme vid det snabbaste vi kan åstadkomma: O (()1). En uppslagning och titta i listan vi hittar på den platsen. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 29 / 32
Leta i listor Hashing... kollisionslistor DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 30 / 32
Hashing Användningsområden Användbart, javisst. Hashtekniker som beskrivits här med en stor mängd variationer används ofta. Snabb hantering av Pythons dict. Man använder ganska små hashtabeller med kollisionslistor. Python har en inbyggd hash-funktion som duger bra till det mesta. Många OS (inklusive Linux) använder metoden för att snabbt hitta bland tillgängliga program. Telefonbolagen använder hashtabeller vid uppringningar. En uppkoppling kan ta många vägar genom telefonnätet så man bygger hashtabeller för att hålla reda på uppringningarna. Skurar på flera tusen (ibland tiotusentals) uppringningar måste hanteras snabbt och när uppkopplingen är klar måste man snabbt städa i väntan på nästa skur. Men filssytem behöver kunna räkna upp saker i ordning och då duger inte hashing. Filsystemet använder den näst snabbaste metoden, B + -träd. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 31 / 32
Nästa gång Vi ska nu gå över till att blicka bakåt och utåt. Lite dator- och datorprogrammeringshistoria. Titta lite på hur man löst grundläggande funktionalitet i andra programmeringsspråk och jämföra. DA2001 (Föreläsning 20) Datalogi 1 Hösten 2018 32 / 32