400 likes | 762 Views
Algoritmit. Algoritmitekniikat ja algoritmien analyysi Lajittelu - Valintalajittelu (selection sort) - Lisäyslajittelu (insertion sort) - Kuplalajittelu (bubble sort) - Kuorilajittelu (shellsort) - Jakaumalajittelu (distribution counting) - Pikalajittelu (quicksort)
E N D
Algoritmit • Algoritmitekniikat ja algoritmien analyysi • Lajittelu - Valintalajittelu (selection sort) - Lisäyslajittelu (insertion sort) - Kuplalajittelu (bubble sort) - Kuorilajittelu (shellsort) - Jakaumalajittelu (distribution counting) - Pikalajittelu (quicksort) - Limityslajittelu (merge sort) - Prioriteettijonot ja kekolajittelu (heap sort) - Jakolajittelu (radix sort) • Haku - Symbolitaulut ja binääriset hakupuut - Hajakoodaus (hashing) • Merkkijonojen haku
Algoritmit • Algoritmien tulee täyttää seuraavat kriteerit: Yleisyys - algoritmin on sovelluttava määritellyn tehtävän kaikkiin tapauksiin. Deterministisyys - algoritmin jokainen toimenpide on selkeä ja yksikäsitteinen. Terminoituvuus - algoritmi päättyy äärellisen toimenpidemäärän suoritettuaan. Syöte - algoritmille annetaan ulkoa ei yhtään tai useita tietoalkioita. Tuloksellisuus - algoritmi tuottaa vähintään yhden kaikissa tapauksissa oikean tuloksen. Tehokkuus - jokaisen toimenpiteen tulee olla niin yksinkertainen, että henkilö kykenee periaatteessa suorittamaan ne kynää ja paperia käyttäen.
Algoritminen ongelmanratkaisu • Iteraatio • Rekursio
Rekursio • Rekursiivinen funktio on funktio, joka kutsuu itseään toisella syötteellä • Rekursiota käytettäessä määritellään: • Yksi tai useampi perustapaus jolle tiedetään ratkaisu • Yksi tai useampi rekursiivinen kutsu, joka jakaa alkuperäisen olgelman pienempiin, helpommin ratkaistaviin ongelmiin • Rekursiivinen ratkaisu on usein helpompi onjelmoida, koska se voidaan koodata melkein suoraan olgelman määrittelyn perusteella
Kertoma • Iteratiivinen määritelmä:n!=n(n-1)(n-2)…1 • Rekursiivinen määritelmä:n!=1, n = 1n!=n(n-1)!, n > 1
Iteratiivinen kertoma int kertoma(int n) { int tulo=1, i; for(i=1; i<n; i++) tulo*=i; return i; }
Rekursiivinen kertoma int kertoma(int n) { if(n == 1) return 1; return n * kertoma(n - 1); }
Kertoman rekursiopuu n! (n-1)! (n-2)! … 1! 0!
Kuinka rekursio toimii • Rekursiivinen koodi vaikuttaa ”mystiseltä” koska se ei sisällä silmukkaa • Rekursiiviset funktiot käyttävät ”näkymätöntä silmukkaa” • Rekursiivinen funktio kutsuu itseään kunnes ongelma on ratkaistu • Jokaisella kutsulla osa ongelmasta ratkaistaan • Ongelman pienentyessä jokaisella kutsulla lopulta jäljellä on yksi tai useampi perustapaus, joille ratkaisu tiedetään • Perustapauksen ratkaiseminen vastaa silmukasta poistumista. Perustapauksessa rekursiivista kutsua ei tehdä.
Rekursiivinen Fibonaccin lukuFi= Fi-1 + Fi-2, i>= 2, F0=F1=1 int fibonacci(int n) { if(n <= 1) return 1; return fibonacci(n - 1) + fibonacci(n - 2); }
Fibonaccin luvun rekursiopuu F5 F4 F3 F3 F2 F1 F2 F1 F1 F0 F1 F0
Algoritmien suunnittelutekniikoita • Inkrementaalinen lähestymistapa (incremental approach) • Ahne lähestymistapa (greedy approach) • Perääntyminen (backtracking) • Hajoita ja hallitse (divide and conquer) • Dynaaminen ohjelmointi (dynamic programming) • Satunnaisalgoritmit (randomized approach)
Inkrementaalinen lähestymistapa • Ongelman ratkaisua rakennetaan pala kerrallaan esim. iteraation avulla. • Yksittäinen ongelman osa otetaan käsittelyyn ja ratkaistaan se, minkä jälkeen siirrytään seuraavan osan käsittelyyn.
Ahne lähestymistapa • Jokaisessa vaiheessa tehdään siinä tilanteessa parhaalta tuntuva päätös, eikä mietitä päätöksen seurauksia tulevaisuuteen. • Ahneella algoritmilla saavutetaan tavallisesti paikallinen optimi, joskin ongelman ratkaisu voi olla myös globaali optimi.
Perääntyminen (backtracking) • Perääntyminen tapahtuu tilanteessa, jossa tietyn ratkaisupolun jatkaminen on mahdotonta tai ei kannata
Hajoita ja hallitse (divide and conquer) • Ensimmäisessä vaiheessa (1. ja 2.) ongelma jaetaan osaongelmiin ja lopuksi (3.) yhdistetään osaongelmien ratkaisut yhteen koko ongelman ratkaisuksi • Divide: Jaetaan ongelma aliongelmiksi • Conqueror: Ratkaistaan aliongelma rekursiivisesti • Yhdistä aliongelmien ratkaisut alkuperäisen ongelman ratkaisuksi
Dynaaminen ohjelmointi (dynamic programming) • Dynaaminen ohjelmointi ratkaisee jokaisen osaongelman ainoastaan kerran • Kaikkien aikaisempien päätösten tuloksettalletetaan ja käytetään tuloksia systemaattisella tavalla • Käytännössä todennäköisesti helpoin algoritmien suunnittelutekniikka
Fibonaccin luku dynaamisen ohjelmoinnin avulla int fibonacci(int n) { int fib[n], i; fib[0]=fib[1]=1; for(i=2; i<n; i++) fib[i]=fib[i-1]+fib[i-2]; return fib[n]; }
Satunnaislalgoritmit (randomized approach) • Satunnaisuuden käyttö on hyödyllistä hyvin monimutkaisten ongelmien ratkaisemisessa, kun globaalin optimin löytäminen ei ole mahdollista tai edes välttämätöntä. • Yksinkertaisten algoritmien tehostamisessa voidaan myös käyttää satunnaisuutta
Algoritmien analyysi • Saman ongelman ratkaisemiseksi on tavallisesti olemassa useita vaihtoehtoisia algoritmeja. Niiden vertailussa kiinnitetään huomiota lähinnä seuraaviin tekijöihin: • tuloksen hyvyys • tilakompleksisuus • aikakompleksisuus
Algoritmien analyysi Teoreettinen tutkimus ohjelmien suorituskyvystä ja resurssien käytöstä. Mikä on nopeutta tärkeämpää? modulaarisuus oikeellisuus ylläpidettävyys toiminnallisuus käyttäjäystävällisyys ohjelmoijan aika yksinkertaisuus laajennettavuus
RAM laskentamalli • Algoritmit ovat ainoa tärkeä, kestävä ja alkuperäinen osa tietojenkäsittelytiedettä koska niitä voidaan tutkia laitteisto ja ohjelmointikieli riippumattomalla tavalla. • Syynä on suunnittelun ja analyysin rajoittaminen RAM lasketamalliin: • Jokainen “yksinkertainen” operaatio (+, -, =, jos, kutsu) vie vain yhden askeleen. • Silmukat ja aliohjelmakutsut eivät ole yksinkertaisia operaatioita, vaan riippuvat syötteen koosta ja aliohjelman sisällöstä. • Muistiviittaukset vievät yhden askeleen. • Algoritmin ajoaika mitataan laskemalla askelten lukumäärä.
Neliömatriisien yhteenlaskun aikakompleksisuus int i, j; for(i = 0; i < n; i++) for(j = 0; j < n; j++) c[i][j] = a[i][j] + b[i][j]; n+1 vertailua, 2n+1 sijoitusta/laskutoimitusta n+1 vertailua, 2n+1 sijoitusta/laskutoimitusta 0 vertailua, 2 sijoitusta/laskutoimitusta • Suoritusaika T: T(n)=(n+1)(n+1)=n2+2n+1 vertailua ja T(n)=(2n+1)(2n+1)2=8n2+8n+2 sijoitusta/laskutoimitusta
Paras, huonoin ja keskimääräinen kompleksisuus Algoritmin huonoimman tapauksen kompleksisuus on funktio jonka määrittää maksimimäärä askelia mille tahaansa n kokoiselle syötteelle Algoritmin parhaan tapauksen kompleksisuus on funktio jonka määrittää minimimäärä askelia mille tahaansa n kokoiselle syötteelle Algoritmin parhaan tapauksen kompleksisuus on funktio jonka määrittää keskimäärinen askelmäärämille tahaansa n kokoiselle syötteelle Kompleksisuudet määrittävät askelten lukumäärän syötteen koon funktiona
Täsmällinen analyysi on vaikeaa! Algoritmin paras, huonoin ja keskimääräinen kompleksisuus määrittivät askelten lukumäärän ajan funktiona Funktioiden täsmällinen määrittäminen on vaikeaa! Tavallisesi on selkeämpää ja helpompaa käsitellä funktion ala- ja/tai ylärajoja Pelätty O notaatio peliin!
f(n)=O(g(n)) Matematiikka: f(n)=O(g(n)) tarkoittaa cg(n):n olevan yläraja f(n):lle, kun n > n0 Käytäntö: Pudota vähiten merkitsevät termit sekä vakiot esim. 3n3+90n2-5n+6046= O(n3)
f(n)=(g(n)) Matematiikka: f(n)=(g(n)) tarkoittaa cg(n):n olevan alaraja f(n):lle, kun n > n0 Käytäntö: Pudota vähiten merkitsevät termit sekä vakiot esim. 3n3+90n2-5n+6046= (n3)
f(n)=(g(n)) Matematiikka: f(n)=(g(n)) tarkoittaa c1g(n):n olevan yläraja ja c2g(n):n alaraja f(n):lle, kun n > n0 Käytäntö: Pudota vähiten merkitsevät termit sekä vakiot esim. 3n3+90n2-5n+6046= (n3)
Mistä olikaan kyse? 3n2-100n+6 = O(n2), koska 3n2 > 3n2 -100n + 6 3n2-100n+6 = O(n3), koska .00001n3 > 3n2 -100n + 6 3n2-100n+6 O(n), koska c x n< 3n2 , kun n > c f(n)=O(g(n)) tarkoittaa cg(n):n olevan yläraja f(n):lle, kun n > n0 Ajattele yhtäsuuruuden tarkoittavan joukossa funktiota.
Mistä olikaan kyse? 3n2-100n+6 = (n2), koska 2.99n2 < 3n2 -100n + 6 3n2-100n+6 (n3), koska 3n2 -100n + 6 < n3 3n2-100n+6 = (n), koska 101010n < 3n2 - 100 + 6 f(n)=(g(n)) tarkoittaa cg(n):n olevan alaraja f(n):lle, kun n > n0 Ajattele yhtäsuuruuden tarkoittavan joukossa funktiota.
Mistä olikaan kyse? 3n2-100n+6 = (n2), koska O ja 3n2-100n+6 (n3), koska ainostaan O 3n2-100n+6 (n), koska ainoastaan f(n)=(g(n)) tarkoittaa c1g(n):n olevan yläraja ja c2g(n):n alaraja f(n):lle, kun n > n0 Ajattele yhtäsuuruuden tarkoittavan joukossa funktiota.
Logaritmit: mitä ne ovat ja mistä ne tulevat? • Logaritmi on exponettifunktion käänteisfunktio:x=logby bx=y • Exponentiaaliset funktiotkasvavat huolestuttavan nopeasti • Tällöin käänteiset exponetti funktio,l. logaritmit, kasvavat virkistävän hitaast • Binäärihaku on esimerkki O(lg n) algoritmista. Jokaisen vertailunjälkeen puolet avaimista voidaan hylätä. Tällöin 20 vertailua riittää löytämään halutun nimen miljonan nimen puhelinluettelosta. • Jos ongelmaan on olemassa O(lg n) algoritmi, käytä sitä!
Logaritmien ominaisuuksia • Asymptoottisesti logaritmin kannalla ei ole merkitystä:logba= logca/ logcblog2n= log100n / (log1002), missä log1002 on vakio • Asymptoottisesti mikään n:n polynomifunktio ei vaikuta: log(n475+n2+n+96)=O(log n), koska n475+n2+n+96=O(n475) ja log n475= 475 log(n) • Exponettifunktio dominoi mitä tahaansa polynomia, jonka takia exponetiaalisen kompleksisuuden omaavia algoritmejä pyritään välttämään.
Kertaluokkamerkinnöillä laskeminen c*f(x)=O(f(x)) f(x)+c=O(f(x)) f(x)+g(x)=O(max[f(x), g(x)]) =O(max[O(f(x), O(g(x))]) logkx=O(logpx)
Analyysin tarkistaminen • Ajetaan ohjelma arvoilla N ja 2N, missä N on mahdollisimman suuri • Kun N tuplaantuu:O(N) – ajoaika tuplaantuu O(N2) – ajoaika nelinkertaistuuO(N3) – ajoaika kahdeksankertaistuuO(log N) – vakiotermi lisää riippumatta N:stäO(N log N) – hiukan huonompi kuin O(N) • Alemman asteen termit sotkevat tarkastelua
Analyysin tarkistaminen • Olkoon T(N) mitattu suoritusaika ja oletetaan, että T(N)=O(g(N)) • Lasketaan c=T(N)/g(N) • c lähestyy positiivista arvoa => g(N) on tiukka raja • c lähestyy nollaa => g(N) on liian lepsu raja • c:n arvot hajaantuvat => oletus T(N)=O(g(N)) ei päde