Ohjelmoinnin peruskurssien laaja oppimäärä

Samankaltaiset tiedostot
Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Ohjelmoinnin peruskurssien laaja oppimäärä

Tutoriaaliläsnäoloista

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 1

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Tietorakenteet ja algoritmit

Scheme-kesäkurssi luento 5

Ohjelmoinnin peruskurssien laaja oppimäärä

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi

Scheme-kesäkurssi luento 2

11/20: Konepelti auki

Scheme-kesäkurssi luento 3

REKURSIO. Rekursiivinen ohjelma Kutsuu itseään. Rekursiivinen rakenne. Rakenne sisältyy itseensä. Rekursiivinen funktio. On määritelty itsensä avulla

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Algoritmit 1. Luento 3 Ti Timo Männikkö

811120P Diskreetit rakenteet

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä, kevät

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen:

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

Ohjelmoinnin peruskurssi Y1

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

815338A Ohjelmointikielten periaatteet

Algoritmit 1. Luento 13 Ti Timo Männikkö

Algoritmit 2. Luento 13 Ti Timo Männikkö

Ohjelmoinnin peruskurssi Y1

Tietorakenteet ja algoritmit. Kertaus. Ari Korhonen

C++11 lambdat: [](){} Matti Rintala

Scheme-kesäkurssi luento 4

Tietorakenteet ja algoritmit - syksy

Racket ohjelmointia osa 2. Tiina Partanen Lielahden koulu 2014

Ohjelmoinnin perusteet Y Python

Luento 4 Aliohjelmien toteutus

13. Loogiset operaatiot 13.1

A TIETORAKENTEET JA ALGORITMIT

Esimerkkejä polynomisista ja ei-polynomisista ongelmista

Ohjelmoinnin peruskurssien laaja oppimäärä

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Jakso 4 Aliohjelmien toteutus

58131 Tietorakenteet ja algoritmit (syksy 2015)

Jakso 4 Aliohjelmien toteutus

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.

Ohjelmoinnin peruskurssien laaja oppimäärä

ITKP102 Ohjelmointi 1 (6 op)

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

Ohjelmoinnin peruskurssi Y1

811120P Diskreetit rakenteet

Kerta 2. Kerta 2 Kerta 3 Kerta 4 Kerta Toteuta Pythonilla seuraava ohjelma:

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

Luku 3. Listankäsittelyä. 3.1 Listat

Ohjelmoinnin perusteet Y Python

5/20: Algoritmirakenteita III

Ohjelmoinnin peruskurssi Y1

Kysymyksiä koko kurssista?

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

Ehto- ja toistolauseet

JOHDATUS TEKOÄLYYN TEEMU ROOS

Ohjelmoinnin peruskurssi Y1

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

Ohjelmoinnin perusteet Y Python

ITKP102 Ohjelmointi 1 (6 op)

Luento 4 Aliohjelmien toteutus

Tietorakenteet ja algoritmit

Groovy. Niko Jäntti Jesper Haapalinna Group 31

Ohjelmoinnin perusteet Y Python

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

Pythonin Kertaus. Cse-a1130. Tietotekniikka Sovelluksissa. Versio 0.01b

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 1: Rekursiivinen ajattelutapa, Scheme-kielen perusteita (mm. SICP 11.2.4) Riku Saikkonen 16. 10. 2012

Sisältö 1 Kurssijärjestelyitä 2 Perusteita Scheme-kielestä, häntärekursio 3 Rekursio

Kurssijärjestelyitä kurssin sivuilla on nyt: SICP-kirjasta käsiteltävät kohdat ohjeita Schemen käytöstä ensimmäiset harjoitustehtävät (2 kierrosta 4:stä, deadlinet 31. 10. ja 12. 11.) tehtävien palautusjärjestelmä tulossa pian tehtäviin voi kysyä apua: IRC:stä (kurssin kanavalta tai assistentilta) milloin tahansa, mutta varsinkin viikottaiseen päivystysaikaan (aika tulee kurssin sivuille) tavallisen kurssin laskuharjoituksissa ti klo 812 Maari-A:ssa (laajan assistentti Miki Tolonen on toinen niiden pitäjistä) ensi viikolla on vakioajan sijaan erillinen laskuharjoitusaika to 25. 10. klo 1214 Maari-A

Kurssin käyttämä Schemen versio syksyn kurssilla käytetään Scheme-kielen R 5 RS-nimistä versiota ei siis uudempaa R 6 RS-versiota käytämme Scheme-toteutusta nimeltä Gambit-C http://www.iro.umontreal.ca/~gambit/ interaktiivinen tulkki ja tehokas kääntäjä sisäänrakennettuna hyvä debuggeri melko helppo liittää muihin ohjelmointikieliin se on valmiiksi asennettuna Niksulassa (ei Aalto-koneissa) voit asentaa sen omalle koneellesi (ohje wikissä) ja/tai hae itsellesi Niksulan tunnus (T-talon huoneesta B210, arkisin klo 12-14, sano että suoritat laajaa) ks. https://wiki.aalto.fi/display/laajaohj12/scheme-ohjeita

Sisältö 1 Kurssijärjestelyitä 2 Perusteita Scheme-kielestä, häntärekursio 3 Rekursio

Scheme ja Python Schemessä ja Pythonissa on paljon samaa, esimerkiksi: dynaaminen tyypitys (tyyppejä ei näy koodissa) samantapainen sisennystyyli (tosin Scheme ei pakota siihen) interaktiivinen tulkki ja Schemessä on erilaista muun muassa: perussyntaksi (esim. sulut) silmukkarakenteiden sijaan käytetään rekursiota muuttujien määrittelytapa ei olioita (ja funktioita käytetään enemmän) Pythonia paljon pienempi kieli monta eri toteutusta, joissa on omat standardikirjastot

Pieni Scheme-esimerkki (SICP 1.2.4) Kaksi potenssiinkorotusalgoritmia b n expt.scm (define (square n) (* n n)) ; apufunktio fast-expt:iä varten (define (slow-expt b n) (if (= n 0) 1 (* b (slow-expt b (- n 1))))) (define (fast-expt b n) (cond ((= n 0) 1) ((even? n) (square (fast-expt b (/ n 2)))) (else (* b (fast-expt b (- n 1)))))) Testiajo: (fast-expt 2 150) 1427247692705959881058285969449495136382746624

Silmukat ja häntärekursio (SICP 1.2.1) lausekielissä käytetään paljon silmukoita (for, while, jne.) Schemessä tyypillisempää on tehdä apufunktio, joka kutsuu itseään häntärekursiivisesti eli niin, että funktiokutsun jälkeen ei tehdä mitään Schemessä tämä on tehokasta (Javassa ja Pythonissa pino kasvaisi) häntärekursiivista koodia { voi lukea matemaattisemmin p jos c > n esim. alla iter(p, c) = iter(c p, c + 1) muuten Scheme fact.scm (define (factorial n) (define (iter p c) (if (> c n) p (iter (* c p) (+ c 1)))) (iter 1 1)) Python rekursiivisesti def factorial(n): def iter(p, c): if c > n: return p else: return iter(c*p, c+1) return iter(1, 1) Python fact.py def factorial(n): p = 1 c = 1 while c <= n: p = c * p c = c + 1 return p

Tavallisessa rekursiossa pino kasvaa (SICP 1.2.1) Rekursiivinen kertomafunktio (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) fact.scm esim. (fact 4):ää evaluoidessa pinoon jää lauseke (* 4 ), kun (fact (- 4 1)):tä kutsutaan perustapaukseen päästessä pinossa on (* 4 (* 3 (* 2 (* 1 )))) oikealla on pino enemmän todellisuutta vastaavassa muodossa (tosin se riippuu toteutuksesta) Kutsupino lopussa: Paluuosoite fact:iin fact:n argumentti n=0 Paluuosoite fact:iin fact:n argumentti n=1 Paluuosoite fact:iin fact:n argumentti n=2 Paluuosoite fact:iin fact:n argumentti n=3 Paluuosoite tulkkiin fact:n argumentti n=4...

Häntärekursiossa pinon ei tarvitse kasvaa (SICP 1.2.1) Häntärekursiivinen kertoma fact.scm (define (f-iter p c n) (if (> c n) p (f-iter (* c p) (+ c 1) n))) (define (fact n) (+ 0 (f-iter 1 1 n))) nyt (fact 4):ää evaluoidessa menossa on koko ajan vain yksi f-iter:n kutsu ensin (f-iter 1 1 4), sitten (f-iter 1 2 4),..., lopuksi (f-iter 24 5 4), joka palauttaa 24 Kutsupino lopussa: Paluuosoite fact:iin f-iter:n argumentti p=24 f-iter:n argumentti c=5 f-iter:n argumentti n=4 Paluuosoite tulkkiin fact:n argumentti n=4.. ilman (+ 0...):aa pinoon ei jäisi fact:istakaan mitään.

Muita tapoja tehdä silmukoita Schemessä on myös muutama silmukkarakenne: nimetty let: lyhyempi syntaksi häntärekursiiviselle silmukalle do: yleistetty tavanomainen for- ja while-silmukka nämä on sisäisesti toteutettu funktionaalisesti häntärekursiolla näitä ei kuitenkaan yleensä käytetä (varsinkaan do:ta) lisäksi Schemen makroilla olisi helppo määritellä omia silmukkarakenteita (nämäkin kaksi voi toteuttaa makroilla) Nimetty let (define (factorial n) (let iter ((p 1) (c 1)) (if (> c n) p (iter (* c p) (+ c 1))))) fact.scm do (define (factorial n) (do ((p 1 (* c p)) (c 1 (+ c 1))) ((> c n) p))) fact.scm

Globaalien ja paikallisten muuttujien määritteleminen Schemessä on monta tapaa määritellä muuttujia ja proseduureja, mutta melkein aina kannattaa käyttää alla olevia tapoja globaalit muuttujat (vain päätasolla): globaali proseduuri: (define (f x)...) tai (define f (lambda (x)...)) globaali muuttuja: (define x 3) paikalliset (esim. funktion sisäiset) muuttujat: paikallinen proseduuri: (define (f x)...) (let ((f (lambda (x)...)))...) toimii myös, mutta tällöin funktiossa ei voi viitata itseensä paikallinen muuttuja: (let ((x 3))...) useampi edellisiin viittaava paikallinen muuttuja: (let* ((x 3) (y (+ x 1)))...) eri tapoihin määritellä muuttujia palataan tulkkien yhteydessä, mutta nämä säännöt riittävät käytännön ohjelmointiin

Sisältö 1 Kurssijärjestelyitä 2 Perusteita Scheme-kielestä, häntärekursio 3 Rekursio

Rekursiivinen ajattelutapa Tässä eräs tapa ratkaista ohjelmointiongelma rekursiivisesti (vrt. matemaattinen induktio): 1 Etsi perustapaukset eli triviaaliratkaisu. 2 Keksi tapa ratkaista iso ongelma muokkaamalla pienemmän ongelman ratkaisua tai yhdistämällä useamman pienemmän ongelman ratkaisut. Esimerkki: Kuinka monella eri tavalla annettu luku voidaan jakaa tekijöihin? (ei vain alkulukuihin esim. 12 = 2 2 3 = 2 6 = 3 4 eli 3 tavalla) Helpommin ratkaistava versio: Kuinka monella eri tavalla n voidaan jakaa tekijöihin käyttäen vain m 2:ta tai suurempia lukuja? Perustapaus: 0 tapaa, jos m m > n

Rekursiivinen ajattelutapa: tekijöihinjakoesimerkki Määritellään proseduuria f (n, m) = kuinka monella tavalla n voidaan jakaa tekijöihin käyttäen vain m:ää tai suurempia lukuja? Perustapaus: f (n, m) = 0, jos m m > n Helpompien ongelmien (pienempi n tai isompi m lähestyy perustapausta) ratkaisujen avulla kaksi vaihtoehtoa: jos n ei ole jaollinen m:llä, f (n, m) = f (n, m + 1) (sillä tekijoissä ei ole m:ää) muuten f (n, m) = 1 + f (n/m, m) + f (n, m + 1). (esim. f (12, 2) = 1 + f (6, 2) + f (12, 3) eli 2 6, 6:n tavat, 3) Scheme-koodina (define (divisible? n m) (= (remainder n m) 0)) (define (f n m) (cond ((> (* m m) n) 0) ((divisible? n m) (+ 1 (f (/ n m) m) (f n (+ m 1)))) (else (f n (+ m 1))))) (define (ways-to-factor n) (f n 2)) factor.scm

Toinen rekursioesimerkki: Robotit ruudukossa ### # # ### # # # ### eräs tehtävä (tai osa siitä) viimevuotisesta NCPC-ohjelmointikilpailusta: robotti lähtee ruudukon vasemmasta yläkulmasta ja osaa liikkua vain oikealle tai alas, muttei seinään # voiko se päästä oikeaan alakulmaan, ja montako eri reittiä sinne on? miten ratkaisisit tämän Pythonilla tai Schemellä? rajapinta esim. (numpaths f n), missä n on ruudukon koko (n n) ja (f x y) palauttaa 1 jos ruudussa (x, y) on seinä, muuten 0 (tai Pythonissa numpaths(f, n), ja f voisi toki olla funktion sijaan kaksiulotteinen taulukko) älä mieti tehokkuutta vielä

Ratkaisu rekursiolla Scheme-koodina robotpaths.scm (define (numpaths f n) (define (paths-from x y) (cond ((or (>= x n) ; reunan yli? (>= y n) (= (f x y) 1)) ; seinässä? 0) ((= x y (- n 1)) ; perillä? 1) ; maalista itseensä 1 polku (else (+ (paths-from (+ x 1) y) ; oikealle (paths-from x (+ y 1)))))) ; ja alas (paths-from 0 0)) tällainen rekursiivinen ratkaisu on nopea tehdä, muttei tässä esimerkissä kovin tehokas ei siksi että rekursio olisi sinänsä hidasta, vaan koska apufunktiota kutsutaan monta kertaa samoilla argumenteilla ohjelmointikilpailussa tätä piti optimoida tallentamalla jo laskettuja apufunktion arvoja (eli nk. dynaamisella ohjelmoinnilla)

Generatiivinen ja strukturaalinen rekursio lisäesimerkki rekursiosta kirjan kohdassa 1.2.2 (Counting change) edellisten esimerkkien kaltainen päättely on yksi rekursion käyttötarkoitus rekursiota voi ajatella olevan kahdenlaista: rakenteellinen (structural) rekursio: käydään jokin monimutkainen tietorakenne läpi pala kerrallaan rekursiivisesti (esim. edellisen esimerkin ruudukko parempia esimerkkejä SICP luvussa 2 listojen yhteydessä) generatiivinen (generative) rekursio: ohjelma tuottaa osaongelmia itse (kuten tekijöihinjakoesimerkissä) (nämä termit eivät ole kovin yleisessä käytössä)