Lösningar Datastrukturer TDA416 2016 12 21 roblem 1. roblem 2. a) Falskt. Urvalssortering gör alltid samma mängd av jobb. b) Sant. Genom att ha en referens till sista och första elementet, kan man nå både första och sista elementet med komplexiteten O( 1 ). c) Falskt. Det kan dels bero på antalet kollisioner och dels på hash-funktionens komplexitet. d) Falskt, en kö har nomalt O(1) medan en prioritetskö har O( 2 log n ) e) Falskt, för att ta bort sista elementet måste jag ha tag på det näst sista elementet. f) Falskt. Genom att använda någon form av adresssortering (t.ex. 'bucket sort' ) till ett fält av storleken 10000 element och sedan gå genom och samla upp elementen fås max(10000; n) som är 0(n). Testar: Träd Beskriv kortfattat egenskaperna hos träden... a) 2-3: träd där noderna kan ha 1 eller 2 datadelar och 2 eller 3 barn respektive splay: är ett binärt sökträd där man splayar upp sökta noder till roten. Ej balanserat. Binärt sökträd: För alla noder gäller att alla noder i vänster delträd är mindre och alla noder i höger delträd är större än noden. AVL: är ett balanserat BST. Trädet håller reda på delträdens höjd och balanserar om sig om det blir obalans. b) Sätt in talen 70, 90, 40, 50, 30, 10 i given ordning i ett AVL-träd...Tag sedan ut element 40 Vid pilen nedan så gör man en högerrotation runt 40 för att balansera. Vid tag ut 40 så har jag ersatt med minsta till höger.
2 c) Rita ett binärt träd med... Problem 3. Antag att du satt in talen 1-6 i ett splay träd... see tex https://en.wikipedia.org/wiki/splay_tree eller en visualisering på https://www.cs.usfca.edu/~galles/visualization/splaytree.html
Problem 4. Visa hur heapsort fungerar på sekvensen: 10, 7, 6, 15, 20, 9, 1, 14... Svar: I fas 1 gör man om fältet till ett POV träd dvs en heap I fas 2 plockar man ut element och lägger dom sist samt återställer POV egenskapen 3
4
Problem 5. Testar: Grafer a)...din taktik är att se om du känner någon som känner någon som 5 Svar: Gör om grafen till en viktad graf där alla vikter är 1 och använd Dijkstras algoritm. Ser också till att den håller reda på vilken som är föregående nod i kortaste vägen. Startnoden är du själv. Dijkstra ger kortaste vägen en till alla så nu kan du gå igenom vägarna till dom andra i kostnadsordning och ta den första väg som leder till en kändis. Återskapa nu kortaste vägen tillbaks till dig. O(n) + O(dijkstras) b)... genom att bli vän med någon populär person med mycket kontakter... Svar: Leta reda på noden med max utbågar: vi kan helt enkelt gå igenom alla noder i grafen och kolla hur många bågar varje nod har som utgår från dem. Löpa igenom alla noder är O(n). c)... en graf där alla förberedelsemoment var med och vilka moment som skulle... Svar: Topologisk sortering. Du byggde en riktad graf för allt som skulle göras och en båge från en nod till nästa innebär att det momentet skulle vara klart innan nästa kunde påbörjas. Topologisk sortering ger en topologisk ordning på noderna i grafen. Att noderna är topologiskt ordnade betyder att alla noder som har en båge till en given nod kommer före denna i ordningen. När noderna är saker som skall göras betyder detta att för ett givet moment ligger alla de moment som måste göras innan detta moment före det i den topologiska ordningen. Bygga grafen O(n+e) + top sort. (dfs) O(n) d) Hur hittar man cykler i en graf Svar: Dfs (eller bfs). Om man gör en dfs sökning med sig själv som startnod och kommer tillbaka till sig själv så har man hittat en cykel. O(n) Del B Implementeringar och algoritmer Problem 6. Testar: algoritmer, datastrukturer, komplexitet Antag att A är en n*n-matris med enbart ettor och nollor. Varje rad i matrisen börjar med ettor och följs sedan av enbart nollor, dessutom är antalet ettor i en rad inte fler än i raden under. Skriv en effektiv algoritm som beräknar antalet ettor i matrisen. Vilken komplexitet har din algoritm? Glöm inte motivera. Lösning: int countones(int [][] a) // Output: The number of ones in a nrofones = 0 currcol = 0 for i=0 to n-1 { while ( currcol < n && a(i,currcol) == 1 ) { currcol = currcol + 1 nrofones = nrofones + currcol return nrofones Det är lätt att se att nrofones uppdateras exakt n gånger (en gång för varje rad). Variabeln currcol kommer att uppdateras k gånger, där k är antalet ettor i sista raden och alltså är k <= n. Därför är algoritmen O(n). Lösningar som är O(n 2 ) är inte effektiva.
6 Problem 7. Representera mängder som sorterade vektorer. Ge algoritmer för att beräkna unionen och snittet av två mängder. Glöm inte att det bara skall finnas unika element i mängder. Svar: Första meninegn är viktig här. Står det Representera mängder som sorterade vektorer så är det just det man skall göra. Komplexitet O(n+m) där n,m är resp mängds storlek. set union(set a, set b) // Input: two sets a and b represented as arrays // with n and m element respectively // Output: the union of a and b let c be a new vector int i = 0 // index into a int j = 0 // index into b int k = 0 // index into c while ( i < n && j < m ) { if ( a[i] < b[j] ) { c[k++] = a[i++] else if ( a[i] = b[j] ) { c[k++] = a[i++] j++ else { c[k++] = b[j++] while (i < n) { c[k++] = a[i++] while (j < n) { c[k++] = b[j++] return c Storleken på c är såklart ett problem. I värsta fall är den n+m men det beror på antalet lika element. Men i pseoudokod kan vi bortse från sådana detaljer. set intersection(set a, set b) Input: two sets a and b represented as arrays // with n and m element respectively Output: the intersection of a and b let c be a new vector int i = 0 // index into a int j = 0 // index into b int k = 0 // index into c while ( i < n && j < m ) { if ( a[i] < b[j] ) { i++ else ( if a[i] = b[j] ) { c[k++] = a[i++] j++ else { j++ return c
Problem 8. Testar: träd Antag att vi representerar binära träd med 3 saker, target, left och rigth. Target består av key och data, left och rigth pekar på respektive barn. När vi tex söker så har vi ett element med enbart key del (data är tom) och får tillbaka ett element med både key och data. Ge pseudokod-algoritmer för att sätta in och ta bort ett element. Pesudokod innebär att du skall undvika detaljer som tex att det behövs wrapper-metoder. Om elementet redan finns vid insättning så görs ingenting. add(tree t, target e) remove(tree t, target e) Många läste binärt sökträd här men så står det inte, det står binärt träd. Jag har ändå rättat som om bägge dessa var ok. Här kan target, left och rigth, key och data och tree anses kända. Allt annat du inför måste du beskriva 7 add: sök igenom trädet för att se om e redan finns där. Om inte så sätt in på första bästa plats dvs man kan göra rekursiva anrop till vänster tills det inte finns något mer vänsterbarn och sätta in där. Remove: först måste man hitta noden (x) som skall tas bort (eller rättare sagt föräldern (p) till noden som skall tas bort). Sedan får man flera fall som vanligt: inga barn till x: sätt p.left eller p.rigth beroende på var x finns till null inget vänsterbarn till x eller inget högerbarn till x: länka förbi x c har två barn: enklast är att hitta något att byta plats på med x. Eftersom vi inte har någon ordning så kan man hitta första bästa nod utan barn. Man tar bort den noden och ersätter x med den nodens innehåll. För lösningar med BST se boken eller F-ant.