Några svar till TDDC70/91 Datastrukturer och algoritmer

Relevanta dokument
Tommy Färnqvist, IDA, Linköpings universitet

Magnus Nielsen, IDA, Linköpings universitet

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

Datastrukturer. föreläsning 3. Stacks 1

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

Lösningar Datastrukturer TDA

Algoritmer, datastrukturer och komplexitet

Algoritmer, datastrukturer och komplexitet

Tentamen med lösningsförslag Datastrukturer för D2 DAT 035

Föreläsning 2 Datastrukturer (DAT037)

DD1320 Tillämpad datalogi. Lösning (skiss) till tenta 20 okt 2011

Tentamen: Programutveckling ht 2015

Ekvivalensrelationer

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

Asymptotisk komplexitetsanalys

Lösningsförslag till tentamen Datastrukturer, DAT037,

Programkonstruktion och Datastrukturer

Abstrakta datatyper. Primitiva vektorer. Deklarera en vektor

Föreläsning 4. Kö Implementerad med array Implementerad med länkad lista Djup kontra bredd Bredden först mha kö

Rekursion och induktion för algoritmkonstruktion

Tentamen Datastrukturer för D2 DAT 035

n (log n) Division Analysera skolboksalgoritmen för division (trappdivision). Använd bitkostnad.

Tommy Färnqvist, IDA, Linköpings universitet

Föreläsning Datastrukturer (DAT037)

Träd Hierarkiska strukturer

Lösningsförslag till tentamen Datastrukturer, DAT037 (DAT036), Tiden det tar att utföra en iteration av loopen är oberoende av värdet på

Föreläsning 2. Stackar, köer och listor TDDC91,TDDE22,725G97: DALG. Innehåll. 1 ADT stack. 1.1 Tillämpningar

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

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

Föreläsning 5 Innehåll

Föreläsning 5 Innehåll. Val av algoritm och datastruktur. Analys av algoritmer. Tidsåtgång och problemets storlek

Föreläsning Datastrukturer (DAT036)

Algoritmer och datastrukturer TDA Fredrik Johansson

Tentamen Datastrukturer (DAT036)

Datastrukturer. föreläsning 9. Maps 1

Föreläsning 9 Datastrukturer (DAT037)

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

Algoritmanalys. Inledning. Informationsteknologi Malin Källén, Tom Smedsaas 1 september 2016

Föreläsning 8 Datastrukturer (DAT037)

Föreläsning 6: Introduktion av listor

Tentamen i Algoritmer & Datastrukturer i Java

TDDI16 Datastrukturer och algoritmer. Algoritmanalys

SORTERING OCH SÖKNING

Tentamen Datastrukturer (DAT036)

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

Lösningsförslag till tentamen Datastrukturer, DAT037,

Algoritmer och datastrukturer TDA143

SCB :-0. Uno Holmer, Chalmers, höger 2 Ex. Induktiv definition av lista. // Basfall

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

Rekursion. Koffman & Wolfgang kapitel 5

Föreläsningsanteckningar F6

TENTAMEN I DATASTRUKTURER OCH ALGORITMER DVG B kl. 14:00-19:00

Algoritmer och effektivitet. Föreläsning 5 Innehåll. Analys av algoritmer. Analys av algoritmer Tidskomplexitet. Algoritmer och effektivitet

Ordnad lista. Listor... Ordnad lista... Ordnad lista typer

FÖRELÄSNING 11 DATALOGI I

Tommy Färnqvist, IDA, Linköpings universitet. 1 Sortering Heap-sort Merge-sort Sammanfattning... 10

Sökning och sortering

Tildatenta Lösningsskiss

Programmering för språkteknologer II, HT2014. Rum

Algoritmer och datastrukturer H I HÅKAN S T R Ö M B E R G N I C K L A S B R A N D E F E L T

Föreläsning Datastrukturer (DAT036)

Föreläsning Datastrukturer (DAT037)

Tentamen Datastrukturer D DAT 035/INN960

Föreläsning 4 Datastrukturer (DAT037)

Föreläsning 13 Datastrukturer (DAT037)

Bakgrund och motivation. Definition av algoritmer Beskrivningssätt Algoritmanalys. Algoritmer. Lars Larsson VT Lars Larsson Algoritmer 1

Föreläsning 5. Rekursion

Datastrukturer och algoritmer. Föreläsning 4 Test, Stack och Kö

Dugga Datastrukturer (DAT036)

Föreläsning 5: Dynamisk programmering

ADT Kö. Seminarium 4 Köer och Stackar Innehåll. Operationer. ADT Stack. Definition. Definition

Quicksort. Koffman & Wolfgang kapitel 8, avsnitt 9

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

Programmering II (ID1019) :00-11:00

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

Föreläsning 10. Riktade grafer. Viktade grafer. TDDC91,TDDE22,725G97: DALG. Innehåll. Innehåll Riktade grafer A 10.3

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Tentamen i Algoritmer & Datastrukturer i Java

Föreläsning 2. Kortaste vägar i grafer.

Länkade listor kan ingå som en del av språket, dock ej i C Länkade listor är ett alternativ till:

Föreläsning 6 Datastrukturer (DAT037)

Föreläsning Datastrukturer (DAT036)

Lösning av några vanliga rekurrensekvationer

Föreläsning 11 Datastrukturer (DAT037)

Datastrukturer och algoritmer

Föreläsning 9 Innehåll

Föreläsning 8 Datastrukturer (DAT037)

CS - Computer science. Datateknik Informationsbehandling Datalogi Datavetenskap (ÅA 2008)

Översikt. Stegvis förfining. Stegvis förfining. Dekomposition. Algoritmer. Metod för att skapa ett program från ett analyserat problem

Introduktion till algoritmer - Lektion 4 Matematikgymnasiet, Läsåret Lektion 4

Lösningsförslag för tentamen i Datastrukturer (DAT036) från

ADS : STACK ADT: STACK. Stack och Kö -Implementering - Tilllämpningar. Oftast förekommande metoder i Stack. TopOfStack

Tentamen'('Datastrukturer,'algoritmer'och'programkonstruktion.'

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

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

Tentamen TEN1 HI

Datastrukturer. föreläsning 10. Maps 1

Tommy Färnqvist, IDA, Linköpings universitet. 2 Rekursion i C Implementation av rekursion Svansrekursion En till övning...

Föreläsning Datastrukturer (DAT036)

Transkript:

Några svar till TDDC70/91 Datastrukturer och algoritmer 2011--18 Följande är lösningsskisser och svar till uppgifterna på tentan. Lösningarna som ges här ska bara ses som vägledning och är oftast inte tillräckliga som svar på tentan. 1. (a) Sant. log(n!) < log(n n ) = n log(n) som växer polynomiskt. (b) Sant. Enligt definitionen av O behöver vi två konstanter c > 0 och n 0 1 sådana att max{f(n), g(n)} c(f(n) + g(n)) för varje heltal n n 0. Eftersom funktionerna f(n) och g(n) är icke-negativa är maximum av de två funktionerna alltid mindre än summan av funktionerna. Detta gäller för c = 1 och n 0 = 1. 2. Den grundläggande idén är att om två prov är olika så kan de förkastas eftersom ett av dem inte tillhör majoriteten och majoriteten bevaras om vi gör detta. Algoritmen behandlar proverna ett och ett och håller reda på en kandidat c till att vara ett majoritetsprov och dess multiplicitet k. Invarianten vi använder är att om vi lägger till k kopior av prov c till de obehandlade proverna så är majoritetsprovet i ursprungsuppsättningen av prover och denna nya uppsättning prover samma. Algorithm 0.1: FindMajority(S) k 0 for i 0 to n 2 if k = 0 { k 1 then do c S[i + 1] if S[i + 1] = c else then k k + 1 else k k 1 return (c) Alternativa lösningar skulle kunna innebära att gå genom arrayen med prover och jämföra varje konsekutivt par. Om ett par innehåller distinkta prov, kasta bort dem. Om ett par innehåller två likadana prov, behåll ett av dem. Utför sedan samma procedur på resterande prover. I varje sådant svep över alla kvarvarande prover kastas åtminstone hälften av proverna bort. Låt oss, för enkelhets skull, anta att n = 2 k. Då är antalet jämförelser som behöver utföras inte fler än n/2 + n/4 + n/8 +... + 1 = 2 k 1 +... + 1 = 2 k 1 = n 1. 3. (a) 3 2 2 8 2 1

9 9 1 9 9 7 9 7 6 9 7 9 9 4 9 (b) 3 3 3 2 3 2 8 2 8 8 8 9 8 9 1 9 1 9 1 7 9 1 7 6 1 7 6 7 6 7 6 4 6 4 4 Algorithm 0.2: Reverse(Q) (c) S en tom stack while! Q.isEmpty() do S.push(Q.dequeue()) while!s.isempty() do Q.enqueue(S.pop()) 4. (a) (b) Djupet av en nod v är lika med djupet av föräldern plus ett. Därför kommer vår algoritm att härma en preordertraversering (varje förälder måste behandlas före sina barn). För att beräkna djupet av varje nod i T anropas följande algoritm med T och T.root() som indata. 2

Algorithm 0.3: ComputeDepth(T, v) if T.isRoot(v) then setdepth(v, 0) else setdepth(v, 1 + getdepth(t.parent(v))) children T.children(v) while{ children.hasnext() child children.next() do ComputeDepth(T, child) Vi antar att children(v) går i tid O(c v ) i värsta fallet, där c v är antalet barn v har. Då tar varje rad i if -satsen tid O(1). Tilldelningen till children tar O(c v ) tid och while -loopen exekveras också c v gånger för att rekursivt beräkna djupen av alla noder i delträdet rotat i v. Om vi exkluderar de rekursiva anropen tar ComputeDeptht O(c v ) tid. Hur lång tid tar ComputeDepth(T, T.root())? Notera att för varje nod v i T anropar vi ComputeDepth(T, v) exakt en gång (eftersom varje nod har som mest en förälder och vi börjar med roten i T ). Därför är exekveringstiden för ComputeDepth(T, T.root()) lika med den sammanlagda tiden det tar att exekvera den icke-rekursiva delen av ComputeDepth för varje nod i T. Det blir totalt v T O(c v) = O( v T c v), vilket är O(n). En alternativ lösning till det här problemet behöver en extra datastruktur som kan göra insättningar och borttagningar i O(1) tid (t.ex. stackar och köer). Följande är en algoritm som använder en stack för att beräkna djupet. För att få till en algoritm som använder en kö får vi starta med en tom kö och ersätta alla push- och pop-operationer med anrop till enqueue respektive dequeue. Algorithm 0.4: ComputeDepth(T ) current T.root() S en tom Stack S.push(current) while!s.isempty() current S.pop() if T.isRoot(current)) then setdepth(current, 0) do else setdepth(v, 1 + getdepth(t.parent(v))) children T.children(v) while children.hasnext()) do S.push(children.next()) Anledningen till att vi kan använda både stack och kö här är att det inte spelar någon roll i vilken ordning vi behandlar barnen till varje nod, så länge vi behandlar noden själv före alla dess barn. Vi säkerställer detta genom att ta ut en nod och sedan sätta in dess barn i vilken extra datastruktur det nu är vi använder. Observera att varje nod sätts in och tas ut exakt en gång. Antalet insättningar är en övre gräns för hur många gånger den yttre while -loopen exekveras och antalet uttagningar begränsar antalet iterationer i den inre while -loopen. Allting annat är enkla operationer och metoder som tar O(1) tid, så den här algoritmen går också i O(n) tid. 3

. 6. (a) För att illustrera lösningsprincipen ger vi först en algoritm baserad på antagandet att elementen har en av två färger: röd eller blå. Vi håller reda på två index i arrayen front och end. front och end rör sig mot varandra till de möts coh då terminerar algoritmen. Medan de traverserar sekvensen gör vi följande: så fort front ser ett rött element och end ser ett blått element byter vi plats på dessa element. Det betyder att alla platser i arrayen f ront traverserar kommer att innehålla blåa element, medan alla element end traverserar kommer att innehålla röda element. Algorithm 0.: RedBlueSort(S) n S.size front 0 end n 1 while front < end if S[f ront].color() = red and S[end].color() = blue comment: swap the two elements then tmp S[front] S[front] S[end] S[end] tmp do comment: find the leftmost red element if such exists while S[front].color() = blue and front < end do front front + 1 comment: find the rightmost blue element if such exists while S[front].color() = red and front < end do end end 1 Algoritmen är in-place och eftersom front och end rör sig mot varandra besöks varje element i sekvensen av någon av dem exakt en gång. Varje gång vi inkrementerar front eller dekrementerar end utförs som mest en swap-operation och som mest tre kontroller (färgkontroll och möjligtvis två kontroller av f ront < end). Alla dessa tar konstant tid att utföra. Därför är körtiden för RedBlueSort O(n). Algoritmen för fallet med k färger är baserad på ovanstående algoritm. k gånger gör vi följande: Vi håller reda på right boundary för S (initialiserad till n). Vi väljer en av k färger, color i som vi inte valt förut. Vi sorterar arrayen S precis som ovan förutom att vi använder color i som den röda färgen och alla färger som inte är color i som den blåa färgen. Dessutom sorterar vi endast element i S som finns mellan 0 och (inte inklusive) right boundary. Efter att vi är klara sätter vi right boundary till det värde indexen front och end konvergerat till. Observera att en iteration av den här algoritmen har exekveringstid O(n) eftersom det, i princip, är samma algoritm som för fallet med två färger och den körs k gånger. Därför blir den totala exekveringstiden O(nk). 4

Algorithm 0.6: SingleColorSort(S, right boundary, currcolor) front 0 end right boundary 1 while front < end if S[f ront].color() = currcolor and S[end].color() currcolor comment: swap the two elements then tmp S[front] S[front] S[end] S[end] tmp do comment: find the leftmost currcolor element if such exists while S[front].color() currcolor and front < end do front front + 1 comment: find the rightmost non-currcolor element if such exists while S[front].color() = red and front < end do end end 1 if S[f ront].color() = currcolor then return (f ront) else return (end) Algorithm 0.7: ColorSort(S, C) right boundary S.size() for colorind { 0 to C.size() 1 currcolor C[colorind] do right boundary SingleColorSort(S, right boundary, currcolor) (b) Låt k vara ett heltal i intervallet [0, n 2 1]. Om vi representerar talet i bas n skulle det bestå av två tal (l, f), sådana att k = l n + f, där l och f båda är från intervallet [0, n 1]. Lämpligt nog är den lexikografiska ordningen på bas n-representationen precis samma som ordningen för heltalen vi vill sortera. Därför kan vi använda Radix-sort för att sortera sekvensen i linjär tid. Algorithm 0.8: LimitedSort(S, n) comment: change the representation for i 0 to n 1 do A[i] ((S[i] S[i] mod n)/n, S[i] mod n) Radixsort(A) comment: restore the representation for i 0 to n 1 do S[i] A[i][0] n + A[i][1] 7. (a) Problemet är att uppdateringen av avståndsmärkningen bara sker för noder som är grannar till den nod som behandlas och som inte är i molnet än. 2 0 inf 1 inf 2 0 1 2

(b) Det här kan misslyckas av två skäl. För det första är det inte säkert att strategin hittar någon stig alls, eftersom den inte har någon mekanism för att backa om den hamnar i situationen att alla utgående bågar från noden den befinner sig i leder till noder som redan besökts. I figuren nedan till vänster besöks noderna i ordningen start, a och b. Väl i b har alla grannar till b redan besökts, så algoritmen fallerar vid steg iv. För det andra kan strategin misslyckas om det finns tre noder v i, v j, v k där bågvikterna mellan dem uppfyller följande egenskaper: w((v i, v j )) < w((v i, v k )) (så stigen algoritmen väljer mellan v i och v k går genom v j ) w((v i, v j )) + w((v j, v k )) w((v i, v k )) (triangelolikheten) Figuren nedan till höger visar ett exempel på detta noderna besöks i ordningen start, a, b, goal med 70 som total väglängd. Den kortaste vägen, däremot, är start c goal, med längd 1. Att bågvikterna uppfyller triangelolikheten är rätt så vanligt, särskilt om de representerar ett faktiskt fysiskt avstånd mellan noderna. start a c 20 goal b start a c 20 goal b 60 6