Lab-PM

Akademin för innovation, design och teknik
Caroline Uppsäll
1(4)
Datastrukturer,algoritmerochprogramkonstruktion
DVA104,HT2015
Laboration4–Implementeringochutvärderingav
sökalgoritmer
Läs noga igenom hela labbspecen innan du börjar implementera.
Nål i höstacken
Man brukar säga “det är som att leta efter en nål i en höstack” när man står inför en till
synes hopplös uppgift att leta efter någonting. En outtröttlig dator kan dock finna en nål
i en höstack - förr eller senare. Med tillräckligt sluga algoritmer kan man dessutom se
till att det går fort.
Ni ska utvärdera hur olika sökmetoder påverkas av ”höstackens storlek” då man letar
efter en ”nål” i den. För att ni ska få tider som är tillräckligt långa för att vara mätbara
måste ni ha rejält många ”strån i stacken” (ett antal miljoner element för den största
storleken). Ni behöver ha minst 3 olika storlekar (med stora skillnader i storlek) för att
kunna dra några slutsatser. Förslag på storlekar är 50 000, 500 000 samt 5 000 000
element.
(höstacken = mängd av data/tal, nål = data/tal att leta efter, strån = enskilt data/tal i
mängden)
•
För att slumpen inte ska påverka mätningen måste ni upprepa mätningen flera
gånger, förslag är att mäta tiden över minst 50-100 sökningar/varv för varje
datamängd. För varje sökning/varv så ska en ny nål slumpas fram. På detta sätt
får ni en mätning som är mer oberoende av tur eller otur.
•
Eftersom olika sökmetoder är olika effektiva, så måste ni också välja olika antal
upprepningar för olika sökmetoder. Annars kommer ni antingen att få vänta
väldigt länge på de långsamma sökmetoderna eller så blir de snabba inte
mätbara.
•
Sökmetoderna påverkas också olika av storleken på ”höstacken”, vissa är ganska
oberoende av ändrad storlek medan andra påverkas kraftigt.
•
Det kan vara bra att leta upp lite information om hur komplexiteten för de olika
sökmetoderna varierar för att lättare komma fram till ett lämpligt antal
upprepningar för respektive testfall. Alternativt får ni prova fram ett lämpligt
antal upprepningar.
•
Ni måste förstås tänka på att skala om den mätta tiden till en gemensam enhet så
att det blir jämförbart.
En viss variation i mätningarna kan uppstå om man byter dator mellan körningarna,
åtminstone om det är stor skillnad mellan datorernas prestanda. Ni bör därför notera
resultaten för de olika metoderna från körningar på samma datortyp (eller åtminstone
datorer med hyfsat lika prestanda).
För att ”höstacken” ska fungera för de olika metoderna måste ni representera den med
unika värden. Detta kan ni t.ex. göra genom att använda de filer med data som
tillhandahålls på Blackboard eller genom att fylla en n element lång ”höstack” med
värdena 1 – n. I de senare fallet kommer ni att få tänka till lite extra på hashtabellen i
uppgift 4, ni får också se till att den ”nål” ni sedan ska söka efter är slumpad på ett
sådant sätt att den inte nödvändigtvis behöver finnas i ”höstacken”.
Akademin för innovation, design och teknik
Caroline Uppsäll
2(4)
Tips1: Skapa ett fält (array) för varje höstack, alltså en array med 50.000 element, en
med 500.000 element och en med 5.000.000 element, där elementen är slumpade och
unika. Använd sedan dessa fält för att skapa de andra datatyperna som sökningen ska
köras på.
Tips2: När sökning sker i såhär stora mängder kan det hända att ni får ”stack
overflow”, detta betyder att minnet på stacken inte räcker till. Fundera på hur ni kan
lösa detta problem.
Tiden ni mäter ska bara inkludera själva sökningen. Hur stor noggrannhet behöver man
mäta med? Ta reda på vilken kod i C som behövs för att ni ska kunna få ut
exekveringstiden.
Sökningen ska ske på följande fyra sätt:
1 – Sekventiell sökning
Själva koden ni ska skriva är trivial, bara att loopa igenom höstacken (arrayen med
element) till dess att nålen (ett specifikt element) är funnen. Sökningen får i detta fall
inte förutsätta att det finns en nål att hitta. (I många verkliga problem kan det vara lika
värdefullt att få svar på om det finns en nål i höstacken, som att få reda på data som är
associerad med den).
Själva sökningen ska givetvis implementeras som en funktion.
2 – “Optimerad” sekventiell sökning
Om ni tittar på er kod för sekventiell sökning så ser det kanske ut som en hopplös
uppgift att göra den ännu enklare. Men om ni är riktigt kluriga så inser ni att det borde
gå att snabba upp sökningen genom att ta bort lite kod. Hur ska det gå till?
- Jo, genom att lägga till den ”nål” ni söker sist i ”höstacken”, dvs. efter alla ”strån” (efter
alla element) så kan villkoren för att avbryta loopen göras enklare. Ni behöver då inte
testa om slutet av fältet har nåtts, för nu vet ni att även om det inte finns någon ”nål” i
”höstacken” så får ni ändå träff på den extra ditlagda ”nålen”.
Lägg in resultatet från denna och uppgift 1 i samma diagram. Inte illa va? - Kanske inte
revolutionerande, men det borde i alla fall märkas en skillnad. Får du ingen skillnad i tid
mellan de två sökmetoderna så behöver du fundera över/diskutera hur det kan komma
sig. Den ”optimerade” versionen behöver inte göra jämförelsen vilket i teorin betyder att
den borde gå snabbare. Du kan också prova att öka storleken på datamängderna samt
antal varv som sökningen körs för att få ett tydligare utslag.
3 – Balanserat binärt sökträd
I många tillämpningar sker sökning betydligt oftare än insättning. T.ex. kan det vara så
att man skapar ”höstacken” initialt (dvs. sätter in elementen i någon datasamling) och i
just det initiala skedet spelar exekveringstiden inte någon roll. Det kan t.ex. ske vid
systemstart. Därefter är sökning den helt dominerande operationen, insättning och
borttagning av element sker förhållandevis sällan. I denna typ av tillämpningar “lönar”
det sig alltså att “investera” i en “dyr” datalagring som görs initialt, om man därigenom
uppnår att de efterföljande sökningarna blir “billiga”.
Akademin för innovation, design och teknik
Caroline Uppsäll
3(4)
I sådana fall kan ett binärt sökträd vara ett bra alternativ, speciellt om man inte vet
något om storleken på datamängden. I denna deluppgift ska ni använda ert sorterade
binära träd från laboration 3 (som också är ett sökträd).
Repetera körningen med samma storlekar på höstacken som i de två tidigare
deluppgifterna, och lägg in i ett diagram. Jämför med de tidigare körningarna. Nå?
Om ni valt att fylla en n element stor array (i 1 och 2) med värdena 0 – n så behöver ni
använda er balanseringsfunktion för att bygga trädet utifrån arrayen, annars kommer ni
att få ett degenererat träd att arbeta i (det kommer då att ta extremt lång tid att fylla
samt balansera trädet för de stora mängderna).
Tips: Oavsett hur ni valt att fylla trädet, se till att det är balanserat innan ni sätter igång
med sökningen.
4 – Hashtabell
Upphetsad av framgångarna ska ni nu göra en fjärde utvärdering. Med samma
motiveringar som i föregående deluppgift kan man tänka sig att ta kostnaden för att
bygga upp en hashtabell i utbyte mot en efterföljande effektiv uppslagning. Hashtabeller
kommer bäst till sin rätt då man i förväg har ett hum om hur mycket data som ska
lagras. Låt oss anta en sådan situation. Hur stor bör tabellen vara relativt mängden data
som man tror ska läggas in? Ni kan med fördel använda “chained hash table”. Och då
kan det kanske vara läge att tänka på återanvändning. Av vad?
Leta upp en hashfunktion som verkar bra. Det finns bland annat en del skrivet på nätet.
Ange referens som kommentar, och skriv även en motivering till ditt val. Många
hashfunktioner baserar sig på strängar. Om dina nålar t.ex. är av någon heltalstyp så blir
ju inte det riktigt samma sak. Går det att använda strängbaserade funktioner ändå på
något sätt om nycklarna utgörs av heltal?
Ni ska förstås göra er hashtabell som en ADT.
Lägg återigen in era körningar i samma diagram. Vad säger ni nu då? Kanske ni behöver
lägga in resultaten från binärt träd och hashtabell i ett eget diagram för att det ska vara
möjligt att jämföra dem inbördes.
Om ni valt att fylla en n element stor array (i 1 och 2) med värdena 0 – n så kommer ni
aldrig att få några krockar i tabellen, ni kommer alltså hamna på bästa fallet för
sökningen oavsett nål, detta måste lösas på något sätt. Nedan följer två alternativ:
•
•
När ni fyller tabellen så slumpar ni för varje nytt värde fram ett index. Värdet
som ligger på det indexet i arrayen ska sedan läggas in i tabellen. Då kommer ni
att få dubbletter i trädet. I sökningen så kommer ni alltid att hitta den första
”instansen” av dessa dubbletter. För att få mer realistiska mätvärden så kan ni
vid sökning slumpa fram en nål att söka efter och vilken ”instans” av den nålen
ni vill hitta (i ett avgränsat intervall).
Den andra lösningen på problemet är att använda de färdiggenererade filerna
med slumpade unika data som finns tillgängliga på Blackboard.
Vilka åtgärder var mest värda att investera i om man tar hänsyn till långsiktiga effekter?
Akademin för innovation, design och teknik
Caroline Uppsäll
4(4)
Redovisning
Samtliga uppgifter ska redovisas muntligt under ett och samma redovisningstillfälle
genom att visa fungerande implementationer till labbassistenten.
Om samtliga laborationer redovisats och godkänts innan tentamen erhålls bonuspoäng
på denna. Tänk dock på att redovisa labbarna utspridda under hela kursens gång då det
troligtvis inte finns tid om alla ska redovisas på slutet.