Složitost je úvod do problematiky Úvod praktická realizace algoritmu = omezeí zejméa: o časem o velikostí paměti složitost = vztah daého algoritmu k daým prostředkům: časová složitost každé možiě vstupích dat přiřazuje počet operací při výpočtu podle staoveého algoritmu o čas se měří počtem utě provedeých operací (doba provedeí operace ezávisí a rozsahu vstupích dat) o bývá často podceňováa o často zrychleí úlohy řešeo rychlejším HW, ebo o dílčím zrychleím programátorský trik (viz. zarážka u tříděí) přepis části kódu do assembleru apod. o vhodější zkusit ajít rychlejší algoritmus pokud existuje paměťová složitost závislost paměťových ároků a vstupích datech Přesé zjištěí složitosti staoveí časové složitosti v závislosti a: o kokrétích datech o rozsahu dat mohem častější obecě aalýzou algoritmu ( často velmi složité) u triviálích algoritmů lze detailí aalýzou programu příklad č. 1 součet prvků pole static it SoucetPrvku(it[] pole) it suma = 0; // prirazei p1 for(it i = 0; // prirazei p2 i < pole.legth; // porovai c1 i++) // soucet a prirazei s1+p3 (i = i+1) suma += pole[i]; // soucet a prirazei s2+p4 // (Suma = Suma + Pole[i]) retur suma; o časová složitost pro prvků pole (pole.legth = ): C() = p1 + p2 + ( + 1) * c1 + * (s1 + p3) + * (s2 + p4) 1
o zjedodušeí stejě složité p, c, s uiverzálí akce a: C() = a + a + ( + 1) * a + a * (a + a) + * (a + a) = a * (3 + 5 * ) o pokud akce a bude trvat jedotku času C() = 3 + 5 příklad č. 2 součet prvků čtvercové matice static it SoucetMatice(it[,] matice) it suma = 0; // prirazei p1 for(it i = 0; // prirazei p2 i < matice.getlegh(0); // porovai c1 i++) // soucet a prirazei s1+p3 for(it j = 0; // prirazei p4 j < matice.getlegh(1); // porovai c2 j++) // soucet a prirazei s2+p5 suma += matice[i][j]; // soucet a prirazei s3+p6 retur suma; o časová složitost pro čtvercovou matici řádu (Rad = ): C() = p1 + p2 + ( + 1) * c1 + * (s1 + p3) + + * ( p4 + ( + 1) * c2 + * (s2 + p5) + * (s3 + p6)) 1) po převedeí a akce: C() = a + a + ( + 1) * a + * (a + a) + + * ( a + ( + 1) * a + * (a + a) + * (a + a)) = = 3a + 5a + (3a + 5a) = = 3a + 5a + 3a +5a 2 = = 3a + 8a + 5a 2 2) pokud akce a bude trvat jedotku času C() = 3 + 8 + 52 Vypočteé délky trváí fukcí pro oba příklady pro a = 1 ms Odhad složitosti pole matice 10 53 583 20 103 2163 40 203 8323 80 403 32643 přesé vyjádřeí pro růzé ás obvykle ezajímá používá se pouze tedece růstu počtu operací pro zvětšující se pak lze výrazy pro C() zjedodušit zaedbáím: 1) aditivích kostat (u matice 3) 2) multiplikativích kostat (u matice 5 a 8) 2
3) všechy složky s ižším řádem růstu ež ejvyšším (u matice ) u pole je C() = složitost je lieárí u matice je C() = 2 složitost je kvadratická Vypočteé délky trváí fukcí po zjedodušeí Asymptotická složitost pole matice 10 10 100 20 20 400 40 40 1600 80 80 6400 asymptotické chováí fukce = chováí pro velká uvažme dvě fukce t() a g(): 1) ezáporé fukce defiovaé a oboru přirozeých čísel 2) t() výpočetí čas algoritmu (obvykle vychází z C()) 3) g() jedoduchá fukce použitá pro porováí s t() o t() a g() můžeme říci: t roste ejvýše tak rychle jako g O(g()) 0 1) tedy existuje přirozeé číslo K: t ( ) K g( ) pro součet matice výše je K = 6 2) t ( ) O( g( )), O(g()) je asymptotická složitost v tomto způsobu zápisu: 1) součet pole jede cyklus složitost O() 2) součet matice dva cykly složitost O( 2 ) Hrubý odhad složitosti pro triviálí algoritmy jedoduché každý vořeý cyklus zvyšuje mociu složitosti o jedu 3
všechy prezetovaé jedoduché třídící algoritmy mají složitost O( 2 ) zkracováí vitřích cyklů zaedbáváme pozor: složitost je odvozea od algoritmu, ikoli od dat! algoritmy tříděí pracovaly ad jedoduchým polem, ale dva vořeé cykly Třídy složitosti Kostatí O(1) o ideálí případ o pouze jedoduché matematické operace Lieárí O() o jede cyklus v algoritmu o apř. sekvečí vyhledáváí, ásobeí vektoru skalárem, Kvadratická O( 2 ) o algoritmy se dvěma cykly (vořeými!!!) o apř. základí třídící algoritmy, sčítáí matic Logaritmická O(log ) o biárí vyhledáváí o v každém kroku se rozsah dat sižuje a poloviu... 2 1, kroků půleí itervalů je h 2 4 tedy 2 h h log 2 o místo log obvykle pouze log 2 Loglieárí O( log ) o ebo také liearitmická, supralieárí o pro algoritmy rozděl a pauj o apř. algoritmus tříděí quick sort, FFT (Fast Fourier Trasform rychlá fourierova trasformace) existují i další třídy složitosti Praktický výzam složitosti doby výpočtu růzých tříd složitosti pro růzá data; podmíka: akce a trvá 1 s (CPU ~ 1ky GHz) 10 100 1 000 10 000 100 000 O(log ) 3,3 s 6,6 s 10 s 13,3 s 16,6 s O() 10 s 100 s 1 s 10 s 100 s O( log ) 33 s 660 s 10 s 133 s 1,66 ms O( 2 ) 100 s 10 s 1 ms 100 ms 10 s Efektivita algoritmů a data většia algoritmů růzý počet operací pro růzá data 4
ejlepší, ejhorší a průměrý případ Nejhorší případ Nejlepší případ ohraičuje výpočetí čas shora ohraičuje výpočetí čas zdola Průměrý případ o iformace o chováí algoritmu a typickém ebo áhodém vstupu o eí to průměr ejhoršího a ejlepšího případu!!! o velmi důležité ěkteré algoritmy mají průměrou efektivitu o moho lepší ež ejhorší případ Příklad: sekvečí vyhledáváí static it SeqSearch(it[] pole, it prvek) it idex; for(it i=0;i<pole.legth;i++) if (pole[i] == prvek) idex = i; retur idex; retur -1; o ejhorší případ o ejlepší případ o průměrý případ prvek eí aleze (pole.legth operací) hledaý prvek a prví pozici (1 operace) složitější (statistika) Dodatky k výrazům Priorita a asociativita operátorů (precedece ad associativity) Pořadí operací ve výrazech dáo o Závorkami o Prioritou operátorů o Asociativitou operátorů Priorita který operátor ovliví operady jako prví * vyšší priorita ež + x + y *z totéž jako x + (y * z) o Asociativitou operátorů směr vyhodoceí operátorů se stejou prioritou x + y + z se vyhodocuje jako (x + y) + z + asociativí zleva 5
Category Operators associativity Primary x.y f(x) a[x] x++ x-- ew typeof checked uchecked Nejvyšší priorita Uary + -! ~ ++x --x (Přetypováí)x Multiplicative * / % Additive + - Shift << >> Relatioal ad type testig < > <= >= is as Equality ==!= Logical AND Logical XOR & ^ Logical OR Coditioal AND && Coditioal OR Coditioal?: R L Assigmet = *= /= %= += -= <<= >>= &= ^= = R L Nejižší priorita většia operátorů zleva doprava (L R), kromě ozačeých R L doporučeí příklady: závorkovat!!! if (A > B && A < C) totéž co if ((A > B) && (A < C)) x = A/B*C; (asociativita) totéž co x = (A/B)*C; x = y = 10*C; totéž co x = (y = 10*C); Zkráceeé vyhodocováí logických výrazů využívá se asociativity log operátorů zleva it a = 5; it b = 0; if ((b!= 0) && (a / b > 2)) Cosole.Write("ahoj"); o problém pokud b = 0 a / b = pád programu o zkráceé vyhodoceí > 2) ikdy edojde Podmíěý (terárí) operátor?: sytaxe: bvyraz? vyraz1 : vyraz2; sématika pokud (b!= 0) == false, k vyhodoceí (a / b 6
if (bvyraz) vyraz1; else vyraz2; je to výraz!!! typické použití: vyraz1 i vyraz2 přiřazují do stejé proměé o Př.: převod čísla a absolutí hodotu it prom = 10; prom = (prom >= 0)? prom : -prom; rozdíl oproti if a příkladu: pokud je a > b pak Cos(a), jiak Cos(b) o if je příkaz double x; if (a > b) x = Math.Cos(a); else x = Math.Cos(b); o? : je výraz další příklady: double x = Math.Cos(a > b? a : b); it a,b,c; a = (b == 2)? 1 : 3; c = (a > b)? a : b; 7