ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

Samankaltaiset tiedostot
Algoritmit 1. Demot Timo Männikkö

Algoritmit 1. Demot Timo Männikkö

Algoritmit 1. Demot Timo Männikkö

Algoritmit 1. Demot Timo Männikkö

Algoritmit 2. Demot Timo Männikkö

Algoritmit 1. Luento 8 Ke Timo Männikkö

Algoritmit 1. Luento 7 Ti Timo Männikkö

Algoritmit 2. Luento 2 Ke Timo Männikkö

Algoritmit 2. Luento 2 To Timo Männikkö

Algoritmit 2. Luento 7 Ti Timo Männikkö

Algoritmit 1. Luento 5 Ti Timo Männikkö

Algoritmit 1. Luento 12 Ti Timo Männikkö

Hakupuut. tässä luvussa tarkastelemme puita tiedon tallennusrakenteina

Algoritmit 1. Luento 12 Ke Timo Männikkö

Algoritmit 1. Luento 4 Ke Timo Männikkö

Algoritmit 2. Luento 4 To Timo Männikkö

Algoritmit 1. Luento 2 Ke Timo Männikkö

Algoritmit 2. Luento 3 Ti Timo Männikkö

Algoritmit 2. Demot Timo Männikkö

Algoritmit 2. Luento 4 Ke Timo Männikkö

(a) L on listan tunnussolmu, joten se ei voi olla null. Algoritmi lisäämiselle loppuun:

58131 Tietorakenteet ja algoritmit (kevät 2016) Ensimmäinen välikoe, malliratkaisut

Algoritmit 1. Luento 3 Ti Timo Männikkö

Algoritmit 2. Luento 3 Ti Timo Männikkö

Algoritmit 2. Luento 5 Ti Timo Männikkö

Miten käydä läpi puun alkiot (traversal)?

Algoritmit 2. Luento 14 Ke Timo Männikkö

Algoritmit 2. Luento 13 Ti Timo Männikkö

Koe ma 1.3 klo salissa A111, koeaika kuten tavallista 2h 30min

Algoritmit 2. Luento 6 Ke Timo Männikkö

A TIETORAKENTEET JA ALGORITMIT

58131 Tietorakenteet ja algoritmit (kevät 2014) Uusinta- ja erilliskoe, , vastauksia

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

Algoritmit 1. Luento 10 Ke Timo Männikkö

Algoritmit 1. Luento 14 Ke Timo Männikkö

Algoritmit 2. Luento 5 Ti Timo Männikkö

Algoritmit 1. Luento 11 Ti Timo Männikkö

Algoritmit 2. Luento 8 To Timo Männikkö

Tietorakenteet, laskuharjoitus 3, ratkaisuja

Algoritmit 2. Luento 6 To Timo Männikkö

Tietorakenteet, laskuharjoitus 7, ratkaisuja

4 Tehokkuus ja algoritmien suunnittelu

Algoritmit 2. Luento 9 Ti Timo Männikkö

ITKP102 Ohjelmointi 1 (6 op)

Algoritmit 2. Luento 9 Ti Timo Männikkö

Diskreetin matematiikan perusteet Laskuharjoitus 2 / vko 9

TKT20001 Tietorakenteet ja algoritmit Erilliskoe , malliratkaisut (Jyrki Kivinen)

Tarkennamme geneeristä painamiskorotusalgoritmia

11. Javan toistorakenteet 11.1

Algoritmit 1. Luento 6 Ke Timo Männikkö

58131 Tietorakenteet (kevät 2009) Harjoitus 6, ratkaisuja (Antti Laaksonen)

58131 Tietorakenteet (kevät 2009) Harjoitus 9, ratkaisuja (Antti Laaksonen)

Algoritmit 1. Luento 10 Ke Timo Männikkö

811312A Tietorakenteet ja algoritmit III Lajittelualgoritmeista

811312A Tietorakenteet ja algoritmit , Harjoitus 2 ratkaisu

Algoritmit 2. Luento 10 To Timo Männikkö

Algoritmit 2. Luento 10 To Timo Männikkö

List-luokan soveltamista. Listaan lisääminen Listan läpikäynti Listasta etsiminen Listan sisällön muuttaminen Listasta poistaminen Listan kopioiminen

Algoritmit 2. Luento 13 Ti Timo Männikkö

Ohjelmoinnin perusteet Y Python

Kysymyksiä koko kurssista?

Algoritmit 1. Luento 9 Ti Timo Männikkö

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

2. Seuraavassa kuvassa on verkon solmujen topologinen järjestys: x t v q z u s y w r. Kuva 1: Tehtävän 2 solmut järjestettynä topologisesti.

4. Algoritmien tehokkuus

Binäärihaun vertailujärjestys

12. Javan toistorakenteet 12.1

12. Javan toistorakenteet 12.1

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Sisällys. 11. Javan toistorakenteet. Laskurimuuttujat. Yleistä

Ohjelmoinnin perusteet Y Python

Pinot, jonot, yleisemmin sekvenssit: kokoelma peräkkäisiä alkioita (lineaarinen järjestys) Yleisempi tilanne: alkioiden hierarkia

Tietorakenteet ja algoritmit - syksy

Datatähti 2019 loppu

58131 Tietorakenteet ja algoritmit (syksy 2015)

Algoritmit 2. Luento 11 Ti Timo Männikkö

58131 Tietorakenteet ja algoritmit (kevät 2013) Kurssikoe 1, , vastauksia

Tietorakenteet, laskuharjoitus 1,

Algoritmit 2. Luento 1 Ti Timo Männikkö

Koe ma 28.2 klo salissa A111, koeaika kuten tavallista 2h 30min

1.1 Pino (stack) Koodiluonnos. Graafinen esitys ...

Taulukoiden käsittely Javalla

Nopea kertolasku, Karatsuban algoritmi

Luku 8. Aluekyselyt. 8.1 Summataulukko

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

ITKP102 Ohjelmointi 1 (6 op)

3. Hakupuut. B-puu on hakupuun laji, joka sopii mm. tietokantasovelluksiin, joissa rakenne on talletettu kiintolevylle eikä keskusmuistiin.

Kohdissa 2 ja 3 jos lukujen valintaan on useita vaihtoehtoja, valitaan sellaiset luvut, jotka ovat mahdollisimman lähellä listan alkua.

Algoritmit 2. Luento 12 To Timo Männikkö

Sisällys. 12. Javan toistorakenteet. Yleistä. Laskurimuuttujat

811312A Tietorakenteet ja algoritmit II Perustietorakenteet

Algoritmit 1. Luento 13 Ma Timo Männikkö

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

Sisältö. 2. Taulukot. Yleistä. Yleistä

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Oikeasta tosi-epätosi -väittämästä saa pisteen, ja hyvästä perustelusta toisen.

A TIETORAKENTEET JA ALGORITMIT

Transkriptio:

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012 1.1. (a) Jaettava m, jakaja n. Vähennetään luku n luvusta m niin kauan kuin m pysyy ei-negatiivisena. Jos jäljelle jää nolla, jaettava oli tasan jaollinen. int m, n; // oletetaan, että molemmat > 0 while (m >= n) m = m - n; if (m == 0) return true; return false; (b) Lasketaan lukumäärää laskuriin. Aluksi osoitin c merkkijonon alkuun. Siirretään c:tä yhdellä askeleella eteenpäin ja verrataan ensimmäiseen merkkiin. Jatketaan kunnes tulee eri merkki tai kunnes merkkijono loppuu. string mjono; // oletetaan, että pituus > 0 laskuri = 1; // ainakin yksi sama merkki c = ensimmainen(mjono); while (c!= viimeinen(mjono) c = seuraava(c); if (c == ensimmainen(mjono)) laskuri = laskuri + 1; break; // lopetetaan silmukka return laskuri; 1.2. (a) Käydään koko taulukko läpi ja etsitään sekä suurin että pienin luku, minkä jälkeen voidaan laskea erotus. // taulukko t, koko n > 0 // Suoritusaika: suurin = t[0]; // vakio pienin = t[0]; // vakio for (i = 1; i < n; i++) // silmukka suoritetaan n-1 kertaa if (t[i] > suurin) // ehtolause joka kierroksella suurin = t[i]; // sijoituslause tarvittaessa if (t[i] < pienin) // ehtolause joka kierroksella pienin = t[i]; // sijoituslause tarvittaessa erotus = suurin - pienin; // vakio Suoritusaika muotoa T (n) = n t 1 + t 2 = O(n). 1

(b) Muuttuja j osoittaa viimeisimpään eri lukuun. Muuttuja i käy läpi taulukon loput luvut. Jos i ja j osoittavat samansuuruiseen lukuun, paikka i nollataan ja j ei muutu. Muuten j siirtyy i:n kohdalle. // taulukko t, koko n > 0 // Suoritusaika: j = 0; // vakio laskuri = 0; // vakio for (i = 1; i < n; i++) // silmukka suoritetaan n-1 kertaa if (t[i] == t[j]) // ehtolause joka kierroksella t[i] = 0; // sijoituslauseet laskuri++; // tarvittaessa j = i; // sijoituslause tarvittaessa // nollien lukumäärä on nyt muuttujassa laskuri Suoritusaika muotoa T (n) = n t 1 + t 2 = O(n). 1.3. Luentomateriaalin perusteella tiedetään: Kertaluokan määrää termi, joka kasvaa nopeimmin kun n kasvaa. Joidenkin peruskertaluokkien suuruusjärjestys on log 2 n, n, n log 2 n, n 2, n 3, 2 n. Yleisesti n k kasvaa sitä nopeammin mitä suurempi k on. Tämä pätee myös kun k ei ole kokonaisluku, toisin sanoen n = n 1/2 on kertaluokaltaan pienempi kuin n. Siten saadaan (a) f(n) = O(n 5 ) (b) f(n) = O(n) (c) f(n) = O(2 n ) (d) f(n) = O(n) (e) f(n) = O(n log 2 n) (f) f(n) = O(n) Tarkempi perustelu laskemalla raja-arvot: Tiedetään, että f(n) = O(g(n)), jos = C 0. Saadaan lim n f(n) g(n) (a) lim n 3n 5 + 3n 3 + 24n n 5 800 + 50 n + 3n (b) lim n n ( 4n 3 + 2 n 4n 3 (c) lim = lim n 2 n n (d) lim n 4 log 2 n + 10n n (e) lim n 3n log 2 n + 5n n log 2 n ( = lim 3 + 3 n n + 24 ) 2 n 4 = 3 ( 800 = lim n n + 50 ) + 3 = 3 n ) 2 + 1 = 1 n ( ) 4 log2 n = lim + 10 = 10 n n ( = lim 3 + 5 n log 2 n 2 ) = 3

(f) lim n 2n/ log 2 n + n n ( ) 2 = lim n log 2 n + 1 = 1 Kohtien (c) ja (d) raja-arvoja laskettaessa seuraava L Hôpitalin sääntö voi olla f hyödyllinen: Jos lim n a f(n) = lim n a g(n) = 0 tai ja raja-arvo lim (n) n a g (n) f(n) on olemassa, niin lim n a = lim g(n) n a f (n). [Ei tarvitse osata tällä kurssilla.] g (n) 1.4. (a) Minuutti = 60 000 ms, joten laskutoimituksia on N = 60 000 kpl. 25n = N = n = N/25 = 2 400 = 2 400 5n 2 = N = n = N/5 109.5 = 109 1 2 n3 = N = n = 3 2N 49.3 = 49 2 n = N = n = log 2 N = ln N/ ln 2 15.9 = 15 (b) Laskutoimitusten lkm kasvaa 10-kertaiseksi. Merkitään n old = m = 10 000. 25n = 10 25m = n = 10m = 100 000 = 100 000 5n 2 = 10 5m 2 = n = 10m 31 622.8 = 31 622 1 n3 = 10 1 2 m3 = n = 3 10m 21 544.3 = 21 544 2 n = 10 2 m = n = log 2 10 + m 10 003.3 = 10 003 1.5. (a) d = 0; // vakio for (i = 0; i < n; i++) // silmukka n kertaa c[i] = 0; // vakio for (j = 0; j < n; j++) // silmukka n kertaa c[i] += a[i][j]*b[j]; // vakio d += b[i]*c[i]; // vakio Sisimmän silmukan sisältö suoritetaan n n kertaa = O(n 2 ). (b) for (i = 0; i < n; i++) // silmukka n kertaa if (i%2 == 0) // vakio for (j = 0; j <= i; j++) // silmukka i+1 kertaa a = 2*a; // vakio for (j = i; j < n; j++) // silmukka n-i kertaa b = b/2; // vakio // (j-silmukat vain parillisilla i) Molemmat j-silmukat suoritetaan vain jos i on parillinen, ts. vain joka toisella i-silmukan kierroksella. Siten sisempien silmukoiden sisällöt suoritetaan n 2 (i + 1 + n i) = 1 2 n2 + 1 n (jos n parillinen) 2 tai n + 1 (i + 1 + n i) = 1 2 2 n2 + n + 1 2 kertaa = O(n 2 ). 3 (jos n pariton)

(c) for (i = 1; i < n; i++) // silmukka n-1 kertaa for (j = n-1; j >= i; j--) // silmukka n-i kertaa if (t[j] < t[j-1]) // vakio swap(t[j-1], t[j]); // tod.näk. vakio Sisemmän silmukan sisältö suoritetaan n 1 (n i) = (n 1)n i=1 kertaa = O(n 2 ). (n 1)n 2 = 1 2 n2 1 2 n (d) for (i = 1; i < n; i++) // silmukka n-1 kertaa k = 0; // vakio p = t[i]; // vakio for (j = i-1; j >= 0; j--) // silmukka i kertaa if (t[j] <= p) // vakio leap(j, k); // tod.näk. vakio t[j+1] = t[j]; // vakio t[k] = p; // vakio Sisemmän silmukan sisältö suoritetaan kertaa = O(n 2 ). n 1 i = i=1 (n 1)n 2 = 1 2 n2 1 2 n 2.1. (a) etsipienin(t, n) if (n == 1) return t[0]; return min(etsipienin(t, n-1), t[n-1]); Ei-rekursiivinen: Silmukka suoritetaan n 1 kertaa = O(n). Rekursiivinen: Suoritusaika on muotoa a, kun n = 1, T (n) = T (n 1) + b, kun n > 1, missä a, b > 0 vakioita = T (n) = T (n 1) + b = T (n 2) + 2b = T (n 3) + 3b = = T (1) + (n 1)b = a b + bn = O(n). 4

(b) asetaluku(t, n, luku) if (n == 1) t[0] = luku; t[n-1] = luku; asetaluku(t, n-1, luku); return; Ei-rekursiivinen: Silmukka suoritetaan n kertaa = O(n). Rekursiivinen: Suoritusaika samaa muotoa kuin (a)-kohdassa = O(n). (c) laskenollat(t, int n) if (n == 0) return 0; if (t[n-1] == 0) return (laskenollat(t, n-1) + 1); return (laskenollat(t, n-1)); Ei-rekursiivinen: Silmukka suoritetaan n kertaa = O(n). Rekursiivinen: Suoritusaika muuten samaa muotoa kuin (a)-kohdassa paitsi että rekursio päättyy vasta kun n = 0 = T (n) = T (n 1) + b = = T (0) + nb = a + bn = O(n). 2.2. (a) Aputilaa tarvitaan vain vakiomäärä (muuttujat a, b ja c). operate(yhdiste,pino) if (size(pino) < 2) return error; a = pop(pino); b = pop(pino); c = yhdiste(a,b); push(c,pino); 5

(b) Siirretään muut alkiot apupinoon, josta ne siirretään takaisin alkuperäiseen pinoon sitten kun päällimmäinen alkio on ensin sijoitettu pohjalle. Aputilaa tarvitaan apupinolle (ja muille muttujille), joten aputilan koko on samaa kertaluokkaa kuin alkuperäisen pinon koko. sink(pino) if (size(pino) < 1) return error; a = pop(pino); while (!isempty(pino)) b = pop(pino); push(b,apu); // siirretään apupinoon push(a,pino); while (!isempty(apu)) b = pop(apu); push(b,pino); // siirretään takaisin (c) Käytetään aputilana taulukkoa, josta alkiot on helppo poimia halutussa järjestyksessä. Aputilan koko on siis samaa kertaluokkaa kuin alkuperäisen pinon koko. flip(pino) n = size(pino); for (i = 1; i <= n; i++) a[i] = pop(pino); for (i = 1; i <= n; i++) push(a[i],pino); 2.3. (a) Lisätään merkki s pinoon p operaatiolla push(s,p) ja poistetaan merkki pinosta operaatiolla pop(p). Pinoon ei saa lisätä merkkiä sellaisen merkin päälle, joka on aakkosissa aikaisemmin, koska silloin alle jäänyttä merkkiä ei voi poistaa oikealla hetkellä. Tarvitaan vähintään neljä pinoa: push(d,1), push(a,1), pop(1), push(g,2), push(e,2), push(b,1), pop(1), push(f,3), push(i,4), push(c,1), pop(1), pop(1), pop(2), pop(3), pop(2), push(h,1), pop(1), pop(4) (b) Tarvitaan vähintään kaksi pinoa: push(i,1), push(d,1), push(c,1), push(b,1), push(h,2), push(g,2), push(a,1), pop(1), pop(1), pop(1), pop(1), push(f,1), push(e,1), pop(1), pop(1), pop(2), pop(2), pop(1) 6

(c) Lisätään merkki s jonoon q operaatiolla enq(s,q) ja poistetaan merkki jonosta operaatiolla deq(q). Jonoon ei saa lisätä merkkiä sellaisen merkin perään, joka on aakkosissa myöhemmin, koska silloin taakse jäänyttä merkkiä ei voi poistaa oikealla hetkellä. Tarvitaan vähintään kolme jonoa: enq(d,1), enq(a,2), deq(2), enq(g,1), enq(e,2), enq(b,3), deq(3), enq(f,2), enq(i,1), enq(c,3), deq(3), deq(1), deq(2), deq(2), deq(1), enq(h,2), deq(2), deq(1) (d) Tarvitaan vähintään viisi jonoa: enq(i,1), enq(d,2), enq(c,3), enq(b,4), enq(h,2), enq(g,3), enq(a,5), deq(5), deq(4), deq(3), deq(2), enq(f,4), enq(e,5), deq(5), deq(4), deq(3), deq(2), deq(1) 2.4. (a) Täytyy etsiä listan viimeinen tietue. Joudutaan käymään läpi koko lista, joten suoritusaika on O(n), missä n listan koko. if (first == null) // erikoistapaus: tyhjä lista last = null; p = first; while (p.next!= null) p = p.next; // nyt p osoittaa listan loppuun last = p; (b) Operaatio mielekäs vain jos listassa on vähintään kaksi tietuetta. Täytyy etsiä listan viimeinen ja toiseksi viimeinen tietue, joten suoritusaika on O(n). if (first == null) // tyhjä lista return; if (first.next == null) // vain yksi tietue return; q = null; p = first; while (p.next!= null) q = p; p = p.next; // nyt p osoittaa listan loppuun, q edeltävään tietueeseen if (q == first) // käsiteltävä erikseen... p.next = first; p.next = first.next; q.next = first; first.next = null; first = p; 7

2.5. Kaikissa tapauksissa tarvittaviin tietueisiin päästään käsiksi suoraan (ilman listan läpikäyntiä), joten suoritusajat ovat O(1). (a) if (first == null) // tyhjä lista return; if (first.next == null) // vain yksi tietue first = last = null; first = first.next; first.prev = null; (b) (c) // p osoitin lisättävään tietueeseen p.next = null; p.prev = last; if (first == null) // lisäys tyhjään listaan first = p; last.next = p; last = p; if (first!= null) // vain ei-tyhjälle listalle first.prev = last; last.next = first; // siinä kaikki! 3.1. (a) F / \ C G / \ \ A D I \ \ / \ B E H J korkeus 3 lehtisolmuja 4 (b) F / \ B I / \ / \ A D G J / \ \ C E H korkeus 3 lehtisolmuja 5 (c) F / \ E I / / \ C G J / \ \ B D H / A korkeus 4 lehtisolmuja 4 3.2. (a) Esijärjestys: 30, 20, 15, 16, 23, 37, 32, 31, 33, 40 Sisäjärjestys: 15, 16, 20, 23, 30, 31, 32, 33, 37, 40 Jälkijärjestys: 16, 15, 23, 20, 31, 33, 32, 40, 37, 30 8

(b) Haetaan solmua h, jolle h.key=32: 1. c -> null, p -> 30 2. p -> 37 c -> 37, p -> 32 c -> 32, p -> 31 p -> null 3. c.key == h.key joten löytyi (c == h) (c) Haetaan solmua h, jolle h.key=24: 1. c -> null, p -> 30 2. c -> 30, p -> 20 p -> 23 p -> null 3. c.key!= h.key joten ei löytynyt 3.3. (a) Poistetaan ensimmäinen solmu (h.key=15): 1. q -> null, p -> 30 30 2. q -> 30, p -> 20 / \ q -> 20, p -> 15 20 37 3. q.left=p.right / \ / \ 16 23 32 40 / \ 31 33 (b) Poistetaan solmu h, jolle h.key=32: 1. c -> null, q -> null, p -> 30 30 2. q -> 30, p -> 37 / \ cp -> 30, c -> 37, q -> 37, p -> 32 20 37 cp -> 37, c -> 32, q -> 32, p -> 31 / \ / \ 3. c.key == h.key joten jatketaan 15 23 31 40 4. p.right=c.right \ \ (tässä tapauksessa q == c) 16 33 cp.left=p (c) Poistetaan solmu h, jolle h.key=37: 1. c -> null, q -> null, p -> 30 30 2. q -> 30, p -> 37 / \ cp -> 30, c -> 37, q -> 37, p -> 32 20 33 q -> 32, p -> 33 / \ / \ 3. c.key == h.key joten jatketaan 15 23 32 40 4. p.right=c.right \ / (tässä tapauksessa q!= c) 16 31 q.right=p.left, p.left=c.left cp.right=p 9

3.4. Tasapainottaminen: Solmut sisäjärjestykseen; keskimmäisestä solmusta uusi juuri; pienemmistä solmuista vasen alipuu (rekursiivisesti); suuremmista solmuista oikea alipuu (rekursiivisesti). Jos solmujoukossa parillinen määrä solmuja, valitaan seuraavassa keskimmäiseksi solmuksi aina kahdesta vaihtoehdosta pienempi: 15 16 20 23 30 31 32 33 37 40 30 ^^ / \ 15 16 20 23 31 32 33 37 40 16 33 ^^ ^^ / \ / \ 15 20 23 31 32 37 40 15 20 31 37 ^^ ^^ ^^ ^^ \ \ \ 23 32 40 23 32 40 ^^ ^^ ^^ Alkuperäisen puun korkeus 3, tasot 0, 1 ja 2 täynnä. Tasapainotetun puun korkeus 3, tasot 0, 1 ja 2 täynnä. Ei oleellista muutosta. 3.5. Riittää tutkia vain puun rakenteellisessa järjestyksessä ensimmäinen ja viimeinen solmu. Etsitään nämä kaksi solmua, lasketaan molemmat etäisyydet ja valitaan niistä suurempi. p = juurisolmu; // tutkitaan vasen alipuu if (p.left == null) // vasen alipuu tyhjä vasenetaisyys = -ääretön; while (p.left!= null) p = p.left; vasenetaisyys = p.key - juurisolmu.key ; p = juurisolmu; // tutkitaan oikea alipuu if (p.right == null) // oikea alipuu tyhjä oikeaetaisyys = -ääretön; while (p.right!= null) p = p.right; oikeaetaisyys = p.key - juurisolmu.key ; suurinetaisyys = max(vasenetaisyys, oikeaetaisyys); Kaksi hakuoperaatiota, joiden askelten lukumäärä puun korkeus = aikavaativuus tasapainoiselle puulle O(log n), degeneroituneelle puulle O(n). 10