Kysymyksiä koko kurssista? Lisää kysymyksesi osoitteessa slido.com syötä event code: #8777 Voit myös pyytää esimerkkiä jostain tietystä asiasta Vastailen kysymyksiin luennon loppupuolella Tätä luentoa koskevista asioista voi ilman muuta kysyä luennon aikana Asiattomiin kysymyksiin ei tietenkään vastata/reagoida 379
Arvostelu (3op) Osa-alue Kotitehtävät ja palaute Luentoläsnäolo 0 % Tutoriaaliläsnäolo 5/6 Minimisuoritus 50% pisteistä Tutoriaalipisteet 50% pisteistä ViLLE näyttää arvion arvosanasta Toiminto on kuitenkin ensimmäistä kertaa käytössä, ilmoittakaa, jos huomaatte jotain kummallista 380
Arvostelu (5op) Vaatimukset: 3op osio suoritettu (myös aiemman vuoden suoritus käy) Tentti läpäisty (yli 50%) Arvosanaan vaikuttaa tehtyjen ViLLE-tehtävien pistemäärä (korkeintaan +1.0 arvosanaa) Nettiopsuun tulee kaksi arvosanaa: 3op ja 2op. 381
Mentorointi Mentorointi vielä 17.10 ja 24.10 Luokassa K127 klo. 16-18 Kokeilu: ainakin ensi maanantaina voi mentoroinnissa pyytää, että joku vanha kierros avataan mentoroinnin ajaksi Jos kokeilu menee hyvin, jatketaan samaa 382
Tentistä Tenttitärppejä: Lukujärjestelmämuunnos Ohjelmointi Pitää ehdottomasti ymmärtää tulostamisen ja palauttamisen ero, jotta näistä saa pisteitä Monivalintaa teoriasta Abstraktien tietotyyppien tunnuspiirteitä 383
Rekursio, puut ja kertaus 384
Tänään Iteraatio ja rekursio Puut Kertaus 385
Iteraatio ja rekursio
Iteraatio ja rekursio Algoritmiseen ongelmanratkaisuun on kaksi päästrategiaa: 1. Iteraatio (iteration) Toiston avulla oikeaan ratkaisuun lähestyvä ratkaisutapa 2. Rekursio (recursion) Moduuli ratkaisee pienempiä osaongelmia kutsumalla itseään Molemmat ovat tapoja etsiä ongelman ratkaisua
Iteraatio Tavallinen menettely imperatiivisessa ajattelussa Tietokoneen toiminta on luonnostaan iteratiivista Iteraatioperiaate: jotakin toimintaa toistamalla päästään lähemmäs ratkaisua Tarkoitus tuottaa paranevia välitiloja, kunnes Saadaan tarkka ratkaisu tai Saadaan riittävän hyvä likiarvo ratkaisulle
Algoritmi: Iteratiivinen lineaarihaku Parametrit lista, avain ja alku (indeksi), josta haku aloitetaan Tehtävänä palauttaa True, jos avain on listassa indeksin jälkeen ja False muuten def lineaarihaku(lista, avain, alku): for i in range(alku, len(lista)): if lista[i] == avain: return True return False 390
Iteraatio Iteraatio voidaan jakaa kolmeen osaan: Alustus Alustetaan alkuarvot joita muokataan kohti lopullista ratkaisua Testaus Testataan nykytilaa (muuttujien arvoja) ehtoon, joka määrittää lopetetaanko iteraatio Arvojen päivitys Päivitetään algoritmin tilaa (muuttujien arvoja) niin, että ne lähestyvät lopullista ratkaisua
Iteraatio # summataan listan alkioita kunnes summa on yli 100 def summaakunnespaljon(lista): summa = 0 i = 0 while summa <= 100: summa = summa + lista[i] i = i + 1 return summa Alustus Testaus Arvojen päivitys 392
Rekursio
Rekursio Osatehtävän ratkaisemiseen voidaan käyttää mitä tahansa tehtävän ratkaisevaa alimoduulia Jos osatehtävä on samankaltainen (mutta pienempi) kuin moduulin tehtävä, voidaan moduulia itseään käyttää ratkaisun osana Tällöin moduulin määrittely sisältää moduulin itsensä kutsun Moduuli on siis rekursiivinen
Algoritmi: Rekursiivinen lineaarihaku Parametrit lista, avain ja indeksi, josta haku aloitetaan Tehtävänä palauttaa True, jos avain on listassa indeksin alku jälkeen ja False muuten def lineaarihaku(lista, avain, alku): if alku >= len(lista): return False if lista[alku] == avain: return True return lineaarihaku(lista, avain, alku+1) 397
Rekursiivisten moduulien vaatimukset Moduulissa pitää kuvata yksi triviaali, ei-rekursiivisesti ratkeava tapaus Kutsutaan rekursion kannaksi Jokaisen rekursion askeleen tulee lähestyä triviaalia tapausta Kutsutaan usein rekursioaskeleeksi Vaatimuksista seuraa, että rekursiivisen kutsun on oltava ehdollinen Jos ei ehtoa, rekursio jatkuu loputtomiin...
Algoritmi: Rekursiivinen lineaarihaku Syötteet lista, avain ja indeksi, josta haku aloitetaan Tehtävänä palauttaa True, jos avain on listassa indeksin jälkeen ja False muuten def lineaarihaku(lista, avain, alku): if alku >= len(lista): return False if lista[alku] == avain: return True return lineaarihaku(lista, avain, alku+1) Rekursion kanta Rekursioaskel 399
Rekursio - esimerkki kertoma(n) on kaikkien välillä 1..n olevien kokonaislukujen tulo, eli kertoma(n) = n*(n-1)*(n-2)*...*3*2*1 Toisaalta tämä voidaan määritellä myös rekursiivisesti: 1. kertoma(1) = 1 2. kertoma(n) = n * kertoma(n-1) (huom: kertoma määritellään myös 0:lle, kertoma(0)=1, mutta se kasvattaisi esimerkkejä tarpeettomasti)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) k = kertoma(3) Kutsutaan kertomafunktiota
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) kertoma(3) n=3, joten päästään elselohkoon k = kertoma(3)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) kertoma(3) kutsutaan kertoma(3-1) k = kertoma(3)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) kertoma(2) kertoma(3) Nyt n=2, joten mennään jälleen else-lohkoon k = kertoma(3)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) kertoma(2) kertoma(3) Kutsutaan kertoma(2-1) k = kertoma(3)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) kertoma(1) kertoma(2) kertoma(3) Nyt n=1, palautetaan 1 kutsujalle k = kertoma(3)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) kertoma(2) kertoma(3) Tässä n=2, joten palautetaan 2 * 1 k = kertoma(3)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) kertoma(3) Tässä n=3, joten palautetaan 3*2 k = kertoma(3)
Rekursio - esimerkki def kertoma(n): if n == 1: return 1 else: return n * kertoma(n-1) k = kertoma(3) kertoma(3) palautti arvon 6
Rekursio - esimerkki Sama voidaan visualisoida paperille: kertoma(4) =4*kertoma(3) =4*(3*kertoma(2)) =4*(3*(2*kertoma(1))) =4*(3*(2*1)) =4*(3*2) =4*6 =24 Jossa sulkeet ilmaisevat suoritusjärjestystä
Iteraatio vai rekursio Rekursio on aina korvattavissa iteraatiolla ja päinvastoin Todistus sivuutetaan Rekursion käyttö saattaa olla muistia tuhlaavaa Riippuu sekä rekursiofunktion rakenteesta että käytetystä ohjelmointikielestä Joillekin ongelmille on helpohkosti löydettävissä rekursiivinen tai iteratiivinen ratkaisu, muttei molempia
Abstraktit tietotyypit - puu
Abstraktit tietotyypit - puu Puu (tree) on lineaarisen listan yleistys Kaikilla alkioilla on yksikäsitteinen edeltäjä (kuten listassa) Alkiolla voi olla monta seuraajaa ja eri solmuilla voi olla eri määrä seuraajia Rakenteesta tulee siis puumainen hierarkia Tieto esitetään rakenteen haarautumiskohdissa eli solmuissa (nodes) Puun haarat (branches) edustavat loogisia suhteita peräkkäisillä tasoilla olevien solmujen välillä
Abstraktit tietotyypit - puu Solmun seuraajia sanotaan lapsiksi Solmun edeltäjää sanotaan vanhemmaksi Q:n vanhempi P:n lapsi
Abstraktit tietotyypit - puu Hierarkian ylimmän tason alkiota kutsutaan puun juureksi (root) Juurisolmulla ei ole edeltäjää Puun juuri
Abstraktit tietotyypit - puu Alimman tason solmuja nimitetään lehdiksi (leaves) Alla vihreällä Lehtisolmuilla ei ole seuraajia
Abstraktit tietotyypit - puu Ei-lehtisolmuja kutsutaan sisäsolmuiksi Kuvassa valkoiset solmut Sisäsolmuilla on siis aina seuraaja tai seuraajia
Abstraktit tietotyypit - puu Puun haaroja jotka muodostavat solmun ja sen välittömän tai välillisen seuraajan yhdistävän reitin kutsutaan poluksi (path) Polun pituus on välillä olevien haarojen (kaarien) lukumäärä Huom: määritelmissä eroja, voidaan laskea solmujen lukumäärä Polun P-R pituus on 2
Abstraktit tietotyypit - puu Puun korkeus on pisimmän polun pituus juuresta lehteen Puun korkeus on 4
Abstraktit tietotyypit - puu Solmun aste on sen seuraajien lukumäärä Aste on 2 Aste on 4
Abstraktit tietotyypit - puu Listojen tavoin puu samaistetaan usein juuren kanssa Usein sovitaan, että puun jokaisella solmulla on tarkalleen k lapsipuuta Osa lapsipuista voi olla tyhjiä (puu, jossa ei ole yhtään solmua) Tällaista puuta kutsutaan k-haaraiseksi tai k-ariseksi puuksi (kary)
Abstraktit tietotyypit - puu Solmun aste on siis sen ei-tyhjien alipuiden lukumäärä Jos puun jokaisen solmun (paitsi lehtisolmujen) kaikki k alipuuta ovat eityhjiä, sanotaan puuta täydelliseksi k-haaraiseksi puuksi
Abstraktit tietotyypit - puu Alla olevan puun ariteetti on 4 (eli 4-haarainen puu) Ei ole täydellinen, esim. solmulla Q on vain 2 ei-tyhjää alipuuta Kuvaan ei ole merkitty tyhjiä alipuita
Abstraktit tietotyypit - binääripuut Lista on 1-haarainen puu 2-haaraista puuta kutsutaan binääripuuksi (binary tree) Solmun seuraajia sanotaan vasemmaksi ja oikeaksi alipuuksi Binääripuu on yksinkertainen, mutta ilmaisuvoimainen Usein käytetty Niistä esiintyy useita variantteja
Abstraktit tietotyypit - binääripuut Emme esitä binääripuun tai solmujen toteutustapaa tällä kurssilla, mutta tehtävissä käytämme solmuja pistenotaatiolla: solmu.data - solmuun liitetty datamuuttuja solmu.vasen - solmun vasen alipuu solmu.oikea - solmun oikea alipuu Pistenotaation semantiikka selviää kurssilla Algoritmin ja ohjelmoinnin peruskurssi 430
Abstraktit tietotyypit - binääripuut Binääripuun juuri
Abstraktit tietotyypit - binääripuut Juuren vasen lapsi Juuren oikea lapsi
Abstraktit tietotyypit - binääripuut Ei vasenta lasta Ei oikeaa lasta
Abstraktit tietotyypit - binääripuut Puu ei ole lineaarinen rakenne, mutta solmut voidaan luetella systemaattisessa järjestyksessä (ei suuruus, vaan läpikäyntijärjestys) Oletetaan, että binääripuuta läpikäydessä jokaisen solmun osalta käsitellään: Itse solmu Rekursiivisesti vasen alipuu Rekursiivisest oikea alipuu Saadaan kolme vaihtoehtoista järjestystä: Esijärjestys (preorder tree traversal): solmu käsitellään ennen alipuita Sisäjärjestys (inorder): solmu käsitellään alipuiden välissä Jälkijärjestys (postorder): solmu käsitellään alipuiden jälkeen
Esimerkki: Sisäjärjestys def sisäjärjestys(p): if not p.ontyhjä(): sisäjärjestys(p.vasen) print p.data sisäjärjestys(p.oikea) 435
Abstraktit tietotyypit - binääripuut Esijärjestys: 80, 40, 39, 17, 45, 77, 80, 85, 89 Sisäjärjestys: 17, 39, 40, 45, 77, 80, 80, 85, 89 Jälkijärjestys: 17, 39, 77, 45, 40, 89, 85, 80, 80
Abstraktit tietotyypit - binääripuut Muistisääntö läpikäynteihin Piirretään viiva puun ympäri Esijärjestys: viiva ohittaa solmun vasemmalta Sisäjärjestys: viiva ohittaa solmun alapuolelta Jälkijärjestys: viiva ohittaa solmun oikealta Esijärjestys: 80, 40, 39, 17, 45, 77, 80, 85, 89 Sisäjärjestys: 17, 39, 40, 45, 77, 80, 80, 85, 89 Jälkijärjestys: 17, 39, 77, 45, 40, 89, 85, 80, 80
Kertaus 438
Parametrien välityksestä funktioille Pythonissa parametrien välitys on teknisesti aina samanlaista: Funktiolle välitetään viittaus arvoon Näennäinen ero tulee siitä, että osaa arvoista ei voi muuttaa, vaan niistä luodaan kopio Käytännössä tämän voi ajatella seuraavasti, vaikka se ei teknisesti ole oikein, mutta käytännössä on näin: Perustyypit, eli kokonaisluvut, desimaaliluvut, merkkijonot ja totuusarvot välitetään kopioimalla Listoja ei kopioida, funktio saa viittauksen todellisen parametrin listaan
Parametrien välitys esimerkki 1 Esimerkki: def muutalistaa(plista): print "saatiin", plista # tulostaa [1, kaksi, 3] plista[2] = "nelja print "muutettiin:", plista # tulostaa [1, kaksi, nelja ] lista = [1, "kaksi", 3] print 'ennen:', lista # tulostaa [1, kaksi, 3] muutalistaa(lista) print 'jalkeen', lista # tulostaa [1, kaksi, nelja ]
Parametrien välitys esimerkki 2 def kasvatajatulosta(a): a = a + 1 print a Kasvattaa paikallisen a:n (parametrin) arvoa a = 7 kasvatajatulosta(a) print a Tulostaa 8 Tulostaa 7, funktio ei muuttanut muualla ohjelmassa käytetyn a muuttujan arvoa
Return-lauseesta Return-lause palauttaa lausekkeen arvon funktion kutsujalle Funktion suoritus päättyy return-lauseeseen (tai funktion loppuun, jos returnlause ei tule vastaan) Return-lause ilman lauseketta palauttaa arvon None, tätä voidaan käyttää lopettamaan funktion suoritus sopivassa kohdassa, kun palautusarvoa ei tarvita def kertoma(n): if n < 0: if n == 0: return return 1 return n*kertoma(n-1) 442
Nämä funktiot palauttavat aina saman arvon def f(): return 2 def g(): if True: return 2 return 3 def h(): return 2 return 3 def j(): print 10 return 2 def k(): if False: return 4 for i in range(2,100): return 2 return 3 # tulostaminen ei ole palauttamista 443