Tabeller. Programkonstruktion. Moment 8 Om abstrakta datatyper och binära sökträd. Specifikationer för tabellfunktionerna. Operationer på tabellen

Relevanta dokument
Tabeller. Programkonstruktion. Moment 8 Om abstrakta datatyper och binära sökträd. Implementering av tabellen. Operationer på tabellen

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 8 Om abstrakta datatyper och binära sökträd

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 9 Om högre ordningens funktioner. PK1&PM1 HT-06 moment 9 Sida 1 Uppdaterad

Tentamen (del 2) (4 högskolepoäng) i Programkonstruktion och datastrukturer (1DL201)

Datastrukturer. föreläsning 10. Maps 1

Algoritmer och datastrukturer 2012, fo rela sning 8

TDDC74 Programmering: Abstraktion och modellering Datortenta , kl 14-18

Ett generellt träd är. Antingen det tomma trädet, eller en rekursiv struktur: rot /. \ /... \ t1... tn

Föreläsning 9 Datastrukturer (DAT037)

Programkonstruktion och. Datastrukturer

Programkonstruktion. Tentamen,

Datastrukturer, algoritmer och programkonstruktion (DVA104, HT 2014) Föreläsning 5

Föreläsning 9 Innehåll

Föreläsning 9 Innehåll

Datastrukturer i kursen. Föreläsning 8 Innehåll. Träd rekursiv definition. Träd

Inom datalogin brukar man använda träd för att beskriva vissa typer av problem. Om man begränsar sig till träd där varje nod förgrenar sig högst två

Träd Hierarkiska strukturer

Föreläsning Datastrukturer (DAT036)

Föreläsning 7. Träd och binära sökträd

Övningsuppgifter #11, Programkonstruktion och datastrukturer

BINÄRA TRÄD. (X = pekarvärdet NULL): struct int_bt_node *pivot, *ny; X X X 12 X X 12 X X -3 X X

Abstrakta datatyper. Primitiva vektorer. Deklarera en vektor

Programkonstruktion. Tentamen,

Föreläsning 5. Träd Binära träd Binärt sökträd som ADT Implementering av binärt sökträd Travestera binärt sökträd Sökning Insättning/borttagning

Tentamen, Algoritmer och datastrukturer

Tentamen Datastrukturer, DAT037 (DAT036)

Föreläsning 13. Träd

Linjärt minne. Sammanhängande minne är ej flexibelt. Effektivt

Inlämningsuppgiften. Föreläsning 9 Innehåll. Träd. Datastrukturer i kursen

TDDC74 Programmering: Abstraktion och modellering Tentamen, onsdag 9 juni 2016, kl 14 18

Programkonstruktion. Tentamen,

Trädstrukturer och grafer

Föreläsning 7. Träd och binära sökträd

Datastrukturer. Föreläsning 5. Maps 1

Tentamen Datastrukturer (DAT036/DAT037/DIT960)

Datastrukturer. föreläsning 10. Maps 1

Programkonstruktion och datastrukturer. Moment 6 Om generella datastrukturer och träd. PKD 2012/13 moment 6 Sida 1 Uppdaterad

Träd. Rot. Förgrening. Löv

Datastrukturer, algoritmer och programkonstruktion (DVA104, VT 2015) Föreläsning 6

TENTAMEN: Algoritmer och datastrukturer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Självbalanserande AVL-träd Weiss, avsnitt 4.4

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 27 augusti 2016, kl 8 12

Tentamen Datastrukturer, DAT037 (DAT036)

Två fall: q Tom sekvens: () q Sekvens av element: (a b c) ; (sum-rec '(2 4 6)) = 12. q Första elementet uppfyller vissa villkor: (2 a b c)

ADT Prioritetskö. Föreläsning 12 Innehåll. Prioritetskö. Interface för Prioritetskö. Prioritetsköer och heapar

Föreläsning Datastrukturer (DAT036)

Seminarium 13 Innehåll

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Föreläsning Datastrukturer (DAT037)

DD1320 Tillämpad datalogi. Lösnings-skiss till tentamen

Programmering II (ID1019) :00-17:00

Innehåll. Föreläsning 12. Binärt sökträd. Binära sökträd. Flervägs sökträd. Balanserade binära sökträd. Sökträd Sökning. Sökning och Sökträd

Datastrukturer och algoritmer. Innehåll. Trie. Informell specifikation. Organisation av Trie. Föreläsning 13 Trie och Sökträd.

Föreläsning 10 Innehåll. Prioritetsköer och heapar. ADT Prioritetskö. Interface för Prioritetskö. Exempel på vad du ska kunna

Upplägg. Binära träd. Träd. Binära träd. Binära träd. Antal löv på ett träd. Binära träd (9) Binära sökträd (10.1)

Datastrukturer och algoritmer. Innehåll. Tabell. Tabell - exempel. Gränsyta till Tabell. Tabell. Modell. Hashtabell Relation, lexikon.

Föreläsning 3 Datastrukturer (DAT037)

DAI2 (TIDAL) + I2 (TKIEK)

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 8 Erik Nilsson, Institutionen för Datavetenskap, LiU

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 9 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Sätt att skriva ut binärträd

ADT Prioritetskö. Föreläsning 13 Innehåll. Prioritetskö vs FIFO-kö. Prioritetskö Exempel på användning. Prioritetsköer och heapar

Föreläsning 4 Datastrukturer (DAT037)

Föreläsning Datastrukturer (DAT036)

Lösningsförslag till tentamen Datastrukturer, DAT037,

Tentamen Datastrukturer (DAT036)

Självbalanserande träd AVL-träd. Koffman & Wolfgang kapitel 9, avsnitt 1 2

Sökning. Översikt. Binärt sökträd. Linjär sökning. Binär sökning. Sorterad array. Linjär sökning. Binär sökning Hashtabeller

Programmeringsmetodik DV1, Programkonstruktion del 1 Tentamen,

Programmering i C++ EDAF30 Dynamiska datastrukturer. EDAF30 (Föreläsning 11) HT / 34

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren om att du har förstått dessa även om detaljer kan vara felaktiga.

Binära sökträd. Seminarium 9 Binära sökträd Innehåll. Traversering av binära sökträd. Binära sökträd Definition. Exempel på vad du ska kunna

3. Toppkvinnor på hög Låt lådan och de två kvinnornas famnar utgöra stackarna L, K1 respektive K2. Från början finns alla kort i L.

Vad har vi pratat om i kursen?

Tillämpad Programmering (ID1218) :00-13:00

Omtentamen (del 1, 6 högskolepoäng) i Programkonstruktion och datastrukturer (1DL201)

Föreläsning 5 Datastrukturer (DAT037)

Lösningar Datastrukturer TDA

Datastrukturer. föreläsning 9. Maps 1

Datastrukturer och algoritmer. Föreläsning 15 Inför tentamen

Föreläsning 4 Datastrukturer (DAT037)

Produktionsplanering. Programkonstruktion. Ett programutvecklingsexempel. Programutvecklingsprocessen. Exempel produktregister. 2.

Försättsblad till skriftlig tentamen vid Linköpings Universitet

Programmering i C++ EDA623 Dynamiska datastrukturer. EDA623 (Föreläsning 11) HT / 31

Idag: Dataabstraktion

Träd, binära träd och sökträd. Koffman & Wolfgang kapitel 6, avsnitt 1 4

Hitta k största bland n element. Föreläsning 13 Innehåll. Histogramproblemet

Kryptokorsordslösare Programmeringsmetodik DV (period 2) Inlämningsuppgift 1

Det är principer och idéer som är viktiga. Skriv så att du övertygar rättaren om att du har förstått dessa även om detaljer kan vara felaktiga.

Lösningsförslag till exempeltenta 1

Lägg uppgifterna i ordning. Skriv uppgiftsnummer och din anmälningskod överst i högra hörnet på alla papper.

Lösningsförslag till tentamen Datastrukturer, DAT037,

Programmering för Språkteknologer II. Innehåll. Associativa datastrukturer. Associativa datastrukturer. Binär sökning.

Innehåll. F7: Tabell, hashtabell, relation & lexikon. Gränsyta till Tabell. Tabell. Tabell Hashtabell Relation Lexikon.

Tentamen Datastrukturer D DAT 035/INN960

TDDC74 Programmering, abstraktion och modellering DUGGA 2

Teoretisk del. Facit Tentamen TDDC kl (6) 1. (6p) "Snabba frågor" Alla svar motiveras väl.

Tentamen i. TDDC67 Funktionell programmering och Lisp

Föreläsning 14 Innehåll

Transkript:

Programkonstruktion Moment 8 Om abstrakta datatyper och binära sökträd Tabeller En viktig tillämpning är tabeller att ifrån en nyckel kunna ta fram ett tabellvärde. Ett typiskt exempel är en telefonkatalog: Avdelningen för datalogi Andersson, Arne, 10 Bol, Roland, 606 Eriksson, Lars-Henrik, 105 Flener, Pierre, 108 nyckel värde PK 009/10 moment 8 Sida 1 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida Uppdaterad 010-01-18 Operationer på tabellen Tabellen i exemplet kopplar ett heltalsvärde till en sträng. Vad vill man kunna göra för beräkningar med sådana tabeller? Lägg in en uppgift i en tabell (update) Hämta ett värde från en tabell (lookup) Tag bort en uppgift från en tabell (remove) (Fler operationer är tänkbara, vi kommer att diskutera några till, men nöjer oss med dessa just nu.) Not: Man skriver lite slarvigt att man lägger in eller tar bort uppgifter, men tabeller representeras förstås av datastrukturer som all annan information. update och remove beräknar alltså nya tabeller med förändrat innehåll, snarare än ändrar den gamla. PK 009/10 moment 8 Sida 3 Uppdaterad 010-01-18 Specifikationer för tabellfunktionerna Vi antar att tabellernas datatyp har namnet table. TYPE: string*table -> int option (* update(key,value,table) TYPE: string*int*table -> table POST: Tabellen table uppdaterad med värdet value för nyckeln key *) (* remove(key,table) TYPE: string*table -> table POST: Tabellen table med uppgiften om nyckeln key borttagen *) PK 009/10 moment 8 Sida Uppdaterad 010-01-18 Den tomma tabellen Innan man kan börja arbeta med tabeller så måste man ha en första tabell att utgå ifrån. Låt oss anta att det finns ett namngivet värde empty som är en tom tabell. Användning av tabellen Vi låter någon programmera tabellfunktionerna åt oss och sedan kan vi skriva program som använder tabeller! val datalogi = update("andersson, Arne",10, update("bol, Roland",606, update("eriksson, Lars-Henrik",105, update("flener, Pierre",108,empty)))); lookup("bol, Roland",datalogi) > SOME 606 lookup("anka, Kalle",datalogi) > NONE lookup("bol, Roland", update("bol, Roland",13,datalogi)) > SOME 13 lookup("bol, Roland", remove("bol, Roland",datalogi)) > NONE Det verkar fungera bra, men fattas inte något...? PK 009/10 moment 8 Sida 5 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida 6 Uppdaterad 010-01-18

Abstrakta datatyper Vi har inte sagt någonting om hur tabellerna skall representeras. Tydligen kunde vi använda dem ändå! Kunskapen om hur tabeller ser ut finns i koden för funktionerna lookup, update och remove. Den som skriver dessa funktioner måste veta hur tabeller representeras, men inte den som använder tabellerna. Användningen av tabeller är alltså oberoende av representationen. Man säger att representationen av tabellen har abstraherats bort genom dataabstraktion och att tabellen är en abstrakt datatyp. De tre funktionerna och värdet empty utgör tabelldatatypens gränsyta (eng. interface) mot den kod som använder tabeller. PK 009/10 moment 8 Sida Uppdaterad 010-01-18 Implementering av tabellen Ett sätt att implementera tabellen är som en lista. type table = (string*int) list; datalogi > [("Andersson, Arne",10), ("Bol, Roland",606), ("Eriksson, Lars-Henrik",105), ("Flener, Pierre",108)] : table; En invariant är att varje nyckel förekommer högst en gång i annat fall skulle tabellvärdet inte vara entydigt bestämt. PK 009/10 moment 8 Sida 8 Uppdaterad 010-01-18 Tabellprogrammet lookup TYPE: string*table -> int option (* VARIANT: längden hos table *) fun lookup(_,[]) = NONE lookup(key,(key',value)::rest) = SOME value lookup(key,rest); Tabellprogrammet empty, update val empty = []; (* update(key,value,table) TYPE: string*table -> table POST: Tabellen table uppdaterad med värdet value för nyckeln key *) (* VARIANT: längden av table *) fun update(key, value, []) = [(key,value)] update(key, value, (key',value')::rest) = (key,value)::rest (key',value')::update(key,value,rest); Observera att update respekterar datastrukturinvarianten att varje nyckel förekommer högst en gång i tabellen. PK 009/10 moment 8 Sida 9 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida 10 Uppdaterad 010-01-18 Tabellprogrammet remove (* remove(key,table) TYPE: string*table -> table POST: Tabellen table med uppgiften om nyckeln key borttagen *) (* VARIANT: längden av table *) fun remove(key, []) = [] remove(key, (key',value)::rest) = rest (key',value)::remove(key,rest); Observera att även remove respekterar datastrukturinvarianten. Tabelltyper Vi har i specifikationerna skrivit att nycklarna skall vara strängar och tabellvärdena heltal, men tabellfunktionerna blir faktiskt polymorfa: lookup : ''a*(''a*'b) list -> 'b option update : ''a*'b*(''a*'b) list -> (''a*'b) list remove : ''a*(''a*'b) list -> (''a*'b) list Anledningen är att programmet aldrig utför någon operation på nycklar eller värden (bara likhetsjämförr på nycklar) och därför inte bryr sig om vilka typer dessa har. Funktionerna arbetar med tabeller på formen (''a*'b) list. Vår tabell hade typen (string*int) list, vilket är ett speciallfall eller instans av den polymorfa tabelltypen ovan. PK 009/10 moment 8 Sida 11 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida 1 Uppdaterad 010-01-18

Stöd för dataabstraktion i ML För att förhindra att användaren av en abstrakt datatyp av misstag (eller avsiktligt...) gör sig beroende av representationen så har ML stöd för att tvinga användningen att bli representationsoberoende. abstype-deklarationen är en variant av datatype-deklarationen. abstype datatypdeklaration with deklarationer av gränsytan end; Operationer i den abstrakta datatypens gränsyta definieras mellan with och end. Konstruktorerna i datatypsdeklarationen blir osynliga och oåtkomliga utom just mellan with och end. Detta tvingar datatypen att bli abstrakt. Av samma skäl skrivs inte abstype-värden ut av ML-systemet. PK 009/10 moment 8 Sida 13 Uppdaterad 010-01-18 Tabellen som abstype För att göra tabellen till en abstype så kan man definiera en konstruktor Table och tagga listorna i tabellen med den. abstype table = Table of (string*int) list with val empty = Table []; fun lookup(key,table table) =...; fun update(key,table table) =...; fun remove(key,table table) =...; end; PK 009/10 moment 8 Sida 1 Uppdaterad 010-01-18 Olika sorters operationer i gränsytan Man brukar skilja på Operationer som konstruerar nya värden av den abstrakta datatypen (t.ex. update). De kallas ofta konstruktorer. (Men blanda inte ihop dem med konstruktorer som används för att tagga data t.ex. Table). Operationer som hämtar delar av värden (t.ex. lookup). De kallas ofta selektorer. Operationer som gör tester eller jämförr på värden av den abstrakta datatypen. De kallas ofta predikat. Gränserna mellan dessa är dock inte skarp. Intern dokumentation av abstrakta datatyper Varje abstype skall ha intern dokumentation på samma sätt som en datatype. Dessutom skall alla definitioner av värden (val) som ingår i gränsytan också dokumenteras med Namn på värdet Värdets typ Beskrivning av vad värdet representerar T.ex.: (* empty TYPE: table VALUE: En tom tabell *) val empty = Table []; PK 009/10 moment 8 Sida 15 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida 16 Uppdaterad 010-01-18 Fördelar med dataabstraktion Operationerna kan implementeras oberoende av användningen av den abstrakta datatypen. Den som skall använda den abstrakta datatypen behöver inte veta hur datatypen är implementerad. Eftersom den som använder den abstrakta datatypen inte heller får utnyttja eventuell kunskap om hur datatypen är implementerad så kan man ändra implementeringen utan att behöva ändra någonting i övriga delar av programmet. (Så länge som gränsytans funktionsspecifikationer följs!) Av samma skäl så behöver den som skall använda datatypen inte ta något ansvar för invarianter det vilar helt på implementeringen. Den tydliga gränsen mellan implementering och användning gör det lättare att återanvända implementeringen i andra situationer. PK 009/10 moment 8 Sida 1 Uppdaterad 010-01-18 Nackdelar med dataabstraktion Man kan bara göra sådana operationer som är förutsedda. Exempel: Om man vill veta om tabellen är tom, så går inte det! (En nödlösning kan vara att lägga till en operation i gränsytan som exporterar all information i datatypen i något bestämd format och sedan skriva en egen funktion som gör arbetet.) Man kan förlora prestanda i vissa fall. Exempel: Om man vet att en nyckel inte finns i tabellen så kan man lägga in en ny uppgift för nyckeln i konstant tid genom att skriva (x,y)::table i stället för update(x,y,table). Speciellt för ML: Eftersom konstruktorerna inte går att använda utanför abstype-deklarationen så kan de inte används i matchning utanför. Det kan ge mer svårlästa program. PK 009/10 moment 8 Sida 18 Uppdaterad 010-01-18

Likhetstyper Abstrakta datatyper i ML är inte likhetstyper. Värden med samma beteende kan ha olika representation! Exempel: val tab1 = update("a",1,update("b",,empty)); val tab = update("b",,update("a",1,empty)); tab1 och tab är nu bundna till tabeller med samma information. Men tab1 tab, därför att listorna har elementen i olika ordning. För att förhindra misstag och för att inte fakta om datarepresentationen skall avslöjas tillåter inte ML jämförr mellan värden av abstrakta datatyper (utanför with... end). För att kunna jämföra måste gränsytan ha en operation för jämförn som då kan ta hänsyn till representationen. PK 009/10 moment 8 Sida 19 Uppdaterad 010-01-18 Sammanfattning av abstraktion Definitionsabstraktion ett värde ersätts av ett symboliskt namn Ex.: x < maximum i stället för x < 100 (vitsen är bättre läsbarhet och att behöver man ändra maximum räcker det med att ändra på ett ställe där maximum definieras.) Funktionsabstraktion ett uttryck görs oberoende av specifika data Ex.: (fn x => x+1)y i stället för y+1 (vitsen är att (fn x => x+1) kan namnges och användas i många olika sammanhang ofta även bättre läsbarhet.) Dataabstraktion ett program görs oberoende av specifik datarepresentation Ex.: update(x,y,table) i stället för (x,y)::table (vitsen är att man kan förändra representationen utan att ändra programmet, lättare att uppfylla invarianter, ofta bättre läsbarhet.) PK 009/10 moment 8 Sida 0 Uppdaterad 010-01-18 Tabellkomplexitet Vi har representerat en tabell med n nycklar av en lista med n element. För att slå i tabellen måste man i genomsnitt söka igenom halva listan dvs n/ rekursiva anrop av lookup. En lista med en miljon nycklar kräver i genomsnitt 500 000 anrop av lookup för att göra en tabellslagning. Detta är inte bra i praktiken. Tidsåtgången för lookup är alltså proportionell mot antalet nycklar i tabellen. Komplexiteten hos lookup är O(n). Detsamma gäller update och remove. Vi skall se på en annan implementering som ger lägre komplexitet. PK 009/10 moment 8 Sida 1 Uppdaterad 010-01-18 Trädrepresentation Tabellinformation kan lagras i träd i stället för i listor. 1 6 9 Varje nod innehåller en nyckel och motsvarande värde. Detta träd representerar en tabell med nycklarna "1", "", "", "6", "" och "9". (Tänk på att nycklarna är strängar!) I exemplen kommer tabellvärdena att vara heltalet som motsvarar nyckeln. Av utrymmesskäl visas bara nycklarna i figurerna. PK 009/10 moment 8 Sida Uppdaterad 010-01-18 Binära sökträd Ett binärt träd kallas för ett binärt sökträd om den har invarianten: Alla noder i vänster delträd har nycklar med lägre värden än rotnodens nyckel. Alla noder i höger delträd har nycklar med högre värden än rotnodens nyckel Dessa villkor gäller även för varje delträd Sökning i binära sökträd Sök efter nyckeln "6". Starta vid roten. Vid varje nod väljer man vänster eller höger sökträd beroende på om det man söker efter är mindre eller större än nodens nyckel. större mindre 1 6 9 1 6 9 träff PK 009/10 moment 8 Sida 3 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida Uppdaterad 010-01-18

Tidkomplexitet för binära sökträd Om alla nivåer i trädet är fyllda så innehåller ett träd med n nivåer n -1 noder. För att söka efter en nyckel behöver man bara besöka så många noder som motsvarar antalet nivåer. Antalet rekursiva anrop för ett träd n -1 noder är alltså n. Tidsåtgången är proportionell mot logaritmen av antalet nycklar O(log n). Ett träd med en miljon nycklar kräver c:a 0 rekursiva anrop av lookup jämför med 500 000 som krävdes när tabellen representerades som en lista. Implementering av tabeller som binära sökträd Vi kan nu göra en alternativ implementering av tabeller som binära sökträd. Gränsytan med sina funktionsspecifikationer är helt oförändrad. Tack vara att datatypen är abstrakt så kommer inga program som använder tabelldatatypen att påverkas av ändringen. Man kan använda tabellen på exakt samma sätt som när den var implementerad som en lista. Detta förutsätter att trädet är välbalanserat mera senare... PK 009/10 moment 8 Sida 5 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida 6 Uppdaterad 010-01-18 Deklaration av tabeller som binära sökträd abstype table = Empty Bintree of string*int*table*table (* REPRESENTATION CONVENTION: Ett tomt träd representeras av Empty. Varje icketomt träd representeras av Bintree(k,v,l,r), där k är nyckeln, v är tabellvärdet, l är vänster delträd och r är höger delträd. REPRESENTATION INVARIANT: Alla nycklar i vänster resp. höger delträd måste vara mindre resp. större än k *) with (* empty TYPE: table VALUE: Ett tomt träd *) val empty = Empty; fun update...; fun lookup...; fun remove...; end; Funktionen lookup TYPE: string*table -> int option (* VARIANT: Största djupet hos ett löv i table *) fun lookup(key,empty) = NONE lookup(key,bintree(key',value,left,right)) = SOME value if key < key' then lookup(key,left) lookup(key,right); PK 009/10 moment 8 Sida Uppdaterad 010-01-18 PK 009/10 moment 8 Sida 8 Uppdaterad 010-01-18 Körexempel lookup("6",bintree("",, Bintree("",, Bintree("1",1,Empty,Empty), Empty), Bintree("",, Bintree("6",6,Empty,Empty), Bintree("9",9,Empty,Empty)))) > if "6" = "" then SOME if "6" < "" then lookup("6",bintree("",, Bintree("1",1,Empty,Empty), Empty)) lookup("6",bintree("",, Bintree("6",6,Empty,Empty), Bintree("9",9,Empty,Empty))) Körexempel (forts.) > lookup("6",bintree("",, Bintree("6",6,Empty,Empty), Bintree("9",9,Empty,Empty))) > if "6" = "" then SOME if "6" < "" then lookup("6",bintree("6",6,empty,empty)) lookup("6",bintree("9",9,empty,empty)) > if "6" = "6" then SOME 6 if "6" < "6" then lookup("6",empty) lookup("6",empty) > SOME 6 PK 009/10 moment 8 Sida 9 Uppdaterad 010-01-18 PK 009/10 moment 8 Sida 30 Uppdaterad 010-01-18

Uppdatering av binära sökträd För att sätta in nyckeln "3": Sök efter den och sätt in den där den borde ha funnits: mindre hittar inte 1 3 6 9 ny nod PK 009/10 moment 8 Sida 31 Uppdaterad 010-01-18 Funktionen update (* update(key,value,table) TYPE: string*int*table -> table POST: Tabellen table uppdaterad med värdet value för nyckeln key *) (* VARIANT: största djupet av ett löv i table *) fun update(key,value,empty) = Bintree(key,value,Empty,Empty) update(key,value, Bintree(key',value',left,right)) = Bintree(key,value,left,right) if key < key' then Bintree(key',value', update(key,value,left),right) Bintree(key',value', left,update(key,value,right)); PK 009/10 moment 8 Sida 3 Uppdaterad 010-01-18 Obalans Sätter man i tur och ordning in "1", "", "", "6", "" och "9" i ett tomt sökträd så får man: 1 Detta är ett kraftigt obalanserat träd. I praktiken en lista, vilket ger samma tidsåtgång för sökning som i en lista linjärt i storleken. För att binära sökträd skall vara praktiskt användbara måste de balanseras om efter uppdateringar. Balanserade sökträd behandlas i nästa kurs (AD1). PK 009/10 moment 8 Sida 33 Uppdaterad 010-01-18 6 9 Funktionen tolist Ibland vill man hämta ut informationen i ett träd som en lista. Vi utökar gränsytan med funktionen tolist. (* tolist table TYPE: table -> (string*int) list PRE: (inget) POST: En lista av alla nyckel-värde-par i tabellen i inorder. *) (* VARIANT: Största djupet av något löv i table *) fun tolist Empty = [] tolist(bintree(key,value,left,right)) = tolist left @ (key,value) :: tolist right; tolist går igenom (traverserar) hela trädet för att samla information från noderna och bygga en lista. tolist av exempelträdet ger [("1",1),("",),("",),("6",6),("",),("9",9)] PK 009/10 moment 8 Sida 3 Uppdaterad 010-01-18 Mer om traversering tolist besöker vänster delträd först, sedan rotnoden, sedan höger delträd inorder-traversering. Notera att listan som tolist returnerar är sorterad. Genom att bygga ett sökträd med en mängd data och sedan göra om det till en lista i inorder så har man sorterat datamängden! (Ett alternativ till mergesort som kallas trädsortering.) preorder-traversering man besöker först rotnoden, sedan vänster delträd, sedan höger. postorder-traversering man besöker först vänster delträd, sedan höger, sedan rotnoden. PK 009/10 moment 8 Sida 35 Uppdaterad 010-01-18 Polymorfa tabeller Vår tabelldatatyp är definierad med strängnycklar och heltalsvärden. I praktiken vill man kunna definiera en abstrakt datatyp för tabeller som kan hantera alla typer av nycklar och värden eftersom en sådan är mera användbar. Funktionsspecifikationerna behöver då ändras för att bli mera generella, t.ex. TYPE: ''a*(''a*'b) table -> 'b option Notera att typvariabeln för nyckeltypen endast avser likhetstyper (dubbel apostrof). Varför? PK 009/10 moment 8 Sida 36 Uppdaterad 010-01-18

Polymorfa tabeller (forts.) Som vi såg tidigare så var funktionerna som implementerade tabeller som listor redan fullständigt polymorfa. Med deklarationen abstype (''a,'b) table = Table of (''a*'b) list så blir funktionernas typer de önskade lookup : ''a*(''a*'b) table -> 'b option update : ''a*'b*(''a*'b) table -> (''a*'b) table remove : ''a*(''a*'b) table -> (''a*'b) table Det är inte lika enkelt med implementeringen av tabeller som binära sökträd. Med en deklaration abstype (''a,'b) table = Empty Bintree of ''a*'b*(''a,'b) table*(''a,'b) table så blir funktionerna av sig själva polymorfa i tabellvärdet, men inte i nycklarna. Varför? PK 009/10 moment 8 Sida 3 Uppdaterad 010-01-18 Operationer på sökträd blir inte helt polymorfa I implementeringen av tabeller som listor användes likhetsjämför för att jämföra nycklar. = är en polymorf funktion. I implementeringen av tabeller som binära sökträd användes storleksjämför av nycklar. Storleksjämförr är beroende av typen: < är en monomorf funktion. Den är överlastad så den kan fungera med ett antal olika typer (string, int m.fl.), men bara en typ vid varje gång den förekommer i programkoden. Detta händer även om själva sökträden är polymorfa! Detta problem kan man lösa med högre ordningens funktioner (kursmoment 9). PK 009/10 moment 8 Sida 38 Uppdaterad 010-01-18