Datastrukturer och algoritmer Föreläsning 11 © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Innehåll Trie Sökning och sökträd (mer nästa föreläsning) Heap/Hög Kapitel 14.1-14.4, 14.7, delar av kapitel 15 i boken + OH-bilderna… © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Trie Ytterligare en variant av träd. Jmfr med: Oordnat träd - barnen till en nod bildar en mängd Ordnat träd - barnen till en nod bildar en lista I Trie är barnen till en nod organiserade som tabellvärden i en tabell som hör till noden. Trie kallas också för diskrimineringsträd, code-link tree eller radix-search tree. I radix-search tree är argumentvärdena specialiserade till siffror i ett talsystem med given bas. © Anders Broberg, Lena Kallin Westin, 2007 Radix-search tree är argumentvärdena specialiserade till siffror i ett talsystem med given bas (radix).gt
© Anders Broberg, Lena Kallin Westin, 2007 Organisation av Trie Man når barnen (delträden) direkt genom ”namn”, dvs argument/nycklar i barnnodens tabell. När man ritar en trie brukar nycklarna skrivas direkt intill motsvarande båge. © Anders Broberg, Lena Kallin Westin, 2007 Bild från sidan 281 i Janlert L-E., Wiberg T., Datatyper och algoritmer, Studentlitteratur, 2000
© Anders Broberg, Lena Kallin Westin, 2007 Organisation av Trie Tabellerna har en och samma nyckeltyp. tex tecken Ofta saknar de inre noderna etiketter. Träden är lövträd. Trie är normalt nedåtriktad. Binära träd kan ses som ett specialfall av Trie där nyckelvärdena är left och right. © Anders Broberg, Lena Kallin Westin, 2007
Informell specifikation, två sätt: Utgå från Urträdets specifikation och låt typparametern sibling ha värdet Tabell. Då hanteras insättning, borttagning och värdeskontroll av Tabellen själv. I övrigt används de vanliga operationerna för att sätta in och ta bort barn etc. Sätt in lämpliga tabelloperationer direkt i specifikationen av Trie. Insert-child blir tabellens Insert, Delete-child tabellens Remove och Child tabellens Lookup. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Konstruktion av Trie De flesta konstruktioner av träd går bra Om det går bra ändra så att barnen hanteras som tabellvärden i en tabell. En länkad lista med 2-celler byts till 3-celler. Implementerar man tabellen som vektor eller hashtabell får man effektiva Trieimplementationer. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Tillämpningar av Trie Lexikon av sekvenser eller Tabeller där nycklarna är sekvenser. För sekvenser med element av typ A väljer vi en Trie med tabellnycklar av typ A. En sekvens motsv. en väg i trädet från roten till ett löv. Man lägger till en slutmarkör i slutet av varje sekvens om en sekvens kan vara början på en annan sekvens. En annan variant är att ha etiketter i de inre noderna också. Ett viktigt/vanligt specialfall är Lexikon/Tabell av textsträng. En sträng kan ju ses som en lista eller vektor av tecken. © Anders Broberg, Lena Kallin Westin, 2007 Lexikon är man bara intresserad av vägen (finns en väg så finns elementet i lexikonet). Tabellen så är vägen nyckeln och tabellvärdet för nyckeln är i noden. Har man sekvenser av en och samma fixa längd behövs inga markörer.
© Anders Broberg, Lena Kallin Westin, 2007 Exempel på Trie © Anders Broberg, Lena Kallin Westin, 2007 Bild från sidan 284 i Janlert L-E., Wiberg T., Datatyper och algoritmer, Studentlitteratur, 2000
Trie för Lexikon/Tabeller som lagrar sekvenser Speciellt där sekvenserna är lika i början. Fördelar Kompakt sätt att lagra lexikonet/tabellen på. Sökningens tidskomplexitet proportionell mot sekvenslängden. En jämförelse per elementtecken. Den relativa komplexiteten är oberoende av lexikonet/tabellens storlek. Det blir inte ”dyrare” att söka i ett stort lexikon jämfört med ett litet. © Anders Broberg, Lena Kallin Westin, 2007 Den relativa komplexiteten är oberoende av lexikonet/tabellens storlek. Dvs Komplexiteten för tabellen/lexikonets metoder är O(1) i termer av lexikonets (tabellens) storlek.
© Anders Broberg, Lena Kallin Westin, 2007 Tillämpningar Stavningskontroll Skapa ett trie med alla ord som finns i språket. Översättningstabell Löven innehåller motsvarande ord i ett annat språk. Filsystem på Unix/PC Datakomprimering LZ78-algoritmen Huffman-kodning © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Komprimerade Tries Alla enbarnsnoder konverteras till att innehålla hela strängen/sekvensen som är under. Varje intern nod i ett komprimerat Trie har två barn och varje löv symboliserar en sträng. Minnesutrymmet krymper från O(m) till O(n) m är summan av längderna av strängarna n är antalet strängar i strukturen © Anders Broberg, Lena Kallin Westin, 2007
Variant utan slutmarkörer © Anders Broberg, Lena Kallin Westin, 2007 Bild från sidan 286 i Janlert L-E., Wiberg T., Datatyper och algoritmer, Studentlitteratur, 2000
© Anders Broberg, Lena Kallin Westin, 2007 Tries för strängar Insättning Starta i noden och gå nedåt så länge vägen matchar. När man hittar en skiljelinje, stanna och stoppa in resten av strängen som ett delträd. Insättning i komprimerade tries: Är löven strängar kan dessa behöva delas upp i två barn Borttagning I princip samma algoritm fast ”tvärtom”. Sök upp strängen som ska tas bort och radera nerifrån i trädet upp till första förgreningen. © Anders Broberg, Lena Kallin Westin, 2007
LZ78 eller Lempel-Ziv kodning Låt frasen 0 vara strängen ”” Skanna igenom texten Om du stöter på en ”ny” bokstav lägg till den på toppnivån på trien. Om du stöter på en ”gammal” bokstav gå nedåt i trien tills du inte kan matcha fler tecken, lägg till en nod i trien som representerar den nya strängen. Stoppa in paret (nodeIndex, sistaBokstaven) i den komprimerade strängen. Exempel: ”how now brown cow in town.” © Anders Broberg, Lena Kallin Westin, 2007
LZ78 eller Lempel-Ziv kodning Avkodning: Varje gång du stöter på ”0” i strängen lägg nästa bokstav i strängen direkt efter den föregående i den avkodade strängen. För varje index < > 0 stoppa in delsträngen som motsvaras av den noden i den avkodade strängen, följt av nästa tecken i den komprimerade strängen. Notera att man inte behöver skicka med trädet. Exempel: 0h0o0w0_0n2w4b0r6n4c6_0i5_0t9. © Anders Broberg, Lena Kallin Westin, 2007
LZ78 eller Lempel-Ziv kodning I praktiken är kompressionen ≥ 50%. Om man vidareutvecklar kompressionen (tex tar bort nollor i strängen) får man varianter som i praktiken är snabbare än Huffman-kodning. Läs mer om LZ78 i ”Data Structures and Algorithms in Java” av M. T. Goodrich och R. Tamassia, John Wiley & Sons, 1998. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Filkomprimering ASCII-filer är textfiler där varje bokstav representeras av en 8-bitars ascii-kod. Det är alltså en fixlängdskodning Om man tittar på en textfil ser man att vissa bokstäver förekommer oftare än andra. Om man lagrar vanligt förekommande bokstäver med färre bitar än ovanliga så skulle vi kunna spara utrymme. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Filkomprimering Kodningen måste ske så att man enkelt kan avkoda strängen entydigt med kännedom om hur de olika tecknen översätts. Exempel: Antag att de tre tecknen a, b och c kodas som 0, 1 respektive 01. Om en mottagare får strängen 001 vad betyder det? aab eller ac?? Prefix-regeln: Ingen symbol kodas med en sträng som utgör prefix till en annan symbols kodsträng. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Bokstäverna lagras i löven. Den vänstra kanten betyder 0 Den högra betyder 1 Vad betyder 01011011010000101001011011010 © Anders Broberg, Lena Kallin Westin, 2007 Vi använder ett trie! 010 11 011 010 00 010 10 010 11 011 010 A B R A C A D A B R A
Vi vill ha optmial kompression! Så kort sträng som möjligt. Strängen 01011011010000101001011011010 = 29 bits kan kortas ned till 24 bitar 001011000100001100101100 med trädet Gjort bokstäverna A och R kortare och C och D längre. © Anders Broberg, Lena Kallin Westin, 2007 Gjort bokstäverna A och R kortare och C och D längre.
© Anders Broberg, Lena Kallin Westin, 2007 Huffman-kodning Börja med en serie träd bestående av ett enda löv. Till varje löv associeras en symbol och en vikt = symbolens frekvens i texten som ska kodas. Välj de två träd som har minst vikt i roten. Bygg ihop dem till ett träd där de blir barn till en ny nod. Nya nodens vikt = summan av barnens vikter. Upprepa förra punkten tills vi har ett enda stort träd. © Anders Broberg, Lena Kallin Westin, 2007 Används också till bildkomprimering.
Exempel Huffmankodning AB RACADABRA A 5/11 B 2/11 R C 1/11 D A 5/11 11/11 ABRACADABRA blir nu 23 bitar 0 100 101 0 110 0 111 0 100 101 0 © Anders Broberg, Lena Kallin Westin, 2007 6/11 B 2/11 R 4/11 C 1/11 D 2/11
© Anders Broberg, Lena Kallin Westin, 2007 Binärt sökträd Används för sökning i linjära samlingar av dataobjekt, specifikt för att konstruera tabeller och lexikon. I ett vanligt binärt träd kan man i värsta fall måsta besöka alla noder för att hitta ett element. © Anders Broberg, Lena Kallin Westin, 2007 I ett vanligt binärt träd kan man i värsta fall måsta besöka alla noder för att hitta ett element.
Binärt sökträd – Organisation Ett binärt träd som är sorterat med avseende på en sorteringsordning R av etikett-typen så att I varje nod N gäller att alla etiketter i vänster delträd går före N som i sin tur går före alla etiketter i höger delträd. Alla noder är definierade. © Anders Broberg, Lena Kallin Westin, 2007 I ett vanligt binärt träd kan man i värsta fall måsta besöka alla noder för att hitta ett element.
Informell specifikation Skiljer sig från ett vanligt binärt träd: Alla noder måste ha etiketter. Ta bort Create, Has-Label och Set-Label och inför Make som skapar rotnod med värde. Insert-operationerna utökas med ett etikettvärde. Man ska kunna ta bort inre noder också, inte bara löv. Positionsparametern i Delete-node behöver inte peka på ett löv. När man rycker bort en inre nod slits trädet sönder. Hur lagar man det? Är nedåtriktat Parent kan utelämnas. Eftersom trädet är sorterat kan man inte få stoppa in ett nytt element vart som helst. Måste uppfylla sorteringsordningen. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Varför sorterat träd? Det går snabbare att söka i strukturen… För binärt sökträd: Kolla om det sökta värdet finns i den aktuella noden. Om inte sök rekursivt nedåt i vänster eller höger delträd beroende på om det sökta elementet kommer före eller efter nodens värde i sorteringsordningen. Om det binära trädet är komplett: Värstafallskomplexitet för sökning O(log n) för ett träd med n noder. Hur ser man till att trädet blir komplett vid insättning? Mer om detta nästa föreläsning! © Anders Broberg, Lena Kallin Westin, 2007 Visa att om man stoppar in A,B,C,D,E,F,G etc i ett träd som sorterar alfabetiskt så får man ett skevt träd. Tala om att vi kommer titta på tekniker för att fixa det senare… AVL-träd Rita upp trädet R B T N S Y U Stoppa in elementet C i trädet (ska in som vänster barn till N) visa steg för steg.
Insättning i binärt sökträd © Anders Broberg, Lena Kallin Westin, 2007 Bild från sidan 289 i Janlert L-E., Wiberg T., Datatyper och algoritmer, Studentlitteratur, 2000
Borttagning av nod i binärt sökträd Hur tar bort en nod mitt i ett träd? Om den borttagna noden bara hade ett delträd: Lyft upp det ett snäpp Om den borttagna noden hade två delträd: Välj noden med det minsta värdet i höger delträd som ersättning (alternativt noden med största värdet i vänster delträd). Detta är standardkonstruktionen, är upp till den som implementerar trädet. De vanligaste tillämpningarna är inte beroende av denna detalj. Viktigt att visar sitt beslut i specifikation och dokumentation. © Anders Broberg, Lena Kallin Westin, 2007 Antag att vi har trädet R B T N S Y C U Ta bort elementet B: har bara ett delträd, lyft upp det: N T C S Y U Ta bort R Alt 1 S N Y Alt 2 N C S Y
© Anders Broberg, Lena Kallin Westin, 2007 → © Anders Broberg, Lena Kallin Westin, 2007 → Bild från sidan 289-290 i Janlert L-E., Wiberg T., Datatyper och algoritmer, Studentlitteratur, 2000
Varför inte ändra gränsytan? Eftersom man inte får sätta in ett nytt element vart som helst så kanske man lika gärna kan ersätta insert-left och insert-right med en metod place som automatiskt placerar det rätt? På samma sätt ersätta delete-node(pos, bt) med remove(val, bt)? Bägge dessa metoder ligger på en högre abstraktionsnivå än övriga metoder i gränsytan. Place implementerar man i huvudsak med hjälp av andra metoder i gränsytan vilket är lite märkligt. Strukturen döljs (för oss) och blir mer lik en mängd. © Anders Broberg, Lena Kallin Westin, 2007
Tillämpningar av Binärt sökträd Framför allt till konstruktioner av Lexikon och Tabell. Notera att inorder-traversering av binärt sökträd ger en sorterad sekvens av de ingående elementen. Kan alltså sortera element genom att stoppa in dem ett och ett i ett tomt Binärt sökträd och sedan traversera det. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Generaliseringar Ett binärt sökträd underlättar sökning i en en-dimensionell datamängd. Lätt att generalisera detta till sökning i en 2-dimensionell datamängd (quadtree) eller så hög dimension man önskar (tex octtree). © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Quadtree (Fyrträd) Organiserat som ett binärt träd med förgreningsfaktor 4 istället för 2. Tolkning (vanligast): Rotnoden delar in den givna ytan (oftast kvadrat) i fyra lika stora kvadrater. Vart och ett av de fyra barnen delar i sin tur sin kvadrat i fyra osv. Inga koordinater behöver lagras i inre noder. Kan användas för att lagra lägesinformation för punktformiga grafiska objekt. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Quadtree – forts. Man kan också använda det för att representera kurvor och ytor. Svarta kvadranter – fylls helt av objektet Grå kvadranter – fylls delvis av objektet Vita kvadranter – innehåller inte objektet Exempel på tillämpning GIS qtdemo i Matlab på peppar © Anders Broberg, Lena Kallin Westin, 2007
På Matlabs hemsida om Image processing toolbox Image and a Representation of Its Quadtree Decomposition © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Heap/Hög Ett partiellt sorterat binärt träd Etiketterna är sorterade efter en relation R så att a är förälder till b endast om a är före b i ordningen som ges av R. Insättningar och borttagningar görs så att trädet hålls komplett. Insert O(log n), Delete-first O(log n) Kan användas tex för att konstruera en prioritetskö. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Insättning i en Heap Placera den nya noden på första lediga plats. Låt sedan noden vandra uppåt i heapen tills det hamnat rätt i sorteringsordningen eller blivit rot. © Anders Broberg, Lena Kallin Westin, 2007
© Anders Broberg, Lena Kallin Westin, 2007 Borttagning ur en heap Ersätt noden som ska tas bort med den ”sista” noden i heapen. Låt denna vandra ned tills den hamnat ”rätt” eller nått ”botten”. © Anders Broberg, Lena Kallin Westin, 2007