Datastrukturer och algoritmer Föreläsning 7 Tabell, hashtabell Relation & lexikon Innehåll Tabell Tabell Hashtabell Relation, lexikon Modell Uppslagsbok Organisation Ändlig avbildning av argument på värden (mappning av nycklar på värden) Dynamisk datatyp Till skillnad mot pappersvarianten Används ibland som statisk typ 3 4 Tabell - exempel Gränsyta till Tabell Telefonkatalog person -> telnr Eller omvändningen nr -> person Databaser består av (utökade) tabeller Nyckel (argument) och värde Nyckeln används för att hitta rätt Nyckel 0907856259 0701234567 Värde Thomas J jobbet Thomas J:s mobil abstract datatype Table(arg,val) Empty() Table(arg,val) Insert(x:arg,y:val,t:Table(arg,val)) Table(arg,val) Isempty (t:table(arg,val)) Bool Lookup (x:arg, t:table(arg,val)) (Bool,val) Remove (x:arg, t:table(arg,val)) Table(arg,val) 5 6 1
Fält vs Tabell Konstruktion Likheter Index svarar mot elementvärde i ett fält Argumentet/nyckeln svarar mot tabellvärde i en tabell Skillnader Tabell har inga krav på argument/nyckeltypen mer än att likhet ska vara definierad. Index i fält måste vara diskret linjärt ordnat Tabell är en dynamisk datatyp Fält är en statisk datatyp Tabell kan konstrueras som fält om: Argumenttypen är diskret linjärt ordnad Det går att hitta en ODEF-konstant, dvs det finns ett elementvärde som kan representera ett odefinierat värde Argumenten är relativt väl samlade och inte utspridda 7 8 Konstruktion Lista av par: insättningar Lista av par Riktad lista Hashtabell Binärt sökträd Kommer vi att titta närmare på senare Två huvudalternativ Sätt in det nya paret först i listan Kolla om det finns par med samma argument (nyckel) Dubletthantering Måste alltid utföras, antingen vid insättning eller borttagning UTÖKA: jobbet görst vid borttagning MODIFIERA: jobbet görs vid insättning 9 10 Tabell Uppgift 4 Jämför Fält resp Lista som parkonstruktion Insättningskostnad Avläsning Borttagning När väljer man vad? Designfrågor Osorterad vs sorterad (sökning går fortare, insättning långsammare) Länkad struktur eller Fält Utöka eller modifiera vid insättning 11 Implementera tabell på tre sätt Array Lista Lista med move-to-first Kör ett givet testprogram och kommentera resultatet Tänk på att all åtkomst av tabellen måste gå via gränsytan Inget kikande inuti implementationen! 12 2
Tillämpningar Ofta använd datatyp t.ex Representera samband mellan objekt Benämna objekt Associera egenskaper hos ett objekt med motsvarande värden Kompilatorer Symboltabell Fält som Tabell Tippel, Tupel, Tuple, Post, Relation Associerar argument med värden Tippel (Tupel, Tuple) består av element (koordinater) Post (record, struct) är som abstrakt datatyp sett samma sak som Tippel. Relation är en egenskap definierad för en grupp av objekt 13 14 Att jämför nycklar (argument) Måste kunna jämföra argument även när de inte är inbyggda datatyper int, float etc utan även egendefinierade records/struct/objekt Hashtabell Problemet med att implementera en tabell som fält är att grundmängden (definitionsmänden, antalet olika nycklar som kan förekomma) inte får vara för stor Vi behöver en hashfunktion som avbildar den större indextypen A till en mindre typ B En hashfunktion gör detta Omvandlar nycklar till exempelvis index i en tabell 15 16 Hashfunktion Sluten hashning Funktionen f(x) avbildar en stor mängd nycklar, A, på en liten mängd tal, B. y = f(x), x A, y B Kollisioner är oundvikliga och en bra hashfunktion kännetecknas av: Litet förväntat antal kollisioner Sprider elementen jämnt över mängden Bör påverkas av alla delar av nyckeln Sluten och öppen hashning Låt B vara en cirkulär vektor, dvs det sista elementet följer det första Värde Nyckel F(x) 0 Nyckel Värde 0 Thomas Lärare 1 2 3 4 17 18 3
Sluten hashning Exempel: Sluten hasning Linjär teknik för kollisioner Om ett element kolliderar (platsen redan upptagen) sätter man in det på första lediga plats efter den upptagna Ger upphov till klustring i tabellen Sökning efter ett element börjar på den plats som hashvärdet anger och fortsätter ev framåt. Om det inte påträffas före nästa lediga plats så finns det inte i tabellen Om vid borttagning bara lämnar platsen tom blir det fel vid sökning använd en borttagenmarkör 19 Grundmängden 1, 2,..., 125 skall avbildas på värdena 0, 1,..., 6. Mängd = {1, 8, 27, 64, 125} Hashfunktion f(x) = x % 7 20 Sluten hasning, linjär teknik Hashtabeller - fyllnadsgrad Värstafallskomplexiteten för samtliga operationer är O(n) där n är antelet element som finns insatta i tabellen Är dock ytterst osannolikt. Alla element måste ligga i en följd Under försutsättning att tabellen inte fylls till mer än en viss del får man i medeltal O(1) för operationerna En hashtabells fyllnadsgrad (λ) definieras som kvoten mellan antalet insatta element och antalet platser i tabellen En tom tabell har λ = 0 och en full λ = 1. Man vet att Medelantalet platser som måste prövas vid en insättning och misslyckad sökning är uppåt begränsad av (1+1/(1- λ) 2 ) /2 (λ = 0.5 ger 2.5) Medelantalet för en lyckad sökning är uppåt begränsad av (1+1/(1- λ))/2, (λ = 0.5 ger 1.5) 21 22 Sluten hasning, kvadratisk teknik När fyllnadsgraden blir hög (λ > 0.75) blir operationerna för den linjära tekniken långsam Kvadratisk teknik kan användas istället Vid kollision tas först nästa element, sedan det fyra platser framåt, sedan nio platser osv., dvs H, H+1, H+4,, H+i 2, där H är elementets hashvärde Exempel Sätt in talen 89, 18, 49, 58, 9 i en tabell med 10 platser. h(x) = x % 10 89 % 10 = 9 18 % 10 = 8 49 % 10 = 9, upptagen prova H+1 = 0 58 % 10 = 8, upptagen, H+1=9 upptagen, H+4=2 9 % 10 = 9, nästa lediga plats H+4=3 23 24 4
Sluten hashning - kvadratisk teknik Inte säkert att man hittar en ledig plats även om den finns! Exempel: man har en tabell som är 16 element stor och man använder h(x) = x % 16 Stoppar in elementen 0, 16, 32 och 64. Då finns det inte plats för fler tal som hashar till 0. De enda platser som kommer att provas är 0, 1, 4, 9 Men: Om tabellens storlek är ett primtal kan ett nytt element alltid sättas in om fyllnadsgraden < 0.5 Fullständig komplexitetsanalys saknas men i praktiken blir det mindre klustring 25 Öppen hashning I stället för cirkulär vektor används en vektor med listor. I lista nummer i ligger alla element med hashvärde i. Värstafallskomplexitet: O(n) för alla operationer (Alla element i samma lista) Medelfallskomplexitet: Insättning och misslyckad sökning blir n/size Lyckad sökning blir (n-1)/(2*size)+1 Tumregel: inte fler än 2*size element 26 Exempel: öppen hashning Teoretiska resultat Grundmängden 1, 2,, 125 ska avbildas på värdena 0, 1,..., 6. Mängd = {1, 7, 27, 64, 125} Använd hashfunktionen f(x) = x % 7. Chaining = Öppen hashing Linear prob. = Sluten hashing med linjär teknik Double hash = Sluten hashing med kvadratisk teknik 27 Från: http://www.ida.liu.se/labs/logpro/ulfni/dalg/resources/f8.pdf 28 Hashfunktionen Lexikon Vi har använt h(x) = x % m i exemplen Fungerar bra om m är ett primtal, annars kan periodicitet uppstå Det finns mer generella metoder, t.ex h(x) = ((c1 * x + c2) % p) % m p stort primtal > m, t.ex 1048583 c1 och c2 konstant heltal > 0 och < p c2 ofta satt till 0 Ett lexikon är som en tabell utan tabellvärden (bara nycklar) Lexikon är en solitär datatyp. Man kan bara göra modifieringar av isolerade dataobjekt. En icke-solitär datatyp har stöd för att kombinera/bearbeta två eller flera dataobjekt. Exempel: Mängd där man kan slå samman två mängder med union. 29 30 5
Innehåll Konstruktion av lexikon Oftast behöver man bara skapa ett lexikon en enda gång. En förenklad mängd där man tagit bort union, intersection, difference, subset och equal. Kvar är det man behöver för att kunna hålla ordning på en samling objekt: empty isempty(s) insert(v, s) remove(v, s) memberof(v, s) Vi kan få betydligt effektivare konstruktioner när antalet och typen av metoder är begränsade. Konstruktioner av lexikon: Lexikon som Hashtabell Lexikon som Binärt sökträd Lexikon som Trie Eftersom Lexikon är så likt Tabell kan dessa konstruktioner med små ändringar bli effektiva konstruktioner av en tabell. 31 32 6