Tento přehled vznikl pro účely výuky programování pro jednu nadšeneckou skupinku. Můj záměr se rozšířil na vytvoření přehledné učebnice, ze které se dokáže naučit programovat inteligentní samouk. Programování se snažím vysvětlovat tak, aby student chápal, co se během tvorby kódu i během výkonu programu odehrává v operačním systému a uvnitř počítače, proto lekcím programování předcházelo několik lekcí obecné informatiky:
vim
a gcc
(v Debianu ze stejnojmenných balíčků).
vim
u píšete příkazy, např. ukol.c
, je zdrojový kód (zdroják) v jazyce C.gcc ukol.c
.gcc
, kterému jste zdroják předhodili, je překladač jazyka C.a.out
, který spustíte ./a.out
gcc
na řádek. Doporučuji použít gcc -g -std=c99 -Wall -Wextra
, pak překladač upozorňuje na všechny problémy, kterých si umí všimnout. Abyste tuhle nudli nemuseli vždycky znova opisovat, můžete si vytvořit třeba alias gccg
, který vám to nahradí, přidáním řádku alias gccg='gcc -g -std=c99 -Wall -Wextra'
do souboru ~/.bashrc
a restartováním konzole.#include <stdio.h>
int main(){
}
#include <stdio.h> int main(){ printf("Ahoj svete\n"); }
Opište výše uvedený program, přeložte ho za použití chytrých přepínačů a pak ho spusťte.
int
– celé číslofloat
– desetinné číslochar
– znak (ale dá se používat jako číslo s malým rozsahem)bool
– pouze hodnoty true
a false
(tzv. boolean), a je potřeba na začátku zdrojáku includovat soubor stdbool.h
int promenna;
Pozor, zatím proměnná nemá přiřazenou žádnou hodnotu (neníinicializovaná) a tak by se něměla používat ve výrazech.promenna = 3 * 8;
Aritmetika má různé svoje záludnosti, obzvláště pokud se kombinují proměnné typu int
a float
.char retezec[16];
Nyní proměnná retezec
je string, do kterého se vejde 15tiznakový text, protože za textem ještě musí být znak '\0'
. Jiná možnost je deklarovat char retezec[] = "Lokomotiva";
, který vytvoří string s 11 znaky (opět je tam potřeba jeden navíc pro ukončovací znak).string.h
strcpy
, např. strcpy(retezec, "Kobliha");
nebo strcpy(retezec, jinyretezec);
(v druhém případě je však nutné, aby jinyretezec
byl správně deklarovaný a inicializovaný řetězec).strcat
, např. strcat(retezec,jinyretezec);
připojí za obsah stringu retezec
obsah stringu jinyretezec
. U obou funkcí pro práci s řetězci si dávejte pozor, aby se vám do nich ten text vešel!s[1]
je druhý znak řetězce.Napište program, který nadeklaruje celé číslo s identifikátorem prvocislo
s hodnotou 11
, reálné číslo s identifikátorem ludolfovo
s hodnotou 3.1415926
, znak pismenko
s hodnotou q
, boolean pravda
s hodnotou true
a textový řetězec pisnicka
s hodnotou Jsme silni jak silny je lano co k nebi nas po-ooou-ta
. Takový program při spuštění nedává žádný výstup, za úspěch považujte, když se přeloží bez chyb.
stdio.h
printf
. Ten má jako parametry formátovací řetězec a proměnné či výrazy, které chcete vypsat.\
, které znamenají výpis něčeho, co se jinak píše blbě (např. \n
znamená odřádkování), a jiné speciální znaky uvozené %, které odpovídají proměnným/výrazům v dalších parametrech, ve stejném pořadí.%d
– výraz typu int
%f
– výraz typu float
%c
– výraz typu char
%s
– textový řetězecint a; int b; a = 45; b = 23; char[] s = "Kobliha"; printf("Ahoj svete,\nmam rad cislo %d, chutna mi %s a nemam rad cislo %d.\n", b, s, a);Tento program vypíše:
Ahoj svete, mam rad cislo 23, chutna mi Kobliha a nemam rad cislo 45.
scanf
, také má formátovací řetězec, další parametry jsou však ukazatele na proměnné, to pro vás znamená, že kromě případu řetězců před proměnné musíte napsat &
.int a; int b; char s[32]; scanf("%d%d%s", &a, &b, s); printf("Ahoj svete,\nmam rad cislo %d, chutna mi %s a nemam rad cislo %d.\n", b, s, a);Tento program při vstupu (po napsání tohoto na klávesnici)
45 23 Koblihavypíše
Ahoj svete, mam rad cislo 23, chutna mi Kobliha a nemam rad cislo 45.
gets()
načte řádek vstupu (do enteru), puts()
zase jednoduše vypisuje řetězec. Příklad vše osvětlí:
char s[32]; gets(s); // nacte radek, ktery uzivatel zada... puts(s); // ...a pak ho vypise.
Minulý program s deklaracemi proměnných doplňte tak, aby takto vypsal identifikátory a hodnoty proměnných: prvocislo je 11, ludolfovo je 3.14159, pismenko je q a pisnicka je Jsme silni jak silny je lano co k nebi nas po-ooou-ta
. Potom program doplňte tak, že hodnoty bude zadávat uživatel z klávesnice a tyto se pak vypíšou. Na boolean se vykašlete, ten se jednoduše vypisovat nedá.
Počítání věku na Biblickou stezku: Zobrazit
Jméno1 Příjmení1 RokNarození1 Jméno2 Příjmení2 RokNarození2 Jméno3 Příjmení3 RokNarození3Výstup programu v roce 2012 (to, co se potom vypíše na obrazovku):
Jméno1, Jméno2 a Jméno3 maji dohromady vek SoučetJejichVěků.Příklad:
Daniel Friedrich 1999 Michaela Mazna 1999 Tadeas Friedrich 1994Výstup:
Daniel, Michaela a Tadeas maji dohromady vek 44.
if
if (podmínka){ příkaz1 ... }else{ příkaz2 ... }
a
, může být podmínka třeba a < 3
, což přirozeně znamená "a je menší, než 3". Jiné porovnávací značky jsou >
, <=
(menší či rovno), >=
, ==
(rovná se), !=
(nerovná se).int vek; scanf("%d", &vek); if (vek > 20){ printf("Jsi starej\n"); }else{ printf("Jsi malej\n"); }
if (vek > 20) printf("Jsi starej\n"); else printf("Jsi malej\n");funguje naprosto stejně,
if (vek > 20) printf("Jsi starej\n"); else printf("Jsi malej\n");taky, jde skutečně jen o vkus a přehlednost.
else
a jeho blok, pokud to nepotřebujete.
if (vek > 20) printf("Jsi starej\n");
&&
(logické and), pokud alespoň jedna, použije se ||
(logické or). Pokud naopak podmínka nesmí platit, použijte před ní !
(logickou negaci). Každá podmínka musí mít vlastní závorku – je to dobré i pro přehlednost.
int vek; int pocetvlasu; scanf("%d%d", &vek, &pocetvlasu); if ((!(vek <= 20)) && (pocetvlasu == 0)){ printf("Jsi starej plesoun\n"); }else{ printf("Starej plesoun zjevne nejsi\n"); }Logickými operátory a uzávorkováním můžete združit mnoho podmínek k sobě všelikými způsoby.
else
dáte další if
:
int vek; int pocetvlasu; scanf("%d%d", &vek, &pocetvlasu); if ((vek > 20) && (pocetvlasu == 0)){ printf("Jsi starej plesoun\n"); }else if ((vek > 20) || (pocetvlasu == 0)){ printf("Jsi bud starej vlasac, nebo malej plesoun\n"); }else{ printf("Jsi mladik s bujnou kstici\n"); }
strlen
a strcmp
. Například podmínka (strlen(s) == 5)
zjistí, zda je řetězec s
dlouhý přesně 5, (!strcmp(s, "Blaf"))
zjistí, zda je v s
napsáno "Blaf" (na !
u strcmp
nezapomínejte).Upravte program pro Biblickou stezku, aby oznámil, zda hlídka smí soupeřit.
Napište program, který zjistí, zda se dá ze tří zadaných čísel sestrojit trojúhelník s těmito délkami stran a pokud ano, tak zda je pravoúhlý.
//
. Takto si můžete komentovat všechna zajímavá místa v programu. Komentář by měl popisovat, k čemu příkaz/blok je, ne tupě popisovat, co se děje. Například pro
if (vek > 20){je komentář
// je promenna vek vic nez 20?zbytečný, zato
// je uzivatel stary?může pomoci. U složitého příkazu dobrý komentář ušetří mnoho času.
int a; int b;ale ne
int a; printf("%d", b);Také můžete za skupinu logicky souvisejících příkazů dát jedno- či víceřádkovou mezeru.
int main(){ int vek; int pocetvlasu; scanf("%d%d", &vek, &pocetvlasu); if (vek > 20){ printf("Jsi starej"); if (pocetvlasu == 0){ printf(" plesoun\n"); }else{ printf(" vlasac\n"); } }else{ printf("Starej zjevne nejsi\n"); } }O stylech indentace se více můžete dočíst tady. Můj oblíbený je shodou okolností ten, který se používá v jádře Linuxu. =:)
stdlib
, takže bude potřeba includovat soubor stdlib.h
.rand()
vám potom dá náhodné integerové hodnoty. Problém je, že při každém spuštění programu stejnou posloupnost. Tomu se dá předejít tím, že náhodnému generátoru nastavíme tzv. semínko, tj. nějaké číslo, které určí, jak bude posloupnost vypadat. Jenže kde semínko vzít, když má být při každém spuštění programu jiné? Náhodně vygenerovat ho nemůžeme =:)time(NULL)
, definovaná v time.h
, vám řekne, kolik sekund uplynulo od 1. ledna 1970.srand(semínko)
.#include <stdio.h> #include <stdlib.h> #include <time.h> int main(){ srand(time(NULL)); int a = rand(); printf("Nahodne cislo! --> %d\n", a); }
int a = rand() % 100;
.Napište program, který si vymyslí první číslo, operand (+
,-
,*
,/
) a druhé číslo a vypíše příklad na obrazovku. Uživatel napíše výsledek. Program mu odpoví spravne
nebo spatne
a ukončí se. Zkuste pak taky zjistit a vypsat, kolik sekund uživatel příklad počítal. Čísla generujte v rozsahu od 0 do 20. Dejte ale pozor, aby se nedělilo nulou.
while
while
má následující syntax:
while (podmínka){ příkaz ... }
int a = 0; while (a < 100){ printf("%d\n", a); a++; } printf("Cyklus skoncil, a uz je %d\n", a);
do
:
do{ příkaz ... } while(podmínka);
char s[16]; printf("Budeme si povidat, dokud nenapises prazdny radek.\n"); do{ gets(s); printf("%s, rikas? To je tuze zajimava myslenka.\n", s); } while(strlen(s) != 0); printf("Tak cau.\n");
Napište program, který si vymyslí číslo mezi 0 a 99 a uživatel hádá. Program mu vždy odpoví vic
nebo min
nebo, když se uživatel trefí, na kolikátý pokus to uhodl a ukončí se.
Napište program, který vypíše 1000 hvězdiček.
Přepište ho na program, který vypíše čísla od 0 do 999.
Přepište ho na program, který vypíše druhé mocniny čísel od 0 do 999.
for
int i=0; // inicializace řídící proměnné while (i<1000){ // podmínka na ř. p. k ukončení cyklu ... // příkaz(y) v cyklu i++; // změna řídící proměnné }
while
, ale existuje ještě jednodušší prostředek: cyklus for
.while
cyklus:
for (int i=0; i<1000; i++){ ... }
for (inicializace; podmínka; změna){ ... }
for
je tzv. syntaktický cukr, tedy konstrukce, bez které byste se obešli, ale může vám usnadnit práci.(int i=0; i<10; i++)
než (int i=1; i<=10; i++)
.while
a for
Zadá se číslo a program vypíše tolik hvězdiček.
Zadá se číslo a program vypíše prvních jeho 10 násobků.
Zadá se číslo a program vypíše všechny jeho násobky, které jsou menší, než 100.
Zadávají se čísla, dokud se nezadá 0. Pak program vypíše jejich součet.
Zadávají se čísla, dokud se nezadá 0. Pak program vypíše, které bylo největší.
Zadá se textový řetězec, program ho vypíše pozpátku.
Zadá se číslo a program vypíše správně velký trojúhelník z hvězdiček. Příklad:
5 ***** **** *** ** *
Zadá se číslo a program vypíše kruh z písmen (třeba X) o daném poloměru. Příklad:
4 X XXXXX XXXXXXX XXXXXXX XXXXXXXXX XXXXXXX XXXXXXX XXXXX X
Zadá se číslo a program ho vypíše ve dvojkové soustavě. (Pozpátku to je jednodušší.)
Zadá se číslo ve dvojkové soustavě a program ho vypíše v desítkové. (To vstupní si raději načtěte jako string.)
Zadá se číslo a program vypíše všechna prvočísla mezi 0 a tímto číslem.
int a[16];
vytvoří pole a
16ti integerů.p[3]
. Indexuje se od 0, to znamená, že prvky pole mají indexy od 0 do velikost-1. V hranaté závorce samozřejmě nemusí být přímo číslo, klidně tam může být zase nějaká integerová proměnná nebo výraz.'\0'
.Zadá se číslo, program vytvoří tak velké pole, naplní ho náhodnými čísly mezi 0 a 100 a pak hodnoty prvků pole vypíše.
Předchozí program se rozšíří tak, že uživatel zadá další číslo a program mu řekne, zda a na jakém indexu je to číslo v poli.
Zadá se číslo a program vytvoří tak velké pole, naplní ho nějakou rostoucí posloupností čísel (větší indexy mají větší hodnoty) a pak hodnoty prvků pole vypíše.
Předchozí program se zase rozšíří tak, že uživatel zadá další číslo a program mu řekne, zda a na jakém indexu je to číslo v poli, a nějak chytře, aby nezkoumal zbytečně moc prvků.
Vezme se program, co vytváří pole naplněné náhodnými čísly a doplní se tak, že je seřadí podle velikosti. Např.:
6 V poli jsou cisla: 52 12 96 3 12 77 Setridene pole: 3 12 12 52 77 96
Měli jsme dva programy na vyhledání prvku v poli. Jeden prostě projde celé pole, druhý funguje jen na rostoucích polích, zato se zdá, že rychleji. Je to skutečně tak?
Spočítejte složitost hledání prvku v neuspořádaném poli. (Fáze vytváření pole není součástí algoritmu.)
Spočítejte složitost hledání prvku v uspořádaném poli. (Fáze vytváření pole není součástí algoritmu.)
Spočítejte složitost třídění pole. Najděte rychlejší algoritmus. =:)
Dejme tomu, že dostanete za úkol seřadit 100 jmen, zadávaných z klávesnice, podle abecedy. Při testování takového programu toho napíšete víc při zadávání vstupu, než při psaní kódu.
./a.out < vstup.txt > vystup.txt
vstup.txt
je v adresáři, ze kterého program spouštíte a jsou v něm data, kterým rozumí, tak pokud v témže adresáři máte právo vytvořit soubor, bude výstup v souboru vystup.txt
. Pokud už výstupní soubor existuje a vy máte právo do něj zapisovat, jeho obsah se přepíše.>>
místo >
, v takovém případě se soubor nepřepíše, ale nová data se připojí na konec.|
. Takže pokud program a.out
řadí jména podle abecedy a b.out
odstraňuje diakritiku, tak příkaz ./b.out < vstup.txt | ./a.out > vystup.txt
vezme jména ze vstupního souboru, odstraní z nich diakritiku, seřadí je podle abecedy a nasype do výstupního souboru.sort -n -t: -k3 < /etc/passwd | tail -n 10 | cut -d: -f1
vypíše login 10ti uživatelů s nejvyššími User ID.V souboru prace.txt
plném pracujícího lidu je na každém řádku
Jméno Příjmení Datum ČasPříchodu ČasOdchodu HodinováMzdanapř.
Ferdinand Kobliha 29.2. 11:31 23:47 65, poslední řádek se vyznačuje tím, že je na něm jedna tečka a jinak nic. Vaším úkolem je vypsat jména a celkové mzdy, které máte vyplatit, každé jméno jen jednou. Jméno ani příjmení není delší, než 31 znaků. Různých lidí není víc, než 100. Výsledky vypište do
mzdy.txt
. Zde najdete vzorový vstup.
{}
.if
u nebo tělo while
cyklu tedy jakoby obsahují jen jeden příkaz, ale pomocí bloku jich tam vpravíte libovolně mnoho.{ int a; { a = 5; } // zde je a == 5 } // zde a nikdo nezna a = 3; // zpusobi chybu
{ int a = 3; { // a == 3 int a = 5; // a == 5 } // a == 3 } // a neexistue
Pokračování časem. Určitě by měly přibýt ještě následující kapitoly:
Jak by vypadal program, který by třídil dvě pole? Pět polí? Dvacet polí?
#include <stdio.h> int mocnina(int zaklad, int exponent){ for (int i = 0; i < exponent; i++){ vysledek *= zaklad; } return vysledek; } int main(){ int a = 3; int b = 4; int c = 5; if (mocnina(a, 2) + mocnina(b, 2) == mocnina(c, 2)) printf("Trojuhelnik je pravouhly\n"); }
main
je funkce se vším všudy.mocnina
neuvidíte proměnné main
u a obráceně.void
. Pak naopak nic vracet nesmí. Můžete ji ukončit return
em bez parametrů.main
), překladač vás bude přinejmenším varovat, v některých případech překlad selže. gcc
totiž při překladu čte kód odshora dolů a nelíbí se mu, když se volá funkce, o které dosud neslyšelo.Napište funkci, která vypíše objem válce, parametry budou poloměr podstavy a výška. Můžou to být i necelá čísla.
Teď ať ta funkce objem vrátí a vypište ho až v pokračování hlavní funkce.
float krat_pi(float b){ // 3. zastávka float pi = 3.1; //musi stacit, ne // 4. zastávka b = b * pi; // 5. zastávka return b; } int main(){ // 1. zastávka float a = 2; float b; // 2. zastávka b = krat_pi(a); // 6. zastávka }Podíváme se, jak to vypadá v paměti (na zásobníku) v jednotlivých krocích.
[]Na počátku byla paměť pustá a prázdná, jen nad zásobníkem se vznášela alokace.
a b [2 |? ]Pak se alokovaly první proměnné.
a
byla přiřazena hodnota 2, b
má zatím nedefinovanou hodnotu.
a b |b [2 |? |2 ]Pak jsme funkci předali hodnotu proměnné
a
a vznikla nám na zásobníku další proměnná b
. Je to úplně jiné b
než posledně a k lokálním proměnným main
u se teď nedostaneme.
a b |b pi [2 |? |2 |3.1]Alokace proměnné
pi
, nic překvapivého.
a b |b pi [2 |? |6.2|3.1]Změna hodnoty proměnné
b
, taktéž nic překvapivého.
a b [2 |6.2]V okamžiku
return
u se vracená hodnota předá zpět volající funkci, v tomto případě do proměnné b
a dealokují se lokální proměnné pi
a b
. Opuštěním main
u pak zanikají i zdejší lokální proměnné a program končí.
int* a
.&
. Říká se tomu referencování proměnné.*
. Říká se tomu – kupodivu – dereferencování ukazatele.int a = 5; int* p = &a; int b = *p; printf("%d", b); // 5nahraje do ukazatele
p
adresu proměnné a
, pak hodnotu odkazovanou ukazatelem p
nahraje do proměnné b
a vypíše.#include <stdio.h> void plusJedna(int* p_a){ int a = *p_a; a++; *p_a = a; } int main(){ int a = 3; plusJedna(&a); printf("%d", a); }Proměnnou nepředáme funkci přímo, ale referencujeme ji a předáme ukazatel. Ten ve funkci dereferencujeme a děláme si s proměnnou, co chceme. Nakonec výslednou hodnotu uložíme na místo v paměti odkazované ukazatelem.
*p_a = *p_a + 1;
.printf
vypisované proměnné předávány normálně, zatímco scanf
, který hodnoty mění, dostává ukazatele na proměnné.char *
.
#include <stdio.h> #include <string.h> void pridejKoblihu(char* s){ strcat(s, " a kobliha"); } int main(){ char s[20]; strcpy(s, "Mrkev"); pridejKoblihu(s); printf("%s", s); // Mrkev a kobliha }
int *
a taky se dají uvnitř funkce bez problému modifikovat.
#include <stdio.h> void vynulujPosledni(int* pole, int velikost){ pole[velikost-1] = 0; } int main(){ int a[3]; a[0] = 5; a[1] = 7; a[2] = 9; vynulujPosledni(a, 3); printf("%d %d %d", a[0], a[1], a[2]); // 5 7 0 }
Napište funkci, která dostane dvě čísla a prohodí jejich hodnoty.
Napište funkci, která dostane pole a jeho velikost a setřídí ho.
#include <stdio.h> int faktorial(int f){ if (f <= 0) return 1; else return f * faktorial(f - 1); } int main(){ printf("%d", faktorial(5)); // 120 }
f
) a je úplně jedno, že funkce se jmenuje stejně.
f
rovno 0 – vypadá zásobník takto:
f |f |f |f |f |f [5 |4 |3 |2 |1 |0 ]Pak se z rekurze zase vynořuje, předává se součin výsledků a nakonec vypadne 120.
if (f <= 0)
) a rekurze se zacyklí. Rozdíl oproti nezvládnutému while
cyklu je v tom, že tady vám roste zásobník a po čase dojde paměť.
Význam rekurze je v určité změně pohledu na problém.
Funkce faktoriál je napsaná tímto způsobem:
„Kolik je faktoriál 5 nevím, ale když mi řeknete, kolik je faktoriál 4, tak už to vědět budu.”
V dalším kroku:
„Kolik je faktoriál 4 nevím, ale když mi řeknete, kolik je faktoriál 3, tak už to vědět budu.”
A tak dál, až na konec:
„Kolik je faktoriál 0? No jedna, samozřejmě.”
Pak zase zpátky:
„Faktoriál 0 je 1? Potom faktoriál 1 je 1*1, takže 1.”
A stejně tak:
„Faktoriál 1 je 1? Potom faktoriál 2 je 2*1, takže 2.”
A nakonec:
„Faktoriál 4 je 24? Potom faktoriál 5 je 5*24, takže 120.”
Spočítejte složitost výpočtu faktoriálu rekurzí a porovnejte to se složitostí výpočtu faktoriálu cyklem for
.
Napište za použití rekurze funkci, která počítá Fibonacciho posloupnost. Ta je definována takto:
fi1 = 1; fi2 = 1; pro n > 2 fin = fin-1 + fin-2
Pak tutéž funkci napište bez rekurze.
Pak porovnejte složitosti těchto funkcí. Zjistíte, že zatímco u faktoriálu to vyjde nastejno, v tomto případě rekurze zoufale zaostává, že je v podstatě nepoužitelná. Jak si s tím poradit, o tom zas jindy.
#include <stdio.h> int c = 1; void prase(int b){ c = b; } int main(){ int a = 5; prase(3); a = c; }Takový program má při vstupu do funkce
prase
na zásobníku:
c |a |b [1 |5 |3 ]S tím, že proměnná
c
je vidět odkudkoli.
Zatímco rekurze z hlediska jazyka nebyla nic objevného, zato měla nedozírné důsledky z hlediska uvažování o problémech, se strukturami je to přesně naopak. Problém vám nevyřeší, obejdete se bez nich, ale je to tuze praktická věc.
#include <stdbool.h> #include <string.h> #include <stdio.h> struct clovek{ char jmeno[16]; int vek; int vyska; bool ples; }; int vypis(struct clovek nekdo){ printf("Ahoj, jmenuju se %s, je mi %d let, jsem vysokej %d cm a ", nekdo.jmeno, nekdo.vek, nekdo.vyska); if (nekdo.ples) printf("ne"); printf("mam vlasy\n"); } int main(){ struct clovek blaf; strcpy(blaf.jmeno, "Blaf"); blaf.vek = 24; blaf.vyska = 186; blaf.ples = false; vypis(blaf); struct clovek blafovo_plesate_dvojce; blafovo_plesate_dvojce = blaf; strcpy(blafovo_plesate_dvojce.jmeno, "Blof"); blafovo_plesate_dvojce.ples = true; vypis(blafovo_plesate_dvojce); }
struct typ_struktury
a za to do složených závorek výčet takzvaných členských proměnných, jako byste je deklarovali, vždycky typ a název. V tuto chvíli se ještě žádná paměť nealokuje, jen dáváte popis struktury.
struct typ_struktury promenna
. V tuto chvíli se na zásobníku naalokuje přesně tolik místa, kolik struktura zabere.
promenna.clenska_promenna
a pracuje se s nimi úplně stejně jako s jinými proměnnými.
Pokud jste ještě nečetli kapitolu o rekurzi a nepokusili jste se splnit úkoly k ní, nemá moc smysl se pouštět do této.
int fib(int n){ if ((n == 1) || (n == 2)) return 1; else return fib(n - 1) + fib(n - 2); }
n
, dvakrát pro n - 1
, pro n - 5
už osmkrát. A vždycky se to všechno počítá znova.
int fi[100]; int fib(int n){ if (!fi[n]) fi[n] = fib(n - 1) + fib(n - 2); return fi[n]; } int main{ fi[1] = 1; fi[2] = 1; for (int i=3; i<100; i++) fi[i] = 0; fib(99); }
Jaká je složitost zrychleného algoritmu na počítání Fibbonaciho posloupnosti?
Máte n záhonků vedle sebe. Na každém můžete zasadit mrkev nebo petržel, nesmí však být dva záhonky petržele hned vedle sebe. Kolika způsoby lze osadit vašich n záhonků?
Časem by měly přibýt ještě tyto kapitoly:
A u těchto to konečně začne být opravdu zábava:
Tato témata jsou pokročilejší: