diff --git a/KIV PPA1/Poznámky PPA1.md b/KIV PPA1/Poznámky PPA1.md index 1f36338..ce53f97 100644 --- a/KIV PPA1/Poznámky PPA1.md +++ b/KIV PPA1/Poznámky PPA1.md @@ -638,4 +638,1275 @@ for (int prvek: pole) { - Více takových metod může být deklarováno v tzv. utility třídě - Volání je pak možné z jakékoliv metody (třídy či instance) -#### Mechanizmus předání referenčních parametrů metod \ No newline at end of file +#### Mechanizmus předání referenčních parametrů metod +- Metody instance i statické metody třídy mají stejný mechanizmus předávání hodnot parametrů metod + - Hodnoty parametrů se předávají hodnotou + - Platí jak pro parametry primitivních datových typů, tak i referencí (typu třídy, ukazujících na instance) + - Stejný mechanizmus má ale různé důsledky + - Pro primitivní datové typy se změna hodnoty formálního parametru uvnitř metody neprojeví vně metody (protože hodnota parametru je pouze kopií) + - Obsah referenční proměnné je však pouze odkaz ukazující na instanci (na rozdíl od proměnné primitivního datového typu, která obsahuje hodnotu přímo, např. celé číslo) + - Pokud překopírujeme odkaz, bude pořád ukazovat na stejnou instanci => změny provedené v této instanci SE PROJEVÍ i vně metody + +### Konstruktor +- Při vytváření instance třídy operátorem ```new``` je vhodné nastavit počáteční hodnoty atributů této instance (objektu) – pro to slouží tzv. konstruktor +- Konstruktor + - Speciální metoda (instance) pro inicializaci objektu + - Musí se jmenovat stejně jako třída (včetně velikosti písmen) + - Nemá žádnou návratovou hodnotu (ani ```void```) + - Podle toho se pozná od ostatních metod (a podle názvu jako třída + - Při vytváření instance za ```new``` ve skutečnosti voláme konstruktor + - Protože se jmenuje stejně jako třída, vypadá to, že uvádíme třídu + - Konstruktor může být bez parametru, nebo může mít „libovolné“ množství a typ parametrů (jako běžná metoda) + - Konstruktor nemusí být ve třídě explicitně uveden, ale pokud je, typicky obsahuje inicializaci atributů instance + - Často s předáním hodnot atributů pomocí formálních parametrů konstruktoru + - Inicializace atributů nemusí být jen hodnotami formálních parametrů, mohou se např. pouze připravovat složitější datové struktury pro další výpočty + - Konstruktor může být (a často bývá) přetížen + - Umožňuje různou inicializaci atributů instance + +#### Proměnná ```this``` +- V konstruktoru (ale i setrech a dalších metodách) se typicky využívá speciální referenční proměnná ```this``` +- Referenční proměnná ```this``` + - Je dostupná v každé instanci a ukazuje na „tuto“ instanci (tj. na sebe sama) + - Všechny metody instance volané uvnitř své třídy (tj. z jiných metod instance, bez uvedení referenční proměnné, nad kterou jsou volány) jsou implicitně volány nad proměnnou ```this```, to samé platí pro atributy instance + - Díky tomu je možné používat metody a atributy instance uvnitř jejich třídy bez uvedení instance (implicitně se použije ```this```) + - Explicitní použití ```this``` umožňuje přístup k atributům instance, pokud jsou zastíněny lokální proměnnou nebo parametrem metody/konstruktoru se stejným názvem + - Parametry konstruktoru sloužící pro předání počátečních hodnot atributů instance se typicky jmenují stejně + - Díky ```this``` není nutné vymýšlet jiné názvy formálních parametrů metod/konstruktorů + - Explicitní uvedení ```this``` je možné u metod a atributů instance vždy (i když nedochází k zastínění), ale není to nutné ani příliš vhodné +- přetížení konstruktoru + - Při přetěžování konstruktoru je možné volat jiný konstruktor téže třídy + - Volání jiného konstruktoru musí být první příkaz v konstruktoru + - Volá se pomocí ```this(parametry);```, nikoliv jménem konstruktoru + - Není třeba opakovat kód konstruktoru => používá se běžně + +#### Implicitní konstruktor +- Pokud ve třídě není žádný konstruktor uveden volá se při vytváření nové instance implicitní konstruktor bez parametrů + - Tento konstruktor bez parametrů zajistí vytvoření instance v paměti + - Atributy instance jsou implicitně inicializovány na ``0, 0.0, false`` nebo ```null``` podle datového typu + - POZOR! – Pokud do třídy přidáme libovolný explicitní konstruktor, implicitní konstruktor nebude vytvořen! + - Pokud potřebujeme i konstruktor bez parametrů jako doplněk k dalším konstruktorům, musíme ho rovněž explicitně napsat + - Pak je možné použít konstruktor bez parametrů (ale nejedná se o implicitní konstruktor, protože je ve třídě přímo napsaný) + +### Zapouzdření a přístupová práva +- Atributy mohou být přístupné z vnějšku třídy + - Tento postup není vhodný, protože umožňuje změnu atributů bez jakékoliv kontroly, což umožňuje mj. zadat neplatné hodnoty +- **Zapouzdření** (encapsulation) + - Atributy objektu jsou **skryté před vnějšími vlivy** pomocí **přístupových práv** +- Pokud je potřeba změnit nastavení atributů, provádí se to prostřednictvím metod, které mohou obsahovat kontroly – tzv. ```setry``` + - Tyto metody by měly existovat pouze pro atributy, u kterých chceme jejich změnu z vnějšku třídy umožnit +- Pokud je potřeba získat hodnoty atributů, jsou zpřístupněny metodami nazvanými ```getry``` + - Tyto metody by měly existovat pouze pro atributy, jejichž hodnota má být přístupná z vnějšku třídy +- I metody mohou mít nastavená přístupová práva tak, aby je nebylo možné volat z vnějšku třídy + - Typicky pomocné metody + +#### Přístupová práva +- Přístupová práva určují, odkud lze k dané metodě nebo atributu přistoupit +- Klíčová slova určující přístupová práva se píší na začátek deklarace + - U atributů před datový typ + - Např. ```private int pocetClenu;``` + - U metod před návratovou hodnotu nebo ```void``` + - Např. ```public int naDruhou(int x)``` +- Přístupová práva (od nejméně po nejvíce restriktivní) + - ```public``` + - Metoda/atribut je přístupný odkudkoliv (ze stejné třídy, z jiné třídy stejného balíku, z jiné třídy jiného balíku) + - Typicky se používá pro metody + - ```protected``` + - Metoda/atribut je přístupný ze stejné třídy, z jiné třídy stejného balíku a z potomka třídy (viz předmět KIV/OOP) + - Neuvedeno (přístupové právo není explicitně uvedeno) + - Metoda/atribut je přístupný ze stejné třídy a z jiné třídy stejného balíku + - ```private``` + - Metoda/atribut je přístupný pouze ze stejné třídy + - Typicky se používá pro atributy +- Přístupová práva u třídy (a také rozhraní – viz předměty KIV/OOP a KIV/PPA2) + - ```public``` + - Třída musí být v souboru odpovídající názvu třídy + - Neuvedeno + - Třída může být v jiném souboru, který neodpovídá názvu třídy + - Více tříd pak může být v jednom souboru, ale maximálně jedna může být ```public``` (a její název pak odpovídá názvu souboru) + - Pak ale není viditelná z jiného balíku => nepoužívat + - Jiná přístupová práva pro třídy možná nejsou + +#### Getry a setry +- Metody pro přístup k atributům + - Getry začínají slovem ```get``` (anglicky „získat“), v případě atributu typu boolean slovem ```is``` (anglicky „je“) + - Setry začínají slovem ```set``` (anglicky „nastavit“) + - Slova ```get``` a ```set``` se používají, i když píšeme zdrojový kód česky + - Je to konvence pojmenování, která se dodržuje + - Jinak jsou to běžné metody +- Getry + - Hlavička přesně daná pro daný atribut + - ```public datovýTypAtributu getAtribut()``` + - ```public boolean isAtribut()``` + - Např. ```public int getX()``` + - Např. ```public boolean isPrazdny()``` + - Vrací hodnotu atributu, typicky obsahují jedinou řádku s příkazem ```return``` +- Setry + - Hlavička přesně daná pro daný atribut + - ```public void setAtribut(datovýTypAtributu atribut)``` + - Např. ```public void setX(int x)``` + - Nastaví hodnotu atributu + - Obsahuje přiřazení hodnoty do atributu předané přes formální parametr setru + - Typicky se používá referenční proměnná ```this``` jako v konstruktoru + - Typicky by měl obsahovat **kontrolu**, **zda je hodnota formálního parametru platná** (přípustná) + - POZOR! – Nastavit hodnotu pouze, pokud je platná, a jinak neudělat nic není nejšťastnější řešení – **reálně se řeší pomocí výjimek** + - Pokud tuto **kontrolu neobsahuje**, pak se vlastně o **zapouzdření nejedná**, protože si můžeme z vnějšku třídy dělat s atributem, co chceme (byť prostřednictvím getru a setru) + - Pokud tuto kontrolu dělá, **měl by být setr použit i v konstruktoru** místo přímého přiřazení + - Přiřazení je bez kontroly, což umožňuje zadat neplatnou hodnotu přes formální parametry konstruktoru +- Běžné metody instance (ne getry a setry) mohou měnit více atributů najednou, čímž vyjádří jednu změnu stavu instance + - Pokud jsou na sobě atributy závislé a neměly by se měnit každý zvlášť, pak by pro ně neměly existovat setry a místo toho by měla existovat metoda měnící konzistentně všechny závislé atributy najednou + +### Textová reprezentace objektu +- Objekty (instance), mohou být velmi komplikované (obsahovat mnoho různých atributů), často je ale **potřeba získat textovou reprezentaci** objektu (ve formě řetězce – ```String```) + - **Pro výpis objektu** do příkazové řádky – velmi často během ladění programu + - **Pro zobrazení objektu** např. v seznamu v grafickém uživatelském prostředí (GUI) + - Jsou i další použití + - Vypisování hodnot jednotlivých atributů ručně je zdlouhavé, pokud je atributů více, a kód pro výpis je navíc v jiné třídě => využívá se metoda ```toString()``` + +#### Metoda toString() +- Metoda vracející textovou reprezentaci objektu (instance) +- Hlavička metody ```public String toString()``` +- Tato metoda je implicitně v každé instanci (je zděděna od třídy ```Object``` – viz předmět KIV/OOP) +- Vrací řetězec popisující danou instanci + - Metoda pouze VRACÍ řetězec, sama ho NEVYPISUJE +Tato metoda se volá, pokud chceme objekt (instanci) vypsat pomocí metody ```System.out.println()``` +- **Implicitní implementace** + - Vrací řetězec obsahující název třídy, zavináč a číslo určující konkrétní instanci + - Např. ```Bod2D3@15db9742``` + - Neobsahuje informace o stavu třídy (např. hodnoty atributů) +- **Vlastní implementace** + - Implicitní metodu lze překrýt **vlastní implementací** + - Stačí ve třídě vytvořit **metodu se stejnou hlavičkou** + - Před metodu je vhodné napsat ```@Override``` indikující, že **metoda je překryta** (overridden) + - Není to nutné, ale např. Eclipse tuto entitu doplní automaticky, pokud necháme metodu ```toString()``` vygenerovat + - Bližší informace viz předmět KIV/OOP + - Metoda musí vracet řetězec, ale ten může obsahovat cokoliv + - Typicky obsahuje hodnoty atributů (při ladění programu), ale záleží na tom, na co chceme textovou reprezentaci třídy použít + - Příklad typické metody ```toString()``` + +### Porovnání objektů +- Objekty (instance) obecně nejsou uspořádané jako základní datové typy, operátory ```„>“, „>=“, „<“, „<=“``` tedy nelze použít +- Lze však použít porovnání na rovnost (operátor ```„==“```) a také různost (operátor ```„!=“```) + - POZOR! – Má jiný než očekávaný význam + - Výsledkem porovnání je **true**, **pokud se jedná o stejnou instanci** (tj. porovnávané referenční proměnné odkazují na stejnou instanci). **Pokud se nejedná o stejnou instanci**, je výsledkem porovnání **false** + - I když mají **dvě instance stejné třídy stejné hodnoty** všech atributů, výsledek je **false** + - Často je ale potřeba zjistit, zda jsou objekty shodné podle hodnot atributů (některých nebo všech) + - Lze dělat ručně porovnáváním jednotlivých atributů, ale pro více atributů zdlouhavé a kód pro porovnání je v jiné třídě => využívá se metoda ```equals()``` + +#### Metoda equals() +- Metoda slouží **k porovnání objektu** (instance) **s objektem stejné třídy** +- Hlavička metody ```public boolean equals(Object o)``` +- Tato metoda je implicitně v každé instanci (je zděděna od třídy ```Object``` – viz předmět KIV/OOP) + - Stejně jako metoda ```toString()``` +- Metoda vrací ```true```, pokud jsou instance shodné a ```false```, pokud jsou instance rozdílné + - **Co je shodné a rozdílné, určuje kód metody** + - Typicky **se porovnávají hodnoty atributů** +- **Implicitní implementace** + - Chová se stejně jako operátor „```==```“ + - Vrací **true** pouze v případě, že je **stejná instance** +- **Explicitní implementace** + - Implicitní metodu lze překrýt **vlastní implementací** + - Stačí ve třídě vytvořit metodu se stejnou hlavičkou + - Před metodu je vhodné napsat ```@Override``` indikující, že metoda je překryta (overridden) + - Existují doporučení, jak má kód metody ```equals()``` vypadat (viz předmět KIV/OOP) + - Porovnávaná instance je v parametru, který je typu (třídy) ```Object``` + - Aby bylo možné číst atributy porovnávané instance, je potřeba proměnnou explicitně přetypovat na typ třídy naší instance + - Přetypování se zapisuje stejně jako u základních datových typů (název třídy v kulaté závorce) + - Při pokusu o přetypování na nesprávný typ dojde k chybě za běhu programu + - Pak je možné porovnávat jednotlivé atributy + - Příklad implementace metody ```equals()``` + +### Výčtový typ +- Výčtový typ v Javě je sofistikovanější řešení pojmenovaných konstant + +#### Základní použití výčtového typu +- Základní použití výčtového typu se hodí v případě, kdy + - Máme více konstant, které spolu souvisí + - Jejich hodnota je irelevantní +- Deklarace výčtového typu + - Deklaruje se podobně jako třída, místo klíčového slova ```class``` se použije klíčové slovo ```enum``` + - Pravidla pojmenování jsou stejná jako pro třídu – počáteční písmeno velké, počáteční písmena všech dalších slov víceslovného názvu velká + - Pokud je označen přístupovým právem ```public```, musí být v samostatném souboru, jehož název odpovídá názvu výčtového typu + - Na začátku obsahuje konstanty, což jsou jednotlivé hodnoty výčtového typu + - Pravidla pojmenování stejná jako pro konstanty – všechna písmena velká, oddělovač slov ve víceslovném názvu je podtržítko + - Konstanty jsou odděleny čárkami +- Použití výčtového typu + - Výčtový typ můžeme využít pro deklarování libovolné proměnné (lokální, instance, třídy), jako návratovou hodnotu metody, atd. – stejně jako jakýkoliv jiný datový typ (základní, třída, pole) + - Do proměnné výčtového typu lze přiřadit pouze jednu z konstant definovaných v deklaraci výčtového typu nebo hodnotu ```null``` + - Při použití konstanty je třeba použít název výčtového typu + - ```VýčtovýTyp.KONSTANTA``` + - Podobně jako u konstant třídy + - Hodnoty výčtového typu lze porovnávat operátorem „```==```“ s očekávaným výsledkem (na rozdíl od instancí třídy) + - Hodnoty výčtového typu lze přímo vypsat + - Vypíše se přímo název konkrétní konstanty + +#### Pokročilé použití výčtového typu +- Výčtový typ má větší možnosti než bylo popsáno + - Může obsahovat proměnné a metody, které se pak vážou k jednotlivým hodnotám výčtového typu + - Např. u typu ```HodnotaKaret``` by bylo možné u každé hodnoty uvést bodovou hodnotu karet + - Podrobnosti viz předmět KIV/OOP + +## Uspořádání paměti +- **Paměť je** při vykonávání programu **rozdělena na zásobník a haldu** + - Obě části jsou fyzicky **ve stejné paměti (RAM)**, jen **na jiném místě** + +### Zásobník a halda +- **Při vykonávání programu se používají obě části**, některé věci jsou uloženy v zásobníku, jiné na haldě +- **POZOR**! + - **Neplést s datovými strukturami zásobník a halda** (viz předmět KIV/PPA2), jde o něco zcela jiného + - Bohužel v češtině i angličtině je pro obojí stejný název + - Část paměti halda není ani podobná datové struktuře halda + - Část paměti zásobník je principiálně podobný datové struktuře zásobník + +#### Zásobník (stack) +- Slouží pro ukládání volání jednotlivých metod + - Při volání metody se vytvoří nový zásobníkový rámec (stack frame), ve kterém se alokuje (tj. vytvoří) místo pro + - Pomocné hodnoty, které Java používá pro řízení běhu programu + - Formální parametry + - Všechny lokální proměnné + - Proměnné základních datových typů jsou zde uloženy přímo + - Lokální referenční proměnné jsou zde uloženy přímo, ale objekty (instance), na které ukazují, jsou uloženy na haldě + - Při dokončení metody se zásobníkový rámec uvolní +- Je podstatně menší než halda (řádově 1 MB) + - Může se stát, že dojde volné místo na zásobníku + - Typicky při vnořeném volání příliš mnoha metod (typicky při použití rekurze – viz předmět KIV/PPA2) + - Program se ukončí a objeví se chyba přetečení zásobníku (```stack overflow```) + +#### Halda (heap) +- Slouží **pro ukládání objektů (instancí) a polí** + - Při volání konstruktoru se alokuje místo na haldě potřebné pro uložení objektu, mj. jeho proměnných instance + - Paměť uvolní automaticky garbage collector, když na instanci neukazuje žádná referenční proměnná (ani ze zásobníku, ani z instančních referenčních proměnných uložených v instancích na haldě) + - Paměť nelze uvolnit ručně, ale lze JVM požádat, aby zvýšil úsilí automatického uvolňování paměti na haldě voláním metody ```System.gc();``` + - Po dokončení metody JVM udělal vše pro uvolnění paměti odstraněním instancí, na něž již neukazují referenční proměnné +- Je **podstatně větší než zásobník** (většina dostupné paměti – řádově GB) + - Přesto se může stát, že dojde volné místo na haldě + - Typicky při vytváření příliš mnoha a/nebo příliš velkých objektů (nebo polí) + - Program se ukončí a objeví se chyba nedostatku paměti (```out of memory```) + - Při postupném zaplňování paměti se před chybou program typicky zpomalí, což je důsledek zvýšené snahy garbage collectoru o uvolnění paměti +- Oblast metod (method area) + - Část haldy, ve které jsou uloženy přeložené výkonné kódy metod (třídy i instance) a také proměnné třídy + +## Pole +- **Strukturovaný datový typ pro uložení více prvků stejného typu** +- Pro uložení více hodnot stejného typu se hodí pole + +### Základní práce s (jednorozměrným) polem +- Pole + - Strukturovaný datový typ + - Skládá se z **pevně daného počtu prvků** + - **Je homogenní** – všechny prvky v něm uložené jsou stejného typu + - **Počet prvků se stanoví při inicializaci** (vytvoření) pole a pak již **nelze změnit** + - **Počet prvků je délka pole**, která je v **poli kromě prvků rovněž uložená** +- Indexy + - Jednotlivé prvky pole jsou **přístupné pomocí indexů** + - V Javě má index vždy hodnoty 0 až délka pole - 1 + +#### Deklarace a vytvoření pole +- Pole je podobné třídám a objektům + - V podstatě se jedná o speciální třídu a při inicializaci pole vytváříme její „instanci“ uloženou na haldě +- Je potřeba deklarovat referenční proměnou a vytvořit novou „instanci pole“ operátorem ```new``` + - Stejně jako u objektů je možné udělat obojí najednou, nebo nejprve deklarovat referenční proměnou a později vytvořit nové pole + - ```datovýTyp[] proměnná = new datovýTyp[početPrvků];``` + - Při vytváření nového pole se udává počet prvků (v hranatých závorkách „[“ a „]“), které bude pole obsahovat + - Typ prvků pole může být libovolný + - Libovolný základní datový typ + - Libovolná třída +- Protože proměnná typu pole je referenční, může být ```null``` + - Pokud se jedná o lokální proměnnou a nevytváříme pole hned při deklaraci jeho referenční proměnné, je rozumné inicializovat referenční proměnnou na ```null``` + - Pokud se jedná o proměnnou instance nebo třídy, je inicializována na ```null``` implicitně +- Při vytvoření pole jsou jeho jednotlivé prvky implicitně inicializovány na ```0, 0.0, false``` nebo ```null``` podle datového typu pole + - I v případě, že referenční proměnná ukazující na pole je lokální +- Vytvoření pole výčtem hodnot + - Pole je kromě operátoru ```new``` možné vytvořit i výčtem jeho hodnot uvedeným ve složených závorkách ```„{“``` a ```„}“``` + - Např. ```int[] fibonacci = {0, 1, 1, 2, 3, 5, 8, 13};``` + - Pole má stejné vlastnosti jako pole vytvořené operátorem ```new``` – délku pole určí překladač podle počtu prvků + - Často používáno jako vzorová data pro usnadnění ladění, nebo uložení pole konstantních hodnot + - POZOR! – Takto definované pole nemá konstantní prvky, **jeho prvky lze libovolně měnit**, např. ```fibonacci[3] = -6;``` + - POZOR! + - Samotným výčtem hodnot lze pole vytvořit POUZE PŘI DEKLARACI + - Pokud chceme přiřadit do existující referenční proměnné nové pole výčtem hodnot, musí samotnému výčtu předcházet vytvoření pole operátorem ```new``` bez udání počtu prvků + - proměnná = ```new datovýTyp[] {hodn1, hodn2, …};``` + - Např. ```fibonacci = new int[] {1, 1, 2, 3};``` +- Konstantní pole + - Použití klíčového slova ```final``` nezajistí, aby prvky pole po prvním přiřazení nešly změnit + - ```final``` pouze zajistí konstantnost referenční proměnné – nelze do ní již přiřadit jinou hodnotu (tj. jiné pole) + - Prvky pole, na které ukazuje ```final``` referenční proměnná lze ale měnit bez problémů + - To samé platí pro referenční proměnné a instance tříd – hodnoty atributů (proměnných) instance lze měnit, i když je referenční proměnná ukazující na instanci označena jako ```final``` + +#### Přístup k prvkům pole a jeho délka +- K jednotlivým prvkům pole se přistupuje pomocí indexu + - Index se zapisuje za referenční proměnou do hranatých závorek + - ```proměnná[index]``` +- Prvek pole se chová stejně jako proměnná odpovídajícího datového typu + - Lze do něj zapisovat hodnotu + - Lze z něj číst hodnotu + - Např. ```teploty[0] = 17.5;``` + - Např. ```double teplota = teploty[0];``` +- Délka pole + - Každé pole má v sobě informaci o délce uloženou v proměnné ```length``` + - Volá se přes tečkovou notaci stejně jako proměnná instance nad referenční proměnnou pole + - Např. ```int pocetTeplot = teploty.length;``` + - První prvek pole má index 0 + - ```Např. double prvniTeplota = teploty[0];``` + - Poslední prvek pole má index ```pole.length – 1``` + - Např. ```double posledniTeplota = teploty[teploty.length - 1];``` + - Index mimo rozsah pole + - POZOR! – Při pokusu o přístup k prvkům se záporným indexem nebo indexem větším nebo rovným délce pole, dojde k chybě za běhu programu (nikoliv při překladu) – je vyhozena výjimka ```ArrayIndexOutOfBoundsException``` +- Použití pole jako parametr metody + - Pole může být použito jako parametr metody (stejně jako primitivní datový +typ nebo třída) + - POZOR! – Stejně jako u tříd a instancí platí, že změny provedené v hodnotách pole předaného do metody jako parametr se projeví vně metody + +#### Výpis celého pole, inicializace stejnou hodnotou +- Pro práci s poli existuje utility třída ```java.util.Arrays``` + - Obsahuje statické metody (podobně jako třída ```Math```) pro práci s poli +- Výpis celého pole + - Metoda ```Arrays.toString()``` + - Převede celé pole na řetězec, který lze následně vypsat např. metodou ```System.out.println();``` + - POZOR! + - Sama metoda řetězec pouze vrací, nevypisuje ho + - Podobně jako metoda instance toString() u objektů + - Pokud necháme vypsat pole metodou ```System.out.println()``` přímo (bez metody ```Arrays.toString()```), vypíše se pouze identifikace „instance pole“ + - Podobně jako implicitní implementace metody instance ```toString()``` u objektů + - Např. volání ```System.out.println(vektor1);``` vypíše např. [D@1b6d3586 (čísla za „@“ se budou při různých spuštěních lišit) +- Inicializace prvků pole stejnou hodnotou + - Prvky pole jsou při vytvoření implicitně inicializovány na ```0, 0.0, false``` nebo ```null``` podle datového typu pole + - Pokud je potřeba inicializovat pole jinou hodnotou (stejnou pro všechny prvky), je možné využít metodu ```Arrays.fill(pole, hodnota);``` + - Např. ```Arrays.fill(ciselnaRada, 1);``` naplní všechny prvky pole ```ciselnaRada``` hodnotou ```1``` + - Metoda je překrytá pro pole všech základních datových typů a pole typu ```Object``` + - Existuje i varianta s určením počátečního a koncového indexu vyplnění pole ```Arrays.fill(pole, indexOd, indexDo, hodnota);``` + Např. ```Arrays.fill(ciselnaRada, 0, 2, 10);``` naplní první dva prvky (**počáteční index je včetně**, **koncový není včetně**) pole ```ciselnaRada``` hodnotou ```10``` + +#### Použití zápisu ```for - each``` +- Pokud nepotřebujeme pracovat s indexem pole a stačí nám postupný přístup ke všem jednotlivým prvkům, je možné použít zkrácený zápis cyklu ```for``` (známý též jako ```for - each```) + - ```for (datovýTyp prvek: pole)``` + - Cyklus zaručí, že se dostane na všechny prvky – projde se celé pole od začátku do konce + - V každé obrátce cyklu je v proměnné prvek následující prvek pole + - Běžně se používá pro pole (a kolekce – viz předmět KIV/PPA2) objektů + +#### Pole jako tabulka, přepočet indexů +- Tabulka + - Datová struktura obsahující dvojice klíč a hodnota + - Pro daný klíč můžeme získat hodnotu + - Viz předměty KIV/PPA2 a KIV/PT +- Pole se dá použít jako jednoduchá tabulka + - Index může sloužit jako klíč + - Hodnota prvku pole jako hodnota + - Indexy pole začínají vždy od 0 – pokud je potřeba jiný začátek klíčů, je potřeba přepočet + +#### Reprezentace množiny polem +- Množina + - Soubor prvků (např. čísel) chápaných jako celek + - Každý prvek může být obsažen v množině maximálně jednou +- Pro reprezentaci množiny lze využít pole typu ```boolean[]``` + - Indexy odpovídají prvkům množiny + - Hodnoty prvků pole udávají, zda prvek je přítomný v množině (```true```) nebo není (```false```) + +### Pole objektů +- Prvkem pole můžou být kromě základních datových typů i instance + - Použití se nijak neliší, jen je potřeba nezapomenout vytvořit instance jednotlivých prvků, což se u základních datových typů nedělá + +#### Deklarace pole objektů a jeho inicializace +- Deklarace a vytvoření pole se neliší od polí základních datových typů + - Je potřeba deklarovat referenční proměnnou a vytvořit novou „instanci pole“ operátorem ```new``` + - ```Třída[] proměnná = new Třída[početPrvků];``` + - Např. ```Vysledek[] vysledky = new Vysledek[POCET];``` + - Opět je možné nejprve deklarovat referenční proměnnou a později vytvořit nové pole + - Jednotlivé prvky referenční proměnné na instance třídy odpovídající typu pole + - Po vytvoření pole jsou všechny implicitně inicializovány na hodnotu ```null``` + - POZOR! – V tomto okamžiku (po vytvoření pole) tedy jednotlivé instance prvků neexistují – dosud nebyly vytvořeny operátorem ```new``` +- Vytvoření instancí prvků pole + - Instanci každého prvku je potřeba vytvořit zvlášť, typicky v cyklu ```for``` + +#### Přístup k prvkům pole a k proměnným a metodám instance prvků +- Přístup k prvkům pole je stejný jako u polí základních datových typů pomocí indexu v hranatých závorkách „[“ a „]“ +- Jednotlivé prvky jsou referenční proměnné ukazující na jednotlivé instance + - Přístup k atributům a metodám instance je přes tečkovou notaci použitou nad prvkem pole + +### Vícerozměrná pole +- Pole může mít více rozměrů + - Často se využívají dvourozměrná (např. pro uložení matic), ale mohou být i tří a vícerozměrná + - Pole s více než třemi rozměry většinou nemají reálné opodstatnění + - Pro určení požadovaného prvku pole je potřeba více indexů + - Počet odpovídá počtu rozměrů pole +- Vícerozměrné pole jako **pole polí** + - Dvourozměrné pole v Javě je ve skutečnosti jednorozměrné pole referenčních proměnných, kde každá ukazuje na jednorozměrná pole (tj. „řádku“) + - Díky tomu má každé jednorozměrné pole svou délku, kterou je možné zjistit, a dvourozměrné pole ji má též + - Z dvourozměrného pole tak lze zjistit jeho počet řádek i sloupců + - Každé jednorozměrné pole může mít jinou délku + - Trojrozměrné pole v Javě je pak jednorozměrné pole referenčních proměnných, kde každá ukazuje na dvourozměrné pole, atd. + +#### Deklarace a vytvoření vícerozměrného pole +- Deklarace referenční proměnné pro vícerozměrné pole je podobná jako pro jednorozměrné + - Pouze obsahuje více prázdných párů hranatých závorek „[]“ – jeden pár pro každý rozměr pole + - ```datovýTyp[][]…[] proměnná;``` + Např. ```double[][] prvkyMatice;``` +- Vytvoření všech rozměrů najednou + - Nejběžnější použití vícerozměrných polí + - Počty prvků ve všech rozměrech pole udány najednou + - V případě dvourozměrného pole má každý řádek stejnou šířku + - Tzv. pravoúhlé pole – pole tvoří pravoúhlý obrazec – obdélník, kvádr, teserakt, atd. + - ```proměnná = new datovýTyp[počet1][počet2]…[početN];``` + - Např. ```prvkyMatice = new double[vyska][sirka];``` +- Vytvoření rozměrů postupně + - Počty prvků v jednotlivých rozměrech udány postupně + - Nejprve vytvoříme „vnější“ pole a pak do jeho jednotlivých prvků přiřadíme nové „instance“ „vnitřních“ polí + - V případě dvourozměrného pole může mít každý řádek různou délku + - Pole je „zubaté“ + - ```proměnná = new datovýTyp[počet1][]…[];``` + - POZOR! + - Musí se vždy začínat rozměrem nejvíc vně (tj. první závorky zleva) + - Nelze ```proměnná = new datovýTyp[][počet2]…[];``` +- Vytvoření pole výčtem hodnot + - I vícerozměrné pole je možné vytvořit výčtem hodnot + - Pole může být pravoúhlé i „zubaté“ + - Platí stejná pravidla, jako při vytváření jednorozměrného pole + - Použití samotného výčtu je možné pouze při deklaraci, při pozdějším vytvoření pole je nutné použít i operátor ```new``` + +#### Přístup k prvkům pole +- Pro přístup k jednotlivým prvkům vícerozměrného pole se používá více indexů + - Počet indexů odpovídá počtu rozměrů pole +- Použití méně indexů než je rozměrů pole + - Při použití méně indexů se nedostaneme k prvku pole, ale k poli s menším rozměrem + - Např. pokud máme dvourozměrné pole a použijeme pouze jeden index, dostaneme se k jednorozměrnému („vnitřnímu“) poli, tj. k „řádce“ pole + - V okamžiku, kdy se dostaneme na „vnitřní“ pole, můžeme zjistit jeho délku + - To se velmi často využívá + - Funguje dobře při procházení vícerozměrného pole, i pokud je pole „zubaté“ +- Příklady přístupu k prvkům pole a k „vnitřním“ polím kvůli jejich délce je na + - Deklarace a vytvoření pole ```jednotkovaMatice``` +- Kompletní příklad na použití dvojrozměrných polí k násobení matic (v kombinaci s objekty) + - Použitá třída ```Matice``` + +### Pole v paměti +- Pole je ve skutečnosti instance speciální třídy a je celé uloženo na haldě (heap) + - Jak to vypadá v paměti při práci s poli, je demonstrováno na příkladu s polem primitivního datového typu a na příkladu s polem objektů +- **Pole nulové délky** + - Pole může mít délku 0 prvků + - Pak nemá žádný prvek, do kterého by šla zapsat hodnota, ale může být použitelná informace o nulové délce +- Rozdíl oproti referenční proměnné pole rovné ```null``` + - **Referenční proměnná pole rovná null** neukazuje na žádné pole (**žádné pole není na haldě**) + - Pole nulové délky na haldě existuje a ukazuje na něj referenční proměnná, neobsahuje ale žádný prvek + +#### Pole primitivních datových typů v paměti +- Pole primitivních datových typů ve své „instanci“ **přímo obsahuje hodnoty jednotlivých prvků** + +## Ověřování správnosti programu, ladění +- Při vytváření programů je do zdrojového kódu (neúmyslně) zaneseno mnoho různých chyb od překlepů přes neošetření hraničních případů až po logické chyby v celkovém chování programu +- Část chyb odhalí překladač (a upozorní nás na ně IDE nástroj) – chyby při překladu +- Část chyb překladač neodhalí a program jde přeložit + - POZOR! + - Pokud jde program přeložit, neznamená to, že funguje správně! + - Program může (někdy nebo vždy) dávat nesprávné výsledky + - Může docházet k chybám za běhu programu +- Chyby, které překladač neodhalí (chyby za běhu programu), je třeba najít a opravit opakovaným opravováním, překládáním a spouštěním programu s využitím vhodných vstupních dat + - Tato činnost se nazývá ladění (častěji debugging) +- Lze provádět ručně nebo s využitím specializovaného nástroje zvaného debugger – součást téměř všech IDE nástrojů + - Často se používá kombinace obou přístupů +- Vyšší fází ladění je testování + - Zjišťuje se, zda program pracuje správně pro všechny typy vstupů, zda reaguje správně na neplatné vstupy apod. + - Podrobně viz předmět KIV/OKS + +### Odhalení chyb při psaní zdrojového kódu a při překladu +- Překladač ```javac``` umí odhalit především syntaktické chyby + - Často způsobené překlepy v názvech proměnných, metod, zapomenutím na import třídy, zapomenutím deklarace proměnné, atd. + - Všechny nalezené chyby jsou vypsány při překladu +- Překlad v příkazové řádce + - Pokud překládáme program ručně v příkazové řádce příkazem javac, objevíme chyby až po spuštění překladu + - Protože překlad netrvá dlouho (pro malé programy), je možné provádět ho během vývoje opakovaně, např. při každém inkrementálním přidání funkcionality + - Nalezené chyby lze průběžně odstraňovat + - Odstranění chyby se ověří opakovaným překladem + - Je možné i napsat celý program a poté odstranit chyby najednou + - Odstranění chyb se opět ověří opakovaným překladem + - POZOR! + - Při opakovaném překladu se počty chyb mohou snižovat i zvyšovat + - Překladač se snaží při překladu najít co možná nejvíce chyb tj. neskončí při první nalezené chybě, ale pokud to jde, pokračuje dále + - Některé chyby jsou však z pohledu překladače natolik zásadní (ač z pohledu člověka vypadají banálně – např. zapomenutý středník „;“ nebo složená závorka „}“), že mu znemožní kontrolu velké části kódu + - Po opravení takové chyby může překladač tuto přeskočenou část zkontrolovat a tím odhalit další, dosud neodhalené chyby počet chyb může po odstranění chyby vzrůst + +#### Čtení a porozumění výstupu překladače +- Výstup překladače (tj. výpis chyb při překladu) se zobrazí po skončení překladu v příkazové řádce nebo v konzoli IDE nástroje +- Výstup nemusí být stejný v IDE a v příkazové řádce + +### Ladění (debugging) +- Pokud se **program podaří přeložit**, ještě to **neznamená, že funguje správně** + - Většinou správně nefunguje, i když jde přeložit +- Chyby v chování programu neodhalí překladač, musí je najít sám programátor +- Chybné chování programu se typicky projevuje: + - Program je předčasně ukončen s chybovým hlášením (vždy nebo někdy) + - Je třeba rozumět chybovému hlášení + - Program zdánlivě funguje, ale dává pro některé či všechny vstupy zcela špatné nebo částečně špatné výsledky + - Ladění je možno provádět ručně tzv. metodou ladících výpisů a/nebo s využitím specializovaného ladícího nástroje (debuggeru) + - POZOR! + - Program se nedá považovat za odladěný po vyzkoušení jednoho či několika málo vstupů + - Je potřeba zkoušet více různých vstupních hodnot, netypické hodnoty apod. + - Je potřeba zkoušet i neplatné hodnoty, na něž by měl program adekvátně reagovat + - To však zatím není probráno + +#### Chybové hlášení za běhu programu +- Pokud dojde za běhu programu k chybě (přesněji k vyhození výjimky) a tato chyba není v programu ošetřena, program je předčasně ukončen a do konzole (či příkazové řádky) se vypíše chybové hlášení +- Chybové hlášení + - Vypíše, o jakou chybu (výjimku) se jedná (její název a někdy i popis) + - Vypíše tzv. stack trace (výpis zásobníku) + - Zjednodušený obsah zásobníku (stack) programu v okamžiku, kdy k chybě došlo + - Obsahuje volání metod – je jasné, v jaké metodě přesně došlo k chybě (první uvedená metoda) a ze které metody byla tato metoda volána (další uvedená metoda) + - Následují další metody, které byly hierarchicky volány až k metodě ```main()``` + - V jednoduchých programech je většinou zobrazeno i číslo řádky, na které k chybě došlo + - Hlášení o chybách za běhu programu typicky vypadají stejně v příkazové řádce i v konzoli IDE nástroje + +#### Metoda ladících výpisů +- Metoda ladících výpisů se používá, **pokud nemáme k dispozici debugger**, nebo ho z nějakého důvodu nechceme použít +- Na vhodná místa programu vložíme volání metody System.out.println() + - Můžeme vypisovat hodnoty důležitých proměnných + - Můžeme pomocí výpisu unikátních značek (tj. textů) určit, kde se program +- přesně nachází (podle toho, co a v jakém pořadí program vypíše) + +#### Použití debuggeru v Eclipse +- Debugger umožňuje dělat automaticky to, co musíme ručn pomocí kontrolních výpisů a umožňuje mnohem více + - Sledování hodnot vybraných proměnných a výrazů + - Krokování programu řádku po řádce + - Nastavení breakpointů – bodů, ve kterých se program zastaví a umožní od něj krokování +- Spuštění debuggeru v Eclipse + - Vytvoření breakpointu + - Pro zapnutí debuggeru je potřeba nastavit breakpoint, tedy bod, od kterého bude program krokován + - Breakpoint se na určitou řádku nastaví dvojklikem vlevo od požadované řádky + - Alternativou je kliknout pravým tlačítkem na stejné místo => vybrat Toogle breakpoint + - Přítomnost breakpointu na řádce je indikována symbolem + - Stejným způsobem lze breakpoint odstranit + - Spuštění debuggeru + - Mít aktivní třídu s breakpointem + - Debug as… => Java Application + - Pokud si Eclipse není jistý, který program chcete debuggovat, dá vám na výběr + - Pokud není zvolen žádný breakpoint, program proběhne jako při normálním spuštění + - Po spuštění debuggeru program běží normálně, dokud nedosáhne breakpointu + - Potom se objeví dotaz, zda chceme spustit debug perspektivu, která přepne rozložení oken Eclipse +- Popis debug perspektivy v Eclipse + - Okno zásobníku + - Ukazuje, v jaké části programu se právě nacházíme + - Jde o zobrazení části paměti zásobník obsahující rámce pro jednotlivé volání metod + - Toto okno příliš nevyužíváme + - Okno editoru + - Okno se zdrojovým kódem + - V debug perspektivě se zpravidla nepoužívá pro úpravu kódu + - Zelený pruh určuje řádku, na které se program právě nachází při jeho krokování + - Jsou vidět nastavené breakpointy + - Nejdůležitější okno debuggeru + - Okno se strukturou programu (outline) + - Zobrazuje strukturu programu (jednotlivé třídy a metody) + - Toto okno příliš nevyužíváme + - Okno konzole + - Okno, do kterého se vypisuje výstup programu + - Uživatel zde rovněž zadává vstup programu, pokud je třeba + - Okno sledování proměnných + - Zde můžeme sledovat všechny proměnné a jejich aktuální hodnoty během krokování programu + - Druhé nejdůležitější okno debuggeru + - V záložce Breakpoints je seznam všech nastavených breakpointů +- Ovládání debuggeru + - V okamžiku, kdy se program zastaví na breakpointu, lze pokračovat v jeho krokování různými způsoby + - Step Into - též klávesa [F5] + - Provede jeden krok programu + - Pokud je tímto krokem volání metody, skočí do této metody + - Step Over – též klávesa [F6] + - Provede jeden krok programu + - Pokud je tímto krokem volání metody, provede ji celou jako jeden krok (tj. do metody neskočí) + - Step Return – též klávesa [F7] + - Provede všechny zbývající příkazy v metodě, vyskočí z ní a zastaví se na dalším řádku volající metody + - Resume – též klávesa [F8] + - Provede všechny příkazy od aktuální pozice až k dalšímu breakpointu (nebo do ukončení programu) normálně (tj. bez krokování) + - Terminate – též [Ctrl]+[F2] + - Ukončí provádění programu + - Nastavení filtrů krokování (step filters) + - Umožní omezit, do kterých metod je možné při krokování skočit + - Např. nechceme, abychom se při krokování dostali do knihovních tříd a metod Java Core API + - Zapnutí filtrů krokování (Use Step Filters – též [Ctrl]+[F5]) + - Pokud je tlačítko zapnuté, filtry jsou použity a do vybraných balíků nevstoupí ani možnost Step Into + - Sledování hodnot proměnných (okno sledování proměnných) + - Záložka Variables + - Automaticky zobrazuje platné lokální proměnné a jejich hodnoty + - Pro zobrazení statických proměnných a konstant je nutné je zaškrtnout + - => Java => Show Constants a Show Static Variables + - Zobrazení aktuální hodnoty proměnné + - Stačí kurzorem myši najet v okně editoru na proměnnou, která nás zajímá +- Díky debuggeru přesně vidíme, co se v programu děje, jaké jsou hodnoty proměnných + - Podstatně komfortnější, než kontrolní výpisy + - Lze vyzkoušet na odhalení chyb v programu pro výpočet faktoriálu + +## Řetězce a práce s nimi +- Třída ```String``` + - Jedna z nejpoužívanějších tříd z Java Core API + - Řetězcové konstanty (literály – texty uzavřené do uvozovek, např. "Ahoj") používáme od začátku předmětu KIV/PPA1 + +### Specifické vlastnosti třídy String +- ```String``` je třída, jednotlivé řetězce (tj. texty) jsou její instance uložené na haldě (na heapu) +- Z praktických důvodů má však některé vlastnosti, které u jiných tříd nejsou + +#### Vytvoření řetězce bez operátoru new +- Jak bylo vidět ve všech příkladech, které dosud vypisovaly text, instance třídy ```String``` může vzniknout i bez operátoru ```new``` + - Vznikne zápisem literálu (nepojmenované konstanty) + - Např. ```String pozdrav = "Ahoj!";``` + - Např. ```System.out.println("Nazdar!");``` + - Tento postup jsme používali dosud (aniž jsme věděli o tom, že vznikají instance třídy ```String```) + - Tento postup se používá běžně +- Je možné i přímo vytvořit novou instanci třídy String operátorem ```new``` + - Třída ```String``` obsahuje několik konstruktorů umožňující vytvořit řetězec z pole znaků, pole bytů, atd. + - Je možné i vytvořit nový řetězec z jiného řetězce + - Např. ```String pozdrav = new String("Ahoj!");``` + - Tento zápis NEPOUŽÍVAT + - Protože samotný zápis literálu "```Ahoj```" způsobí vytvoření nové instance třídy ```String```, volání new ```String()``` zbytečně vytvoří další instanci + +#### Konstantnost řetězce +- Řetězce v Javě (tj. instance třídy ```String```) jsou konstantní, neměnné (immutable) + - Nelze do nich přidávat text, mazat, nebo měnit jednotlivé znaky + - Veškeré metody zdánlivě upravující řetězec ve skutečnosti vytvoří novou instanci třídy ```String``` a text v původní instanci zůstane nedotčen +- Existují třídy pro práci s měnitelným řetězcem + - Třída StringBuilder + - Třída StringBuffer + - Přesto si ve většině případů vystačíme s třídou ```String``` + - To, že při změně obsahu řetězce dojde k vytvoření nové instance a původní zůstane nezměněná, nám nevadí (v podstatě si toho nevšimneme) + +#### Spojení řetězců pomocí operátoru „+“ (zřetězení) +- Od začátku jsme běžně používali + - Především v metodě ```System.out.println()``` +- Operátor „+“ spojí dva řetězce (operandy) a vytvoří novou instanci obsahující texty obou řetězců (operandů) +- Operátor „+“ také umožňuje připojit k řetězci libovolný datový typ + - Hodnota daného typu se převede na řetězec + - Alespoň jeden operand musí být řetězec, pokud ne, má operátor „+“ význam sčítání + - Pro přehlednost je lepší začínat řetězcem, pokud nechceme začínat uvozujícím textem, lze použít prázdný řetězec + - Časté je použití přímo v metodě ```System.out.println()``` + +### Práce s řetězci +- Metody pro práci s řetězci jsou převážně **metody instance třídy String** +- Proto se volají nad referenční proměnnou ukazující na instanci řetězce + - ```referenčníProměnná.názevMetody(parametry);``` + - Např. ```pozdrav.charAt(0);``` + - Stejné jako u jiných objektů +- Protože instance řetězce vznikne pouhým zapsáním literálu, lze nad ním rovnou volat metody bez nutnosti použití referenční proměnné + - Např. ```"Ahoj".charAt(0); //Funkcni ale nepouzivat``` + - NEPOUŽÍVAT! + +#### Práce s jednotlivými znaky a délka řetězce +- Řetězec si lze představit jako speciální konstantní pole znaků + - Ale jedná se o instanci třídy, nelze s ní pracovat jako s polem – tj. přistupovat k jednotlivým znakům pomocí hranatých závorek „[“ a „]“ + - Pole znaků (tj. ```char[]```) je uvnitř řetězce skutečně obsaženo +- Pro následující příklady předpokládejte deklaraci + - ```String pozdrav = "Nazdar";``` +- Délka řetězce + - Metoda ```length()``` + - POZOR! – Je to metoda, nikoliv proměnná, jako u polí (tj. musí se uvést závorky) + - Vrací počet znaků řetězce (včetně bílých znaků) + - ```int delka = pozdrav.length(); //delka bude 6``` +- Znak na zadané pozici + - Metoda ```charAt(indexZnaku)``` + - Znaky mají index podobně jako prvky pole číslované od 0 do délka řetězce - 1 + - ```char znak = pozdrav.charAt(0); //znak bude 'N'``` +- Index prvního výskytu znaku/podřetězce + - Metoda ```indexOf(znak/podřetězec)``` + - Vrátí index prvního výskytu znaku (podřetězce) v řetězci, nebo -1, pokud znak (podřetězec) není nalezen + - ```int index1 = pozdrav.indexOf('a'); //index1 bude 1``` + - ```int index2 = pozdrav.indexOf("zd"); //index2 bude 2``` + - ```int index3 = pozdrav.indexOf("j"); //index3 bude -1``` +- Index posledního výskytu znaku/podřetězce + - Metoda ```lastIndexOf```(```znak/podřetězec```) + - Vrátí index posledního výskytu znaku (podřetězce) v řetězci, nebo -1, pokud znak (podřetězec) není nalezen + - ``int li1 = pozdrav.lastIndexOf('a'); //li1 bude 4`` + - ```int li2 = pozdrav.lastIndexOf("Na "); //li2 bude 0 ``` +- Náhrada všech výskytů znaku v řetězci + - Metoda ```replace(puvodníZnak, novýZnak)``` + - ```String s2 = pozdrav.replace('a', 'e'); //"Nezder"``` + +#### Porovnání řetězců +- Řetězce jsou instance třídy ```String``` +- Porovnání pomocí operátoru „```==```“, pouze zjistí, zda se jedná o stejné instance **nepoužívat** +- **Porovnání podle obsahů** (důsledně včetně velikosti písmen) – **shodné/rozdílné** + - Metoda ```equals```(```jinýŘetězec```) + - Výsledek ```true``` (řetězce jsou shodné) nebo ```false``` (řetězce jsou rozdílné) +- Porovnání podle obsahů **bez ohledu na velikost písmen** – **shodné/rozdílné** + - Metoda ```equalsIgnoreCase```(```jinýŘetězec```) + - Výsledek ```true``` (řetězce jsou shodné bez ohledu na velikost písmen) nebo ```false``` (řetězce jsou rozdílné bez ohledu na velikost písmen) +- Porovnání podle obsahů (**důsledně včetně velikosti písmen**) – **větší/menší/stejný** + - Metoda ```compareTo```(```jinýŘetězec```) + - Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je dále od začátku abecedy) + - Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je blíže konci abecedy) +- POZOR! – Návratové hodnoty metod ```compareTo…()``` + - Vrácené záporné a kladné číslo (když řetězce nejsou shodné) nemusí být (a není) jen -1 nebo 1 + - Návratovou hodnotu metody je třeba porovnávat pomocí operátorů „>“ a „<“, nikoliv porovnáním operátorem „==“ s -1 či 1 +- **Test začátku a konce řetězce** + - Výsledek ```true```, pokud řetězec začíná/končí zadaným podřetězcem, jinak vrací ```false``` + - Metoda ```startsWith(prefix)``` + - Metoda ```endsWith(postFix)``` + - Metoda ```startsWithIgnoreCase(prefix)``` + - Metoda ```endsWithIgnoreCase(postFix)``` + +#### Získání podřetězce z řetězce +- Stále předpokládáme deklaraci ```String pozdrav = "Nazdar";``` +- Získání podřetězce od zadaného indexu (**včetně**) do konce + - Metoda ```substring(indexOd)``` + - ```String p1 = pozdrav.substring(2); //p1 bude "zdar"``` +- Získání podřetězce od zadaného indexu (**včetně**) do zadaného indexu (**vyjma**) + - Metoda ```substring(indexOd, indexDo)``` + - ```String p2 = pozdrav.substring(0, 2); //p2 bude "Na"``` +- Odstranění bílých znaků ze začátku a konce řetězce + - Metoda ```trim()``` + - Uvažujme deklaraci ```String bz = "\r\n \tahoj \t\n\r";``` + - ```String oriznuty = bz.trim(); //oriznuty bude "ahoj"``` + +### Konverze řetězce na jiné datové typy a obráceně +- Relativně časté operace + - **Převod řetězce na číselný datový typ** + - Typicky při vstupu (když nepoužíváme Scanner, nebo je vstup komplikovanější, nebo v GUI) + - Číselný datový typ je potřeba, abychom mohli provádět aritmetické operace + - ```Např. "1" + "2" je řetězec "12", ale 1 + 2 je 3``` + - **Převod čísla na řetězec** + - Implicitně se provádí při každém výstupu + - Explicitně, když chceme využít operace nad řetězci např. pro čísla (např. zjištění počtu znaků (tj. číslic), zřetězení s řetězcem) + - **Převod instance (objektu) na řetězec** + - Pokud chceme instanci vypsat + +#### Konverze řetězce na jiné datové typy +- Pro základní datové typy se používá metoda ```Typ.parseTyp(řetězec)``` z příslušné obalovací třídy základního datového typu + - Jedná se o metody třídy, volá se s názvem třídy, není potřeba vytvářet instanci + - Např. ```int i = Integer.parseInt("42");``` + - Např. ```long l = Long.parseLong("2444111333");``` + - Např. ```double d = Double.parseDouble("5.972E24");``` + - Např. ```boolean b = Boolean.parseBoolean("false");``` + - Pro objekty + - Není žádný standardní a obecný postup pro převod řetězce na instanci jiné třídy + +#### Konverze jiných datových typů na řetězec +- Běžně se využívá schopnost operátoru zřetězení „+“ převádět jiné datové typy (základní datové typy a instance tříd) na řetězec + - Pro základní datové typy funguje přímočaře + - Pro objekty také – objekt se převede na řetězec implicitním voláním metody ```toString()``` + - Pokud je metoda ```toString()``` překryta, funguje dobře +- Pro pole je potřeba použít metodu třídy ```Arrays.toString(pole)``` + - Pokud se použije pouze operátor „+“, použije se implicitní textová reprezentace pole (např. ```[I@15db9742```) +- Pro základní datové typy existuje další možnost – metoda ```Typ.toString (hodnota)``` z příslušné obalovací třídy základního datového typu + - Např. ```String s = Integer.toString(42); //s bude "42"``` +- Pro základní datové typy a pro instance tříd existuje další možnost – metoda třídy ```valueOf(hodnota)``` třídy ```String``` + - Metoda je překrytá pro všechny základní datové typy a objekty + - Např. ```String s = String.valueOf(42) //s bude "42"``` + +### Rozdělení řetězce na podřetězce +- Často je potřeba **rozdělit řetězec na několik podřetězců** podle oddělovače (mezer, bílých znaků, čárek, teček, pomlček či jiné interpunkce či jiného znaku) + - Metoda instance ```split(regulárníVýraz)``` ve třídě ```String``` + - Metoda má jako parametr regulární výraz + - Regulární výraz + - Řetězec popisující celou množinu řetězců => mnohé znaky tak mají speciální význam + - Parametrem tedy není jen znak, podle kterého se má řetězec rozdělit + - Některé znaky (např. mezera) nemají speciální význam a lze je tak použít bez problémů (tj. ```split(" ")```) + - Některé znaky mají speciální význam a je třeba použít tzv. „escape“ sekvenci + - Zpětné lomítko „\“ před znak, který chceme použít => zruší se tím speciální význam znaku + - Protože však zpětné lomítko má speciální význam i v řetězcových a znakových literálech (umožňuje napsat speciální znaky, např. konec řádky „\n“), je třeba napsat zpětná lomítka + - Metoda vrací pole řetězců, délka pole záleží na počtu podřetězců dvě „\\“ + +### Proměnný řetězec +- V některých případech (ač jich není mnoho) opravdu potřebujeme, aby se při každé změně textu řetězce nevytvářela nová instance => je potřeba měnitelný (mutable) řetězec + - Pokud provádíme v řetězci mnoho změn a použili bychom třídu ```String```, **vytvářelo by se mnoho instancí** – pro každou změnu se vytvoří nová, což zbytečně zabírá paměť a zpomaluje program (vytvoření instance nějakou dobu trvá) + - Pokud by šel **řetězec měnit**, vystačíme si s jednou instancí + +#### Třída StringBuilder +- **Proměnný/měnitelný řetězec** (sekvence znaků) +- Vytvoření instance třídy ```StringBuilder``` + - Lze zadat řetězec, nebo kapacitu + - Kapacita se udává kvůli efektivitě – pokud je dostatečná, nemusí se během práce s řetězcem (při jeho prodloužení) kapacita navyšovat + - Je však možné do instance třídy ```StringBuilder``` vložit/přidat řetězec nebo jiný datový typ (viz níže) a překročit aktuální kapacitu kapacita se automaticky navýší + - Např. ```StringBuilder sb1 = new StringBuilder("Ahoj");``` + - Např. ```StringBuilder sb2 = new StringBuilder(100);``` +- Práce se znaky + - Zjištění konkrétního znaku + - Metoda ```charAt(index)``` + - Vrátí znak na zadaném indexu + - Např. ```int i = sb1.charAt(3); //'o'``` + - Nastavení konkrétného znaku + - Metoda ```setCharAt(index, znak)``` + - Nastaví znak na zadaném indexu na zadaný znak + - Např. ```sb1.setCharAt(0, 'E'); //"Ehoj"``` +- Délka řetězce + - Zjištění délky uloženého řetězce + - Metoda ```getLength()``` + - Vrátí délku řetězce + - Např. ```int d1 = sb1.getLength(); //4``` + - Např. ```int d2 = sb2.getLength(); //0``` +- Nastavení délky řetězce + - Metoda ```setLength(délka)``` + - Nastaví délku řetězce + - Pokud se řetězec prodlužuje, přidané znaky budou mít hodnotu 0 + - Pokud se řetězec zkracuje, znaky nad zadanou délku se oříznou + - Např. ```sb2.setLength(10); //10 znaků hodnoty 0``` + - Např. ```sb2.setLength(0); //Prazdny retezec``` +- Převrácení řetězce + - Metoda ```reverse()``` + - Převrátí pořadí znaků + - Např. ```sb1.reverse(); //"johE"``` +- Přidání/vložení libovolného datového typu + - Přidání libovolného datového typu + - Metoda ```append(hodnota)``` + - Metoda překryta pro všechny základní datové typy, ```Object```, ```String``` a ```StringBuilder``` + - Např. ```sb2.append(true); //"true"``` + - Např. ```sb1.append(sb2); //"johEtrue"``` + - Vložení libovolného datového typu + - Metoda ```insert(index, hodnota)``` + - Metoda překryta pro všechny základní datové typy, ```Object``` a ```String``` + - Znaky na pozici ```index``` a dále se odsunou o počet vložených znaků + - Např. ```sb1.insert(3, 42); //"joh42Etrue"``` + - Smazání podřetězce či znaku + - Smazání podřetězce + - Metoda ```delete(začátek, konec);``` + - Smaže podřetězec začínající na pozici začátek a končící před pozicí ```konec``` + - Např. ```sb1.delete(2, 5); //"joEtrue"``` + - Smazání znaku + - Metoda ```deleteCharAt(index)``` + - Smaže znak na zadaném indexu + - Např. ```sb1.deleteCharAt(2); //"jotrue"``` + +#### Třída StringBuffer +- Proměnný/měnitelný řetězec (sekvence znaků), která má téměř stejné metody a téměř stejné použití jako třída ```StringBuilder``` + - Starší a pomalejší + - Vhodný, pokud má s proměnným řetězcem pracovat více vláken (viz předmět KIV/PGS) + +### Třída Character +- Obalovací třída pro základní datový typ ```char``` +- Obsahuje mnoho konstant důležitých pro práci s různými speciálními znaky (např. z jiných abeced než latinky) +- Obsahuje mj. metody pro určení typu znaku + +#### Určení typu znaku +- Metody pro určení typu znaku třídy ```Character``` + - Jedná se o metody třídy, volají se nad názvem třídy, vrací ```true```, pokud znak je daného typu (podle názvu metody), jinak vrací ```false``` + - Metody pracují správně i pro speciální znaky (které např. nejsou z latinky) + - Metoda ```isDigit(znak)``` + - Zjistí, jestli je zadaný znak číslice + - Např. ```Character.isDigit('3'); //true``` + - Např. ```Characet.isDigit('A'); //false``` + - Metoda ```isLetter(znak)``` + - Zjistí, jestli je zadaný znak písmeno + - Např. ```Character.isLetter('3'); //false``` + - Např. ```Character.isLetter('A'); //true``` + - Metoda ```isLetterOrDigit(znak)``` + - Zjistí, jestli je zadaný znak písmeno nebo číslice + - Např. ```Character.isLetterOrDigit('3'); //true``` + - Např. ```Character.isLetterOrDigit('A'); //true``` + - Metoda ```isWhitespace(znak)``` + - Zjistí, jestli je zadaný znak bílý znak + - POZOR! – druhé „```s```“ v názvu metody je také malé + - Např. ```Character.isWhitespace(' '); //true``` + - Např. ```Character.isWhitespace('\n'); //true``` + - Metoda ```isLowerCase(znak)``` + - Zjistí, jestli je zadaný znak malé písmeno + - Např. ```Character.isLowerCase('a'); //true``` + - Např. ```Character.isLowerCase('A'); //false``` + - Např. ```Character.isLowerCase('3'); //false``` + - Metoda ```isUpperCase(znak)``` + - Zjistí, jestli je zadaný znak velké písmeno + - Např. ```Character.isUpperCase('a'); //false``` + - Např. ```Character.isUpperCase('A'); //true``` + - Např. ```Character.isUpperCase('3'); //false``` + +## Práce s parametry příkazové řádky (programu) +- Mnoho programů je možné spustit s **jedním či více parametry příkazové řádky** (též **parametry programu**) + - Např. většina programů pro práci s různými soubory (obrázky, videa, textové soubory) umožňuje zadat jako parametr soubor, který mají po spuštění otevřít + +### Zadání parametrů příkazové řádky +- Parametry se zadávají při spuštění programu **za příkaz, který program spouští** + - Parametrů může být více + - Jednotlivé parametry jsou odděleny mezerou + - ```java balík.Třída parametr1 parametr2 …``` + - Např. ```java VypisParametruProgramu -v 128``` +- Parametry s mezerou či mezerami + - Pokud je parametrem řetězec, který obsahuje jednu nebo více mezer, je nutné parametr uzavřít do uvozovek (jinak by byl chápán jako více parametrů) + - Např. ```java VypisParametruProgramu 128 "Program Files"``` + +### Předání parametrů příkazové řádky do programu +- S parametry zadanými při spuštění programu lze jednoduše pracovat +- Protože metoda ```main()``` je vstupní bod programu, jsou parametry příkazové řádky předány jako skutečný parametr této metody + - Jsou dostupné ve formálním parametru ```args``` + - Jedná se o pole řetězců + - Řetězce mohou obsahovat libovolné znaky (tedy čísla, písmena, interpunkci, bílé znaky) + - Jednotlivé parametry (řetězce) jsou v jednotlivých buňkách pole + - Délka pole odpovídá počtu parametrů + - Pokud je program spuštěn bez parametrů (tj. všechny dosud předvedené programy), je ```args``` pole délky 0 (nikoliv ```null```) + +### Zpracování parametrů příkazové řádky +- Parametry mohou mít libovolný význam, typicky se jedná o název souboru, přepínače či jiné (např. číselné) hodnoty +- Parametry jsou však vždy předány jako řetězce + - Pokud se jedná o čísla (sloužící k nějakému výpočtu), je potřeba převod z řetězce na číslo + +## Postup při návrhu algoritmu (od problému k programu) +- Pokud máme problém, který chceme vyřešit pomocí počítačového programu, je potřeba nejprve promyslet různé aspekty vytvářeného programu + - Jaký je algoritmus či algoritmy programu + - Jakým způsobem lze algoritmus realizovat a dekomponovat na menší části + - Jaké jsou potřebné datové struktury + - Jaký bude vstup a výstup programu (co má program načítat a co vypisovat) + - Jak bude program komunikovat s uživatelem (typ uživatelského rozhraní) + +### Obecný postup +- Zde je popsáno několik obecných rad, jak při vytváření (rozsáhlejšího) programu postupovat + - Nejedná se o žádnou konkrétní metodiku + - Nejedná se o dogma, které by muselo být dodržováno striktně + +#### Promyšlení jednotlivých aspektů +- Je potřeba rozmyslet všechny zmíněné aspekty o Většina z nich spolu úzce souvisí => změna rozhodnutí v jedné oblasti pravděpodobně ovlivní další oblasti + - Dělat si poznámky, schémata + - Zvláště u složitějších problémů se snadno zapomíná na již vymyšlené věci, proto je potřeba si myšlenky zaznamenávat + +#### Postup programování +- S programováním by se mělo začít, až když je rozmyšlená a navržená struktura aplikace + - Tj. na jaké třídy bude aplikace členěna a do jakých balíku budou tyto třídy umístěny +- Co naprogramovat nejdříve + - Je možno více postupů + - Častý je postup shora dolů + - Vytvoří se kostry jednotlivých (téměř všech) tříd i s hlavičkami metod + - Do těchto koster se následně postupně doplní funkcionalita (těla metod) + - Pokud budeme mít nejprve hotovou kostru většiny tříd metod (s prázdnými těly), hodí se to při následném psaní těl metod + - Těla metod mimo jiné obsahují volání jiných metod naší aplikace => pokud tyto metody existují (byť s prázdnými těly), IDE nástroj může při psaní pomoci s doplňováním jejich volání +- Průběžná kontrola funkcionality + - IDE nástroj nás upozorní na překlepy a jiné syntaktické chyby je možné vytvořit program, který půjde hned napoprvé přeložit (tj. bez chyb při překladu) + - Program však s vysokou pravděpodobností obsahuje chyby v chování programu, na které nás IDE nástroj neupozorní je potřeba ladění + - Řádné ladění je možné až po dokončení aplikace + - Ladění částí kódu (např. jednotlivých výpočtů) je však možné už v průběhu může to usnadnit ladění v závěrečné fázi, protože části kódu byly už alespoň částečně prověřeny + +#### Úpravy algoritmů a refaktoring +- Pro začátečníky ale i pro zkušené programátory není snadné zohlednit při návrhu programu všechny aspekty +- Často se na něco zapomene +- Náprava opomenutí může být drobná, ale také rozsáhlá +- Je poměrně běžné, že se v již hotovém kódu dělají úpravy + - Za účelem doplnění či změny funkcionality + - Typicky proto, že se na něco zapomnělo, nebo se objevil nový požadavek + - Např. změna algoritmů, změna formátu vstupů a výstupů + - Za účelem vylepšení zdrojového kódu (bez změny funkcionality) + - Tzv. refaktoring + - Např. změna struktury aplikace (rozdělení funkcionality do více tříd ametod), přejmenování a přesunutí tříd, rozdělení aplikace do více balíků apod. + - IDE nástroje často poskytují nástroje pro jeho usnadnění + - Např. přejmenování a přesunutí třídy +- Ve skutečnosti se málokdy stane, že původní návrh, jak by měl program vypadat, se naprogramuje 1:1 a nedojde k žádným změnám + +#### Ladění a testování +- Po dokončení programu je potřeba provést jeho ladění + - Program obsahuje chyby za běhu programu, které je potřeba odstranit + - Důležité je zkoušet program spouštět s různými typy vstupů (včetně neplatných vstupů) a ověřovat, zda dává správné výstupy + - V případě nalezení problému (program padá a/nebo dává nesprávné výsledky), je vhodné použít debugger (případně kontrolní výpisy) pro zjištění, co se v programu děje a pro nalezení a odstranění chyb + +#### Odevzdání programu +- Po dokončení testování je třeba vytvořit formu programu, která je vhodná pro odevzdání či distribuci + - Typicky spustitelný soubor JAR + - Tato forma by rovněž měla být řádně otestována + +## Řazení +- Velmi častá operace v mnoha různorodých algoritmech +- Slouží především pro usnadnění následného vyhledávání + - Používá se nejen v programování, ale i v běžném životě (často se setkáváme s abecedním pořadím, např. slova v rejstříku knihy, které usnadní nalezení požadovaného výrazu) + +### Základní pojmy +- Pro řazení se v angličtině používá slovo „sort“ + - Toto slovo má však dva odlišné významy + - Řazení – činnost, kdy přeskupíme prvky posloupnosti (nejčastěji uložené v poli) tak, aby mezi sousedními prvky platily vztahy „předchůdce-následník“ či „menší-větší“ + - Např. seřadíme pole čísel podle velikosti od nejmenšího čísla k největšímu nebo seřadíme studenty podle příjmení od A do Z + - V předmětu KIV/PPA1 a navazujících předmětech budeme důsledně používat slovo „řazení“ + - Třídění – činnost, kdy prvky z určité skupiny (množiny) rozdělujeme do podskupin podle nějaké společné vlastnosti + - Např. roztřídíme celá čísla na sudá a lichá V českém překladu se občas slovo **„třídění“ používá ve významu řazení => NEPOUŽÍVAT**! +- Klíč + - Řadit je možné prvky primitivních datových typů nebo instance + - Pokud řadíme instance, které mají obecně více atributů, pak typicky řadíme podle jednoho nebo několika z nich + - Atribut, podle kterého řadíme, se nazývá klíč +- Protože se řazení používá velmi často, existuje množství rozmanitých algoritmů, které se navzájem liší některými svými vlastnostmi, zejména svou rychlostí a složitostí implementace + +#### Vlastnosti algoritmů řazení +- Směr řazení + - Řazení vzestupně + - Předchozí prvek je menší nebo roven následujícímu prvku + - Např. 1, 2, 3, 3, 3, 4, 6, 9, 9 + - Častější směr řazení + - Řazení sestupně + - Předchozí prvek je větší nebo roven následujícímu prvku + - Např. 9, 9, 6, 4, 3, 3, 3, 2, 1 + - Pokud nebude explicitně uvedeno jinak, budeme ve zbylém textu uvažovat řazení vzestupně +- Umístění řazených prvků + - **vnitřní řazení** + - **Všechny prvky**, které chceme seřadit, **jsou uloženy v jeden okamžik v operační paměti** + - Ve zbylém textu budeme **uvažovat pouze vnitřní řazení** + - Paměti je „dost“ – lze bez problémů řadit desítky milionů prvků + - **Vnější řazení** + - Řazených prvků je **extrémní množství** a **všechny najednou se do operační paměti nevejdou** + - Prvky jsou uloženy v jednom či více souborech nebo v databázi na vnější paměti (např. na pevném disku) + - **V jeden okamžik je v operační paměti pouze část prvků** +- Stabilita + - Stabilní řazení + - **Řazení je stabilní**, **pokud relativní pořadí prvků se stejnou hodnotou klíče zůstává v seřazeném poli** (posloupnosti) **stejné jako v původním poli** (posloupnosti) + - Např. pokud budu **řadit pole osob s atributy jméno a příjmení podle příjmení**, pořadí osob se stejným příjmením zůstane zachované + - Neseřazené osoby: Jana Volná, Tomáš Marný, Petr Dobrý, Martin Marný, Lenka Malá, Jitka Volná + - Seřazené osoby: Petr Dobrý, Lenka Malá, Tomáš Marný, Martin Marný, Jana Volná, Jitka Volná + - Nestabilní řazení + - Řazení je nestabilní, pokud se relativní pořadí prvků se stejnou hodnotou klíče může po seřazení pole změnit + - Např. pokud budu řadit pole osob s atributy jméno a příjmení podle příjmení, pořadí osob se stejným příjmením nemusí zůstat zachované + - Neseřazené osoby: Jana Volná, Tomáš Marný, Petr Dobrý, Martin Marný, Lenka Malá, Jitka Volná + - Seřazené osoby: Petr Dobrý, Lenka Malá, Tomáš Marný, Martin Marný, Jitka Volná, Jana Volná + - Má význam pouze u řazení objektů + - Pokud řadíme pole základních datových typů, vzájemná poloha dvou stejných prvků není důležitá + - Protože prvky stejné hodnoty stejně nemůžeme rozlišit + - „Je jedno, která trojka bude první a která druhá“ + - Objekty se mohou shodovat v klíči, podle kterého jsme řadili, ale můžou se lišit (a často liší) v hodnotách dalších atributů + - Jejich pořadí může mít význam +- Složitost + - Vlastnost každého algoritmu (nejen algoritmu řazení) + - Dá se použít pro zhodnocení „jak rychlý“ daný algoritmus je nebo „kolik paměti“ daný algoritmus potřebuje + - Udává, jak roste časová (nebo paměťová) náročnost algoritmu v závislosti na velikosti vstupu + - V případě řadících algoritmů je velikost vstupu počet řazených prvků + - Podrobně viz předmět KIV/PPA2 + +### Základní algoritmy řazení +- U všech příkladů budeme předpokládat, že posloupnost prvků, kterou chceme seřadit, je uložená v poli + - Všechny zmíněné algoritmy procházejí pole, přičemž alespoň část pole se prochází opakovaně + - Pro průchod polem jsou využity dva vnořené cykly – typicky cykly for, nebo kombinace cyklů for a while +- Základní operace, které se provádějí v běžných algoritmech řazení, je porovnání prvků a prohození prvků + - Postupným prohazováním dvojic prvků na základě porovnání jejich hodnoty se z neseřazené posloupnosti uložené v poli stane seřazená posloupnost +- **Základní algoritmy řazení** + - Jsou **jednoduché na implementaci** (a tedy i na pochopení jejich principu) + - Všechny mají **časovou složitost Ο(n²)** + - Udává, jak roste čas potřebný pro seřazení posloupnosti prvků v závislosti na počtu prvků n (v nejhorším případě) + - Pokud bude algoritmus potřebovat čas t pro seřazení n prvků, bude pro seřazení 2n prvků potřebovat čas 4t + - Čas roste kvadraticky v závislosti na počtu prvků n +- **Pokročilé algoritmy řazení** + - Jsou složitější na implementaci a pochopení + - Mají **nižší časovou složitost (typicky Ο(nlog2n)**) + - Podrobně viz předmět KIV/PPA2 + +#### Řazení výběrem (selection sort) +- Též řazení výběrem mezního prvku, řazení s přímým výběrem +- Princip řešení + - V celém poli nalezneme index prvku s nejnižší hodnotou + - Vyměníme nalezený prvek s prvním prvkem pole (na indexu 0) + - V poli vyjma prvního prvku nalezneme index prvku s nejnižší hodnotou + - Vyměníme nalezený prvek s druhým prvkem pole (na indexu 1) + - Pokračujeme stejným způsobem pro další prvky, dokud nedosáhneme konce pole +- Vlastnosti **řazení výběrem** + - Řazení **je nestabilní** + - **Složitost Ο(n²)** + +#### Řazení vkládáním (insertion sort) +- Princip řešení + - Pole máme rozdělené na seřazenou (na začátku jeden prvek) a neseřazenou část (na začátku všechny prvky kromě prvního (na indexu 0)) + - Vezme se první prvek z neseřazené části a vloží se na správné místo do seřazené části + - Prvky v seřazené části větší než zařazovaný prvek se posunou o jedno místo doprava => seřazená část se zvětší o jeden prvek + - Opakuji, dokud není pole celé seřazené +- Vlastnosti **řazení vkládáním** + - Řazení **je stabilní** + - **Složitost Ο(n²)** + +#### Řazení záměnou (bubble sort) +- Též bublinkové řazení +- Princip řešení + - Porovnáváme vždy dva sousední prvky, začínáme odzadu + - Pokud jsou prvky v nesprávném pořadí (prvek s nižším indexem je větší), prohodíme je + - Porovnávání a prohazování opakujeme, dokud nedojdeme na začátek pole + - Tím se nejmenší prvek dostane na začátek pole („vybublá nahoru“) + - V průběhu vybublání se i ostatní prvky částečně řadí + - Celý postup opakujeme znovu, ale pouze do druhého prvku pole + - Tím vybublá nahoru druhý nejmenší prvek + - Opakujeme pro třetí nejmenší prvek, atd. + - Předčasné ukončení + - Pokud nedojde při běhu vnitřního cyklu k žádné výměně, je pole seřazené a mohu skončit +- Vlastnosti **řazení záměnou** + - Řazení **je stabilní** + - **Složitost Ο(n2)** + +#### Porovnání základních algoritmů řazení +- **Všechny** tři zmíněné algoritmy mají stejnou **složitost Ο(n²)** + - To neznamená, že jsou **všechny stejně efektivní**, pouze, že **doba řazení roste stejným tempem** (s druhou mocninou počtu řazených prvků) +- Všechny algoritmy řazení provádějí převážně **dvě základní operace** + - **Porovnání** – typicky porovnání dvou prvků + - **Přiřazení** – typicky při prohození dvou prvků (celkem tři přiřazení na jedno prohození) + - Různé řadící algoritmy provedou různý počet porovnání a přiřazení pro stejnou neseřazenou posloupnost + - Podle počtu provedených porovnání a přiřazení lze algoritmy porovnat + - Do algoritmů se přidají dva čítače + - Jeden pro počet porovnání a druhý pro počet přiřazení + - Inkrementují se „ručně“ (tj. je nutné inkrementaci ručně přidat do kódu) při každém provedeném porovnání/přiřazení +- **Základní algoritmy** řazení jsou **efektivní pro malé posloupnosti** (cca několik desítek prvků) +- Pro **větší množství prvků** se používají **algoritmy se složitostí Ο(nlog²n)**, které jsou typicky **obsažené v knihovních metodách většiny běžných programovacích jazyků** + +### Řazení pole řetězců (lexikografické řazení) +- **Řazení řetězců funguje stejně** jako řazení základních datových typů **s výjimkou porovnání** + - Pro porovnání dvou prvků nelze použít operátory „```<```“ a „```>```“ + - Je potřeba použít metodu instance třídy ```String compareTo()```, která vrací 0, kladnou či zápornou hodnotu podle pořadí porovnávaných řetězců v abecedě + - 0 – řetězce jsou stejné (včetně velikosti písmen) + - **Záporná hodnota** – řetězec, nad kterým je metoda volaná, je „menší“ než řetězec v parametru metody + - **Kladná hodnota** – řetězec, nad kterým je metoda volaná, je „větší“ než řetězec v parametru metody + - POZOR! – Kladné a záporné hodnoty jsou obecně různá kladná a záporná čísla v závislosti na obsahu řetězců – není to jen -1 a 1 + +#### Problémy s lexikografickým řazením +- Uspořádání podle abecedy však může mít neočekávané důsledky, typicky při řazení názvů souborů (což je nejčastěji podle názvu) + - Pokud seřadíme čísla ```1, 40, 10, 3, 17, 4```, očekáváme výsledek ```1, 3, 4, 10, 17, 40``` + - Pokud ale budeme řadit řetězce (názvy souborů) ```"1.txt", "40.txt", "10.txt", "3.txt", "17.txt", "4.txt"```, dostaneme výsledek ```"1.txt", "10.txt", "17.txt", "3.txt", "4.txt", "40.txt"``` + - Toto seřazení je **důsledkem porovnání řetězců** + - Běžné porovnávání řetězců implementované i v metodě ```compareTo()``` probíhá postupně podle jednotlivých znaků od začátku řetězce + - Pokud se řetězce shodují v prvním znaku, porovnají se podle druhého znaku atd. + - Jednotlivé znaky se porovnávají podle jejich hodnot + - Jakmile se narazí na znak, který není shodný, hodnota tohoto znaku určí výsledek porovnání řetězců + - Např. při porovnání řetězců ```"Jana"``` a ```"Janicka"``` rozhodnou až znaky ```'a'``` a ```'i'``` na indexu 3 protože ```'a'``` má nižší hodnotu než ```'i'```, „menší“ (tj. blíže začátku abecedy) je řetězec ```"Jana"``` + - Pokud je jeden řetězec předponou druhého, je „menší“ ten kratší řetězec (např. ```"Jan"``` je „menší“ než ```"Jana"```) + - Pokud se porovná řetězec ```"10.txt"``` a ```"3.txt"```, tak hned první znaky (na indexu 0) jsou rozdílné – ```'1'``` a ```'3'``` + - Protože ```'1'``` je menší než ```'3'```, je řetězec ```"10.txt"``` „menší“ než řetězec ```"3.txt"```, i když číslo 3 je menší než 10 + - Řešení – **doplnit nevýznamové nuly**, které jsou však z hlediska lexikografického řazení významové => místo ```"3.txt"``` použít ```"03.txt"``` + +### Řazení pole objektů +- Pole objektů lze řadit **stejnými algoritmy** jako pole základních datových typů +- **Je** ale **nutné určit**, **podle čeho se mají jednotlivé instance porovnávat** (tj. **určit, co bude klíčem**) + - Podle jednoho atributu + - Podle více atributů (víceúrovňové řazení) + +#### Řazení podle jednoho atributu +- Jediný rozdíl oproti řazení pole základních datových typů je, že porovnáváme hodnoty atributů, nikoliv samotné instance + - Pokud je atribut základního datového typu, použijeme přímo operátory porovnání „```<```“ a „```>```“ + - Pokud je atribut referenční proměnná na instanci jiné třídy, musíme použít porovnání definované pro danou třídu + - Např. pro třídu ```String``` je to metoda ```compareTo()``` + +#### Víceúrovňové řazení provedené najednou (běžný postup) +- Poměrně často se může stát, že chceme řadit pole objektů podle více atributů + - Např. osoby podle příjmení a následně podle jména + - Osoby se tedy seřadí podle příjmení, a pokud mají stejné příjmení, seřadí se ještě podle jména + - Je možné udělat v řazení komplexnější podmínku pro prohození prvků obsahující všechny atributy, podle kterých chceme řadit + - Tento postup podstatně znepřehledňuje samotné řazení, zvláště pokud je atributů, podle kterých řadíme, větší množství + - Je vhodnější udělat metodu pro porovnání dvou instancí stejné třídy, která bude vracet hodnoty indikující, která instance je „větší“ + - Tato metoda může obsahovat i poměrně složitou podmínku skládající se z porovnání několika atributů + - Díky umístění v metodě instance nebude znepřehledňovat kód řazení + - Metodu můžeme po vzoru třídy ```String``` nazvat ```compareTo()``` a může vracet hodnoty ```0```, ```1``` a ```-1``` + - Metoda ```compareTo()``` se využívá i při řazení objektů knihovní metodou řazení + - Metoda ```compareTo()``` se může využít i při řazení podle jediného atributu + +#### Víceúrovňové řazení provedené postupně (nepoužívat) +- Další možnost seřazení pole objektů podle více atributů je seřadit ho nejprve podle jednoho atributu a následně podle dalšího + - Je potřeba použít stabilní algoritmus řazení + - Nejprve se pole seřadí podle nejméně důležitého atributu (u osoby podle jména) + - Následně se pole seřadí podle více důležitého atributu (u osoby podle příjmení) + - Protože pořadí prvků se stejným klíčem zůstává při použití stabilního řazení nezměněno, seřazení podle méně důležitého atributu (jména) zůstane zachováno (pro osoby se stejným příjmením) + - Tento postup vyžaduje zopakovat řazení dvakrát a je proto rozumné ho nevyužívat, pokud není nezbytně nutno + - Pokud však není možné řadit podle více atributů najednou (např. v GUI MS Access), tento postup se může hodit + +### Metody řazení v Java Core API +- V **naprosté většině případů není důvod si programovat algoritmus řazení** – využijí se **knihovní metody pro řazení** z třídy ```Arrays``` (nebo ```Collections```) z balíku ```java.util``` +- Pro pole základních datových typů i pole objektů se používají metody ```Arrays.sort(pole)``` a ```Arrays.sort(pole, indexOd, indexDo)``` + - Metody jsou překryté pro pole všech základních datových typů a pole objektů + - Metoda s indexy řadí pouze část pole od indexu ```indexOd``` (včetně) do indexu ```indexDo``` (vyjma) + +#### Řazení polí základních datových typů metodou z Java Core API +- Řazení pole základních datových typů **nevyžaduje žádnou speciální úpravu**, **pouze se zavolá metoda řazení** +- Metody ```sort()``` pro pole základních datových typů obsahují **algoritmus quick sort** + - Je **velmi rychlý** + - Má **složitost Ο(nlog²n)** (v průměrném případě) + - **Není stabilní** – u základních datových typů nepodstatné + - Viz předmět KIV/PPA2 + +#### Řazení polí objektů metodou z Java Core API +- Aby bylo možné **řadit pole objektů** knihovními metodami řazení, **je potřeba, aby třída implementovala rozhraní** ```Comparable``` + - Mnoho knihovních tříd to dělá, a dají se tak řadit knihovními metodami – např. ```String``` + - Podrobnosti viz předměty KIV/PPA2 a KIV/OOP + - Existuje i alternativní možnost, umožňující řadit podle různých kritérií podle toho, které řazení aktuálně potřebujeme + - Je potřeba, aby třída měla rozšířenou hlavičku + - ```public class Třída implements Comparable``` + - Je potřeba, aby třída obsahovala metodu pro porovnání dvou instancí třídy + - ```public int compareTo(Třída třída)``` + - Tato metoda musí vracet zápornou hodnotu, pokud je instance, nad kterou se metoda volá, „menší“ než instance v parametru metody, kladnou hodnotu, pokud je „větší“, a nula, pokud jsou obě instance stejné + - Podle čeho se instance porovnávají, **záleží na těle metody** ```compareTo()```, může to být podle jednoho či více atributů + +### Kopie pole +- Protože při knihovním řazení metodami ```Arrays.sort()``` dojde přímo k seřazení zadaného pole, může se hodit pole před řazením zkopírovat, abychom měli uloženou seřazenou i neseřazenou posloupnost + - Pole lze překopírovat ručně + - Vytvořit nové pole stejného typu o stejné velikosti jako původní pole + - V cyklu ```for``` projít původní pole a do prvků nového pole přiřadit odpovídající prvky původního pole + - **Pole lze překopírovat využitím knihovní metody** ```Arrays.copyOf(pole, nováDélkaPole)``` + - **Metoda je rychlejší** než ruční kopírování + - Metoda umožňuje **pole** také **zkrátit** nebo **prodloužit** (**při zadání jiné délky** než původní délky pole) + - Při zadání **menší délky** se **pole ořízne** + - Při zadání **větší délky** se **prvky navíc nastaví na hodnotu** ```0, 0.0, false``` nebo ```null``` **podle typu pole** + +#### Kopie polí základních datových typů +- Při kopírování polí základních datových typů, kdy jednotlivé hodnoty jsou přímo prvky pole, dostaneme „plnohodnotnou“ kopii pole + - Pokud provedeme změnu prvku v kopii pole, změna se nijak neprojeví v původním poli + +#### Kopie polí objektů +- Při **kopírování polí objektů** jsou v prvcích pole uloženy **pouze reference na jednotlivé instance** + - Zkopírováním pole se **zkopírují pouze reference**, které ale **stále ukazují na původní instance** + - Pokud provedu změnu atributu prvku v kopii pole, projeví se tato změna i v odpovídajícím prvku původního pole (protože se stále jedná o stejnou instanci) + - Jedná o tzv. **mělkou kopii pole** + +## Vyhledávání +- Vyhledávání je velmi často prováděná činnost +- **Zjišťujeme**, **zda je prvek určité hodnoty** (též prvek s hodnotou klíče) **přítomen v poli** + - Někdy stačí informace, zda je či není (```true```/```false```) + - Většinou je potřeba zjistit index, na kterém se hledaný prvek nachází +- Typ vyhledávání + - **Neúplné** + - Nalezneme **první výskyt** prvku + - **Úplné** + - Nalezneme **všechny výskyty** prvku +- Výsledek neúplného vyhledávání + - Typicky první index od začátku pole, na kterém se prvek nachází (prvek může být v poli obsažen vícekrát), nebo záporná hodnota, pokud se prvek v poli nenachází (typické použití, protože index prvku nemůže být záporný) + - Pokud je důležité pouze, zda prvek v poli je či není, ale není důležité kde je, je výsledek vyhledávání pouze ```true``` (prvek je obsažen) nebo ```false``` (prvek není obsažen) +- Výsledek úplného vyhledávání + - Pole (případně výpis) všech indexů, na kterých se hledaný prvek nachází, nebo prázdné pole, pokud prvek není v poli obsažen + - Pokud není důležité, na kterých indexech se prvek nachází, ale zajímá nás, kolikrát je v poli obsažen, výsledkem je počet výskytů prvku (0 pokud prvek není obsažen) + +### Vyhledávání v neseřazené posloupnosti (poli) +- Pokud není pole, ve kterém prvek hledáme, seřazené, je jediná možnost sekvenční vyhledávání + +#### Neúplné sekvenční vyhledávání v poli základních datových typů +- Neúplné sekvenční vyhledávání má **složitost Ο(n)** + - V **nejhorším případě je nutné projít celé pole**, tedy všech n prvků +- Princip vyhledávání + - Procházíme pole od začátku do konce a porovnáváme hodnoty prvků pole s hodnotou hledaného prvku + - Když prvek nalezneme, ukončíme procházení pole a vrátíme index, na kterém jsme prvek nalezli + - Pokud dojdeme až do konce pole a prvek nenajdeme, vrátíme zápornou hodnotu (typicky ```-1```) + +#### Neúplné sekvenční vyhledávání v poli objektů +- Vyhledávání v poli objektů je velice podobné, jako vyhledávání v poli základních datových typů + - Pro porovnání ale **nemůžeme použít operátor** „```==```“, protože pro objekty vrací true pouze v případě, že se jedná o stejnou instanci + - Můžeme **porovnávat přímo jeden či více atributů instance** + - Můžeme **využít metodu** ```equals()```, **pokud je** v dané třídě **správně implementovaná** + +#### Úplné sekvenční vyhledávání +- Úplné sekvenční vyhledávání má **složitost Ο(n)** + - V každém případě **je nutné projít celé pole**, tedy všech n prvků +- Princip vyhledávání + - **Princip** je **stejný jako u neúplného sekvenčního vyhledávání**, pouze **neukončíme procházení pole při nalezení prvního výskytu** prvku, ale projdeme pole **vždy až do konce** + - Protože indexů s pozicemi prvků je více, nestačí vrátit jeden index místo jednoho indexu **vrátíme pole s jednotlivými indexy** + - Délka pole indexů může být maximálně stejná, jako je počet prvků prohledávaného pole a minimálně může být 0, pokud hledaný prvek nebyl v poli nalezen + - Počet výskytů hledaného prvku v poli (a tedy délku pole indexů) na začátku neznáme + - Délku pole indexů tedy volíme jako délku prohledávaného pole + - Délku můžeme po skončení algoritmu zkrátit vytvořením kratší kopie pole na skutečný počet indexů + +### Vyhledávání v seřazené posloupnosti (poli) +- **Pokud je posloupnost seřazená** (předpokládáme vzestupně, ale mohla by být i sestupně), je možné **použít vyhledávání půlením intervalů** (též binární vyhledávání) + - Sekvenční vyhledávání je možné použít také, stejně jako na neseřazenou posloupnost, ale je podstatně pomalejší, takže není důvod ho používat, pokud je posloupnost seřazená + - Pokud provádíme vyhledávání opakovaně a pořadí prvků v prohledávaném poli není důležité, vyplatí se pole jednou seřadit a následně opakovaně používat vyhledávání půlením intervalů + +#### Neúplné vyhledávání půlením intervalů v poli základních datových typů +- Neúplné vyhledávání půlením intervalů (binární vyhledávání) má **složitost Ο(log₂n)** + - Čas vyhledávání tedy roste pouze s logaritmem počtu prvků prohledávaného pole pro **velký počet prvků** prohledávaného pole je **podstatně rychlejší než sekvenční vyhledávání** +- Princip vyhledávání + - V každém kroku rozdělíme prohledávaný interval na dvě poloviny a následně hledáme jen v jedné z polovin + - Zjistíme hodnotu prvku ležícího na prostředním indexu + - Pokud je rovna hledané hodnotě, algoritmus končí + - Pokud je větší než hledaná hodnota, hledáme v levé polovině + - Pokud je menší než hledaná hodnota, hledáme v pravé polovině + +#### Úplné vyhledávání půlením intervalů +- Pokud je hledaný prvek v poli obsažen vícekrát, vyhledávání půlením intervalů najde jeden z výskytů, ale není jasné, který výskyt to je + - Nalevo i napravo od nalezeného indexu se mohou vyskytovat prvky se stejnou hodnotou + - Pro úplné vyhledávání je potřeba sekvenčně prohledat pravé i levé okolí nalezeného indexu, dokud se nenarazí na jiný prvek nebo konec či začátek pole + - Protože stejné prvky jsou v seřazeném poli vždy u sebe, není třeba vracet pole všech indexů, na kterých se hledaný prvek nachází, stačí vrátit první a poslední index + +#### Metody pro vyhledávání půlením intervalů z Java Core API +- Třída ```Arrays``` obsahuje metody pro vyhledávání půlením intervalů + - Metoda ```Arrays.binarySearch(pole, klíč)``` + - Prohledává celé pole + - Metoda ```Arrays.binarySearch(pole, od, do, klíč)``` + - Prohledává pouze část pole udanou indexy ```od``` (včetně) a ```do``` (vyjma) + - Metody jsou překryté pro pole všech základních datových typů a pro pole objektů + - Prohledávané pole musí být seřazené, typicky vzestupně (typicky knihovní metodou ```Arrays.sort()```) + - Metoda vrací index nalezeného prvku, nebo zápornou hodnotu, pokud prvek nebyl nalezen + - Tato hodnota obecně není ```-1``` nutno testovat hodnotu, zda je menší než ```0```, nikoliv rovna ```-1``` + - Absolutní hodnota záporného čísla udává index, na kterém by prvek byl, kdyby v poli byl + +#### Vyhledávání půlením intervalů v poli objektů +- Pokud bychom chtěli použít binární vyhledávání v poli objektů, je nutné určit, podle čeho se mají objekty porovnávat (podle jakého atributu) + - Je nutné seřadit pole podle tohoto vybraného porovnání a stejné porovnání použít i v algoritmu binárního vyhledávání + - Nejrozumnější je použít metodu ```compareTo()```, kterou jsme použili při ručním i knihovním řazení +- Pro správné použití knihovní metody ```Arrays.binarySearch()``` je nezbytné, aby třída, jejíž instance jsou v poli, implementovala rozhraní ```Comparable``` + - Hlavička třídy, jejíž instance jsou v prohledávaném poli, musí být ```public Třída implements Comparable``` + - Musí obsahovat metodu ```public int compareTo(Třída třída)``` + - Podrobnosti viz předměty KIV/PPA2 a KIV/OOP \ No newline at end of file