tsükliliste arvutuste programmeerimine...– negatiivsed arvud võidakse lugeda ka positiivsetest...

21
1 Tsükliliste arvutuste programmeerimine 1 Rekursioon 2 Rekursioon

Upload: others

Post on 14-Feb-2021

8 views

Category:

Documents


0 download

TRANSCRIPT

  • 1

    Tsükliliste arvutusteprogrammeerimine

    1 Rekursioon 2

    Rekursioon

  • 1 Rekursioon 3

    Rekursioon

    Rekursiivne on definitsioon (või definitsioonide rühm), mis määratlebdefineeritava objekti (või objektide rühma) tema enda (või tsükliliseltrühma liikmete endi) kaudu.

    – Mh definitsiooni paremas pooles võib esineda sama muutuja misvasakus.

    Vastavat nähtust nimetatakse rekursiooniks.

    1 Rekursioon 4

    Liigid

    • Otsene rekursioon.Definitsioon on otseselt rekursiivne, kui ta kasutab paremas poolestema enda poolt defineeritud objekti.

    • Kaudne rekursioon.Definitsioon on kaudselt rekursiivne, kui ta on üks liige järjendistx0, . . . , xl−1, kus l > 1 ja iga xi korral xi+1 definitsioon kasutab pa-remas pooles xi-d (loeme xl = x0).

    • Vastastikrekursioon.Kui kaudses rekursioonis definitsioonide arv on 2, siis öeldakse, etneed definitsioonid on vastastikku rekursiivsed.

  • 1 Rekursioon 5

    Rekursiivne kutse

    Rekursiivseks kutseks nimetatakse

    – arvutussammu, kus muutuja asendatakse samast definitsioonist,mille kaudu selle sammuni on jõutud;

    – ka muutuja esinemist oma otseselt rekursiivse definitsiooni pare-mas pooles.

    1 Rekursioon1.1 Funktsiooni määratlemine rekursiivselt

    6

    Funktsiooni määratlemine rekursiivselt

  • 1 Rekursioon1.1 Funktsiooni määratlemine rekursiivselt

    7

    Põhimõte

    Funktsiooni defineerimisel rekursiivselt tuleb kirjeldada:

    – funktsiooni väärtuse leidmine suurematel argumentidel samafunktsiooni väärtuste kaudu väiksematel argumentidel;

    – funktsiooni väärtus vähimatel argumentidel ilma rekursiivsete kut-seteta.

    ∗ Viimased on nn baasjuhud.

    1 Rekursioon1.1 Funktsiooni määratlemine rekursiivselt

    8

    Arvutus

    Kui funktsioon on defineeritud vastavalt sellele põhimõttele, siis arvu-tuse käigus

    – igal rekursiivsel kutsel argumendi väärtus väheneb,

    – kuni saab triviaalselt väikseks ja käiku lähevad baasjuhud.

  • 1 Rekursioon1.1 Funktsiooni määratlemine rekursiivselt

    9

    Tavalised argumenditüübid

    • Rekursioon täisarvudel.Järjestus on standardne (vähemalt mittenegatiivsetel täisarvudel).

    – Negatiivsed arvud võidakse lugeda ka positiivsetest suuremaks,kui funktsiooni väärtus negatiivsel argumendil määratleda väärtu-se kaudu nt vastandarvul.

    • Struktuurne rekursioon (andmestruktuuridel).Järjestus on alamstruktuurijärjestus.

    – Näiteks listist väiksemad listid on tema saba, saba saba jne.

    1 Rekursioon1.1 Funktsiooni määratlemine rekursiivselt

    10

    Standardne rekursioon

    Kõige standardsemal juhul kirjeldatakse funktsiooni väärtus mittetri-viaalsel argumendil funktsiooni väärtuse kaudu talle järjestuses vahetulteelneval andmel.

    – Funktsiooni väärtus positiivsel täisarvulisel argumendil n kirjelda-takse funktsiooni väärtuse kaudu argumendil n− 1.

    – Funktsiooni väärtus mittetühjal listil x : l kirjeldatakse funktsiooniväärtuse kaudu listil l.

  • 1 Rekursioon1.2 Protseduuri määratlemine rekursiivselt

    11

    Protseduuri määratlemine rekursiivselt

    1 Rekursioon1.2 Protseduuri määratlemine rekursiivselt

    12

    Definitsioon funktsiooni kaudu

    Kui protseduur sõltub mingist parameetrist, siis formaalselt on tegufunktsiooniga, mille väärtusteks on protseduurid.

  • 1 Rekursioon1.2 Protseduuri määratlemine rekursiivselt

    13

    Otsene defineerimine

    Pole põhimõttelisi takistusi protseduure määratleda puhtalt protseduuri-tasemel (mitte läbi funktsioonide).

    – Kuna puudub parameeter, mis võiks rekursiivsel kutsel väheneda,siis lõpetamine sõltub muudest asjaoludest (keskkonnast loetud in-fost).

    1 Rekursioon1.3 Listi määratlemine rekursiivselt

    14

    Listi määratlemine rekursiivselt

  • 1 Rekursioon1.3 Listi määratlemine rekursiivselt

    15

    Listid on tsüklilised

    Listid on olemuselt tsüklilised struktuurid: mittetühja listi saba on oma-korda list.

    Seetõttu tuleb pikemate listide defineerimisel kasutada rekursiooni.

    – Võimalik defineerida funktsiooni kaudu

    – ja ka otse.

    1 Rekursioon1.3 Listi määratlemine rekursiivselt

    16

    Otsene defineerimine

    Listi määratlemisel tuleb

    – kirjeldada listi algus (vähemalt üks element) ilma rekursiivsetekutseteta (n-ö baasjuht)

    – ja kirjeldada ülejäänud osa rekursiivselt sama listi kaudu nii, et igaelemendi arvutamisel läheks vaja ainult eespool seisvaid elemente.

  • 1 Rekursioon1.3 Listi määratlemine rekursiivselt

    17

    Erinevused funktsioonirekursioonist

    • Jaotus baasiks ja sammuks toimub väärtuse, mitte argumendi järgi.

    • Iga rekursiivset kutset rekursiivselt defineeritava listi poole kasutatak-se ülimalt üks kord.

    – Ühekordsest sidumisest piisab, kuna puuduvad parameetrid, muu-tuv keskkond vms, mis võiks arvutuse käiku muuta.

    1 Rekursioon1.3 Listi määratlemine rekursiivselt

    18

    Lõpmatud ja lõplikud listid

    Otsese rekursiooniga on võimalik defineerida nii lõplikke kui ka lõpma-tuid liste.

    – Lõpmatute listide defineerimine on lihtsam, sest puuduvad lõpeta-mistingimused.

  • 1 Rekursioon1.4 Muud näited rekursioonist

    19

    Muud näited rekursioonist

    1 Rekursioon1.4 Muud näited rekursioonist

    20

    Rekursioon suvalisel andmestruktuuril

    Rekursiivselt on võimalik defineerida mida iganes.

    – Nt puud.

    – Ka staatilised andmestruktuurid nagu paarid.

    – . . . .

  • 1 Rekursioon1.4 Muud näited rekursioonist

    21

    Paradoksaalne rekursioon

    Abistruktuure rekursiivselt defineerides on võimalik programmeerida ar-vutus, mis

    – läbib listi vaid ühe korra, kuid

    – loeb kõiki listi elemente mitu korda.

    2 Programmeerimisvõtted 22

    Programmeerimisvõtted

  • 2 Programmeerimisvõtted2.1 Arvutamine rekursiivse funktsiooni argumentidel

    23

    Arvutamine rekursiivse funktsiooniargumentidel

    2 Programmeerimisvõtted2.1 Arvutamine rekursiivse funktsiooni argumentidel

    24

    Imperatiivset programmeerimist jäljendav stiil

    Imperatiivse programmeerimise jäljendamiseks võib defineerida rekur-siivselt abifunktsiooni, mille parameetrid vastavad imperatiivse prog-rammi vahetulemusi hoidvatele muutujatele.

    – Rekursiivsel kutsel antakse edasi muudetud väärtused, esimeselväljakutsel algväärtused.

  • 2 Programmeerimisvõtted2.1 Arvutamine rekursiivse funktsiooni argumentidel

    25

    Akumulaatorid

    Akumulaator on rekursiivselt defineeritud operaatori parameeter, misarvutuse käigus kogub ja akumuleerib infot.

    – Igal rekursiivsel kutsel lisatakse sinna midagi juurde.

    2 Programmeerimisvõtted2.1 Arvutamine rekursiivse funktsiooni argumentidel

    26

    Akumulaatorite liigid

    • Loendurid.

    • Ehitajad.

    • Arvutajad.

    • . . . .

  • 2 Programmeerimisvõtted2.1 Arvutamine rekursiivse funktsiooni argumentidel

    27

    Järjehoidjad

    Järjehoidja on muutuja (tavaliselt akumulaator), mille väärtus näitabtööjärge.

    – Tsükliindeksid.

    – Läbivaadatud elementide nimekirjad.

    – . . .

    2 Programmeerimisvõtted2.2 Sabarekursioon

    28

    Sabarekursioon

  • 2 Programmeerimisvõtted2.2 Sabarekursioon

    29

    Sabarekursioon

    Funktsiooni rekursiivset definitsiooni nimetatakse sabarekursiivseks,kui tema järgi arvutades läheb rekursiivse kutse tulemus alati kogu arvu-tuse tulemuseks (ilma vaheteisendusteta).

    – Rekursiivne kutse (kui see vaadeldavas harus esineb) on konkreet-se rekursioonitaseme viimasena lõpetav tegevus.

    2 Programmeerimisvõtted2.2 Sabarekursioon

    30

    Sabarekursiooni ja akumulaatoritehnika seos

    Üleminekul akumulaatoristiilile tekib tüüpiliselt sabarekursiivne definit-sioon.

    – Kui kõik arvutus viia argumentidesse, ei jäägi midagi rekursioonisttagasipöördumise järel teha.

    Kasutust leiab ka segastiil, kus arvutust jätkub nii akumulaatoritesse kuika rekursiivse kutse järele.

    – Lõpmatuid liste akumulaatoris arvutada ei saa.

  • 2 Programmeerimisvõtted2.2 Sabarekursioon

    31

    Sabarekursiooni tähtsus

    Sabarekursiivset definitsiooni saab kompileerimisel optimeerida.

    – Rekursiivsel kutsel võib uue rekursioonitaseme lokaalsete muutu-jate väärtused kirjutada endiste asemele.

    – Tekib tavaline tsükkel.

    2 Programmeerimisvõtted2.3 Jooksev väärtustamine

    32

    Jooksev väärtustamine

  • 2 Programmeerimisvõtted2.3 Jooksev väärtustamine

    33

    Mälukasutuse optimeerimine

    Mittesabarekursiivne definitsioon üldiselt ei võimalda arvutuse käigusvahetulemusi välja arvutada, tekib pikk väärtustamata avaldis.

    – Arvutuse teostamiseks on tarvis rekursiivse kutse tulemust, temaväljaarvutamiseks omakorda tema rekursiivse kutse tulemust jne.

    Reaalne arvutamine algab alles baasjuhuni jõudmisel.

    Sabarekursioon laseb vahetulemused jooksvalt väärtustada, sest arvu-tused toimuvad argumentidel, rekursiivse kutse tulemust pole vaja.

    2 Programmeerimisvõtted2.3 Jooksev väärtustamine

    34

    Probleem laisa väärtustamisega

    Haskellis on vaikimisi laisk väärtustamine.

    – Ka akumulaatoreid ei väärtustata!

  • 2 Programmeerimisvõtted2.3 Jooksev väärtustamine

    35

    Väärtustusjärjekorra ohje

    Haskellis on spetsiaalne agara väärtustamise operaator $!.

    Sellega saavutame akumulaatoritega tõepoolest võidu mälutarbes.

    – Väärtustatakse siiski ainult seni, kuni selgub, kas tegu on normaal-se väärtusega.

    2 Programmeerimisvõtted2.4 “Jaga ja valitse”

    36

    “Jaga ja valitse”

  • 2 Programmeerimisvõtted2.4 “Jaga ja valitse”

    37

    “Jaga ja valitse”

    “Jaga ja valitse” on programmeerimise strateegia, milles

    – mittetriviaalne ülesanne

    ∗ jagatakse kaheks või enamaks mingis mõttes ühesuurusekssama tüüpi alamülesandeks,

    ∗ lahendatakse need samal viisil ning∗ kombineeritakse tulemused kokku terve ülesande lahen-

    duseks,

    – triviaalne ülesanne lahendatakse otse.

    2 Programmeerimisvõtted2.4 “Jaga ja valitse”

    38

    “Jaga ja valitse” stiili tuntud näited

    • Kasvava funktsiooni väärtuse järgi argumendi otsimine (nn lõigu poo-litamise meetod e kahendotsing).

    • Listis suurusjärjestuses etteantud kohal oleva elemendi leidmine (nnvaliku kiirmeetod).

    • Listi järjestamine (kiirmeetod, põimemeetod).

    • Hanoi tornide ülesanne.

    • . . . .

  • 2 Programmeerimisvõtted2.4 “Jaga ja valitse”

    39

    Realiseerimise viisid

    • Otsene realisatsioon:

    – jagatakse vahetuteks alamülesanneteks, mis lahendatakse üldjuhulrekursiivselt pöördudes, erijuhul otse.

    • Realisatsioon alamülesannete listiga:

    – jagatakse kohe triviaalseteks ülesanneteks,– koostatakse nende lahendustest list,– kombineeritakse lahendused puukujuliselt kokku.

    2 Programmeerimisvõtted2.4 “Jaga ja valitse”

    40

    Dünaamiline programmeerimine

    “Jaga ja valitse” strateegia korral võib sama alamülesannet tekkida kor-duvalt.

    Dünaamiline programmeerimine on “jaga ja valitse” stiilis lahen-duse realiseerimine nii, et alamülesanded lahendatakse ühekordselt.

    – Lahendus salvestatakse ja vajadusel korduvkasutatakse.

  • 2 Programmeerimisvõtted2.4 “Jaga ja valitse”

    41

    Dünaamilise programmeerimise tuntud näited

    • Fibonacci arvude leidmine.

    • Kiire astendamine.

    • Pikima ühise osasõne leidmine.

    • . . . .

    2 Programmeerimisvõtted2.4 “Jaga ja valitse”

    42

    Nõutust rohkem kirjeldamine

    Laisk väärtustamine lubab koodis kirjeldada nõutust rohkem.

    – Kui funktsiooni väärtus vajab väljaarvutamiseks paljusid eelne-vaid, siis defineerida lõpmatu list, milles nad kõik kirjas on.

    – . . . .

    Kirjeldades nõutust rohkem, saab koodi loetavamalt struktureerida.

    – Kasutatakse dünaamilise programmeerimise abivõttena (kõigi ala-mülesannete lahenduste struktuuri, nt listi loomine).