Tietorakenteet ja algoritmit

Samankaltaiset tiedostot
Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit

Algoritmit ja tietorakenteet Copyright Hannu Laine. 1, kun n= 0. n*(n-1)!, kun n>0;

Tietorakenteet ja algoritmit

Rakenteiset tietotyypit Moniulotteiset taulukot

TIETORAKENTEET JA ALGORITMIT

Muita linkattuja rakenteita

Algoritmit 2. Luento 8 To Timo Männikkö

Algoritmit 2. Luento 7 Ti Timo Männikkö

Tietorakenteet ja algoritmit

Algoritmit 2. Luento 13 Ti Timo Männikkö

Algoritmit 2. Luento 14 Ke Timo Männikkö

Lyhyt kertaus osoittimista

#include <stdio.h> // io-toiminnot. //#define KM_MAILISSA int main( ){

Tietorakenteet ja algoritmit

Tietueet. Tietueiden määrittely

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

Algoritmit 1. Luento 4 Ke Timo Männikkö

Algoritmit 1. Luento 8 Ke Timo Männikkö

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Algoritmit 2. Luento 4 To Timo Männikkö

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.

Algoritmit 1. Demot Timo Männikkö

Tietorakenteet ja algoritmit. Kertaus. Ari Korhonen

811120P Diskreetit rakenteet

TAMPEREEN TEKNILLINEN YLIOPISTO

Tietorakenteet ja algoritmit

A TIETORAKENTEET JA ALGORITMIT

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Demot Timo Männikkö

Algoritmit 1. Luento 6 Ke Timo Männikkö

Algoritmit ja tietorakenteet / HL Copyright Hannu Laine

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö. Muistin käyttö C-ohjelmassa

58131 Tietorakenteet ja algoritmit (syksy 2015)

Algoritmit 2. Luento 2 To Timo Männikkö

3. Binääripuu, Java-toteutus

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

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

Algoritmit 2. Luento 4 Ke Timo Männikkö

Merkkijono määritellään kuten muutkin taulukot, mutta tilaa on varattava yksi ylimääräinen paikka lopetusmerkille:

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

// // whiledemov1.c // #include <stdio.h> int main(void){ int luku1 = -1; int luku2 = -1;

TAMPEREEN TEKNILLINEN YLIOPISTO

Moduli 4: Moniulotteiset taulukot & Bittioperaatiot

tietueet eri tyyppisiä tietoja saman muuttujan arvoiksi

Algoritmit 1. Luento 3 Ti Timo Männikkö

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

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Algoritmit ja tietorakenteet / HL 1 Copyright Hannu Laine. Lista. Yleistä

Osoittimet ja taulukot

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

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

Jakso 4 Aliohjelmien toteutus

Algoritmit 1. Luento 12 Ti Timo Männikkö

Algoritmit 2. Luento 2 Ke Timo Männikkö

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Algoritmit 1. Luento 13 Ti Timo Männikkö

Loppukurssin järjestelyt

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

A TIETORAKENTEET JA ALGORITMIT

Tehtävän V.1 ratkaisuehdotus Tietorakenteet, syksy 2003

C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys

Algoritmit 1. Luento 10 Ke Timo Männikkö

Dynaamiset tietorakenteet

Moduli 2: Osoittimet ja taulukot. Joel Huttunen

Luennon sisältö. Taulukot (arrays) (Müldnerin kirjan luku 10) Yksiulotteiset taulukot. Mikä taulukko on? Taulukko-osoitin. tavallinen osoitin

C-ohjelmointi, syksy 2006

C-ohjelmointi, syksy Yksiulotteiset taulukot Moniulotteiset taulukot Dynaamiset taulukot. Binääritiedostot. Luento

Tietorakenteet ja algoritmit - syksy

Algoritmit 1. Luento 12 Ke Timo Männikkö

811312A Tietorakenteet ja algoritmit II Perustietorakenteet

TIE Tietorakenteet ja algoritmit 25

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

ITKP102 Ohjelmointi 1 (6 op)

Loppukurssin järjestelyt C:n edistyneet piirteet

Tietorakenteet, laskuharjoitus 3, ratkaisuja

ITKP102 Ohjelmointi 1 (6 op)

Luento 4 Aliohjelmien toteutus

Ohjausrakenteet. Valinta:

Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.

Hakupuut. tässä luvussa tarkastelemme puita tiedon tallennusrakenteina

2) Aliohjelma, jonka toiminta perustuu sivuvaikutuksiin: aliohjelma muuttaa parametrejaan tai globaaleja muuttujia, tulostaa jotakin jne.

1. Mitä seuraava ohjelma tulostaa? Vastaukseksi riittää yksi rivi joka esittää tulosteen. (6 p)

1. Mitä tehdään ensiksi?

Ohjelmoinnin perusteet Y Python

Osoittimet ja taulukot

A ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä.

Ohjelmoinnin peruskurssi Y1

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Kysymyksiä koko kurssista?

811312A Tietorakenteet ja algoritmit Kertausta jälkiosasta

Tietorakenteet ja algoritmit

Jakso 4 Aliohjelmien toteutus

Algoritmit 2. Luento 9 Ti Timo Männikkö

Algoritmit 1. Luento 9 Ti Timo Männikkö

Transkriptio:

Tietorakenteet ja algoritmit Rekursio Rekursion käyttötapauksia Rekursio määritelmissä Rekursio ongelmanratkaisussa ja ohjelmointitekniikkana Esimerkkejä taulukolla Esimerkkejä linkatulla listalla Hanoin tornit 1

Rekursio Rekursio tarkoittaa palauttamista itseensä. Rekursiota käytetään Määritelmissä Ongelmanratkaisussa Ohjelmointitekniikkana (toisto) Funktio, joka kutsuu itseään on rekursiivinen 2

Rekursio määritelmissä Asioita voidaan määritellä rekursiivisesti. Esimerkiksi lista, binääripuu ja kertoma (n!) voidaan määritellä rekursiivisesti. Esimerkkinä kertoman rekursiivinen määrittely. Matemaattinen käsite kertoma määritellään näin n! = 1, kun n= 0 (rekursion kanta) n*(n-1)!, kun n>0 (rekursiivinen osa) Seuraavalla sivulla sovelletaan kertoman määritelmää käytäntöön. 3

Kertoman määritelmän käyttö Käytetään edellisen sivun kertoman määritelmää ja selvitetään, mitä on 5! 5! = 5*(5-1)! = 5*4! Pienennetään probleemaa = 5*(4*(4-1)!) = 5*(4*3!) = 5*(4*(3*(3-1)!)) = 5*(4*(3*2!)) = 5*(4*(3*(2*(2-1)!))) = 5*(4*(3*(2*1!))) = 5*(4*(3*(2*(1*(1-1)!)))) = 5*(4*(3*(2*(1*0!)))) = 5*(4*(3*(2*(1*1)))) = 5*(4*(3*(2*1))) = 5*(4*(3*2)) = 5*(4*6) = 5*24 = 120 Palataan takaperin ratkaisuun Kanta eli yksinkertainen tapaus löytynyt 4

Rekursio ohjelmointitekniikkana Rekursiivinen funktio kutsuu itse itseään. Esimerkki. Kertoman laskenta // Rekursiivinen funktio, joka laskee kertoman int factorial(int number) { if (number == 0) return 1; if (number > 0) return number*factorial(number-1); void main (void) { printf("\nthe factorial of 4 is %d", factorial(4)); Iteratiivinen olisi tässä parempi. Esimerkki annettu periaatteen oppimisen tarkoituksessa. 5

Rekursio ongelmanratkaisussa Periaate 1. Etsitään yksinkertainen tapaus (ns.rekursion kanta) 2. Palautetaan ongelma itseensä, mutta kooltaan pienennettynä 3. Toistetaan kohtaa 2, kunnes päästään yksinkertaiseen tapauksen (kantaan) 4. Paluu "takaperin" lopulliseen ratkaisuun Esimerkkejä Seuraavaksi käsitellään erilaisia esimerkkejä, kuinka rekursiota käytetään ongelmanratkaisussa ja ohjelmoitaessa ongelman ratkaisevaa funktiota. Esimerkit ovat 1. Taulukon alkioiden tulostus käänteisessä järjestyksessä 2. Taulukon alkioiden järjestyksen kääntö 3. Linkatun listan alkioiden tulostus käänteisessä järjestyksessä 4. Linkatun listan loppuun lisääminen 5. Hanoin tornit 6

Taulukon alkioiden tulostus käänteisessä järjestyksessä 1 Ajattelutapa Oletetaan, että taulukossa on n alkiota. Yksinkertainen tapaus: Taulukko on tyhjä eli siinä on 0 alkiota. Ratkaisu on yksinkertainen, koska ei tarvitse tulostaa tai tehdä mitään. Probleeman pienentäminen: Jos taulukko ei ole tyhjä eli n > 0. Tulostetaan käänteisessä järjestyksessä yhtä alkiota pienempi taulukko, joka seuraa ensimmäistä alkiota. Tämän jälkeen tulostetaan alkuperäisen taulukon ensimmäinen alkio. Sama alkuperäinen ongelma mutta pienempänä Asia ohjelmana seuraavalla sivulla. 7

Taulukon alkioiden tulostus käänteisessä järjestyksessä 2 void print_array(const int* arr, int n); void print_in_reverse_order(const int* arr, int n); void main(void) { int array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; print_array(array, 10); print_in_reverse_order(array, 10); void print_in_reverse_order(const int* arr, int n) { if ( n == 0) { //printf("\n"); Tulee alkuun return; else { print_in_reverse_order(arr + 1, n - 1); printf("%d ", *arr); Tarkastellaan, miten prosessori suorittaa tämän funktion. void print_array(const int* arr, int n) { const int *p; for (p = arr; p < arr + n; p++) printf("%d ", *p); printf("\n"); 8

Taulukon alkioiden järjestyksen kääntö 1 Ajattelutapa Oletetaan, että taulukossa on n alkiota. Yksinkertainen tapaus: Taulukko on tyhjä eli siinä on 0 alkiota. Ratkaisu on yksinkertainen, koska ei tarvitse tehdä mitään. Probleeman pienentäminen: Jos taulukko ei ole tyhjä eli n > 0. Käännetään alkioiden järjestys yhtä alkiota pienemmässä taulukossa, joka seuraa ensimmäistä alkiota. Sitten laitetaan talteen alkuperäisen taulukon ensimmäinen alkio. Seuraavaksi siirretään käännetty pienempi taulukko askel taaksepäin alkuperäisessä taulukossa. Lopuksi viedään talteen laitettu alkuperäisen taulukon ensimmäinen alkio taulukon viimeiseksi. Asia ohjelmana seuraavalla sivulla. Sama alkuperäinen ongelma mutta pienempänä 9

Taulukon alkioiden järjestyksen kääntö 2 void invert_array(int *array, int n) { int aux; if (n == 0) return; Tarkastellaan, miten else { prosessori suorittaa tämän aux = *array; funktion. invert_array(array+1, n-1); move_one_step_backwards(array, n-1); *(array+n-1) = aux; void move_one_step_backwards(int *array, int n) { int i; for (i = 0; i < n; i++) array[i] = array[i+1]; 10

Rekursiivisia funktioita linkatulle listalle Linkatun listan alkioiden tulostus käänteisessä järjestyksessä Tässä rekursio sopii, koska osoittimet on laitettava joka tapauksessa jonnekin talteen. Linkattu merkkilista on määritelty muodossa typedef Tpointer Tlist; Seuraava funktio tulostaa listan käännetyssä järjestyksessä. void print_list_in_reverse (Tlist list) { if (list == NULL) printf("\nlist in reverse order :"); else { print_list_in_reverse (list->next); printf("%c ", list->item); kanta (triviaali tapaus) probleeman pienentäminen 11

Kuinka rekursiivinen funktio toimii Käydään läpi edellisen sivun funktion toiminta ja oletetaan että linkattu lista on muotoa: 1000 1000 a 2000 3000 c 2000 b 3000 NULL 3000 2000 1000 Luvut 1000, 2000 ja 3000 kuvaavat muistiosoitteita. Pinon sisältö kun rekursion kanta saavutetaan. 12

Muita rekursiivisia funktioita linkatulle listalle Linkatun listan loppuun lisääminen insert_to_list_end Rekursiivinen ratkaisu voi olla myös tehottomampi kuin iteratiivinen (pinon haaskaus ). Linkattu merkkilista on määritelty muodossa typedef Tpointer Tlist; Rekursiivinen funktio, jolla lisätään alkio listan loppuun. void insert_to_list_end(tlist *list, Titem data) { if (*list == NULL ) { *list = (Tpointer) malloc(sizeof(tnode)); (*list) -> item = data; (*list) -> next = NULL; else insert_to_list_end_1(&((*list)->next), data); 13

Rekursion oikea ja väärä käyttö Funktio print_list_in_reverse on esimerkki oikeasta tavasta käyttää rekursiota, koska siinä pinoon tallennettavaa historiaa todella tarvitaan. Rekursion oikeaa käyttöä ei ole toteuttaa sillä vain toisto, koska funktion parametrit ja mahdolliset paikalliset muuttujat viedään joka kutsukerralla uudelleen pinoon ja näin haaskataan pinomuistia. 14

Hanoin tornit Klassinen esimerkki rekursiosta probleemanratkaisussa: Hanoin tornit. Probleeman kuvaus: Kultalevyt sauvassa a on siirrettävä sauvaan c sauvaa b hyväksikäyttäen siten, että 1. Missään vaiheessa isompi levy ei ole pienemmän päällä missään sauvassa. 2. Vain yksi levy kerrallaan saa olla pois sauvoista. Käydään läpi ongelman rekursiivisen ratkaisun ajatteluperiaate alla olevan kuvan avulla. a b c Ratkaisun periaate: 1. siirretään n-1 levyä sääntöjä noudattaen tangosta a tankoon b käyttäen hyväksi tankoa c 2. siirretään tankoon a jäänyt suurin levy tankoon c 3. siirrettään n-1 levyä sääntöjä noudattaen tangosta b tankoon c käyttäen hyväksi tankoa a 15

Hanoin tornien ongelman ratkaiseva ohjelma #include <stdio.h> void siirra (int n, char tanko1, char tanko2, char tanko3) { // seuraavilla riveillä voitaisiin testata, montako kertaa funktiossa on käyty // static int kerta = 0; // printf( Kerta := %d n = %d\n", kerta++, n); if (n==1) printf("\n Siirrä tangosta %c tankoon %c ", tanko1, tanko3); else { siirra(n - 1, tanko1, tanko3, tanko2); printf("\n Siirrä tangosta %c tankoon %c ", tanko1, tanko3); siirra(n - 1, tanko2, tanko1, tanko3); void main (void) { int n; printf("\n Montako levyä :"); scanf("%d", &n); printf("\n Käytä seuraavia siirtoja "); siirra(n, 'a', 'b', 'c'); 16

Hanoin tornien kutsupuu. Hanoin tornien kutsupuu 17

Rekursion, pinon ja puiden yhteydet. Rekursio, pino ja puut ovat kiinteästi yhteen kietoutuneita. Rekursion toteuttamiseen käytetään pinoa. Rekursiivisen funktion, jossa funktio kutsuu itseään kaksi kertaa, kutsuista muodostuu ns. kutsupuu. Tietorakenne puu määritellään rekursiivisesti. Useimmat puita käsittelevät operaatiofunktiot toteutetaan rekursiivisesti. Puihin tutustutaan paremmin osassa 13 18

Lisää rekursiolle sopivia probleemoita Sivulla 6 mainittiin eräitä yksinkertaisia probleemoita, jotka voidaan ratkaista rekursiivisesti, vaikka niiden iteratiivinen ratkaisukin on melko suoraviivainen. Seuraavassa esimerkkejä, joissa rekursio yksinkertaistaa huomattavasti ratkaisua: Infix-lausekkeen muuntaminen postfix-muotoon Ruudukossa olevan mielivaltaisen yhtenäisen tahran koon laskeminen (labratehtävänä) Puumaisen hakemistorakenteen läpikäynti Reitin etsintä verkosta Monet binäärisen etsintäpuun operaatiofunktiot Jne Muista myös mitä sivulla 14 on sanottu 19