Hledáme pomocníky pro kurzy programování - pohodová brigáda. Více info
Nauč se s námi víc. Využij 50% zdarma na e-learningové kurzy. Zároveň pouze tento týden sleva až 80 % na e-learning týkající se Javy
discount week 50

7. diel - Poľa v Jave

V predchádzajúcom cvičení, Riešené úlohy k 6. lekcii Javy, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V minulej lekcii, Riešené úlohy k 6. lekcii Javy , sme si v našom Java seriáli ukázali cykly. Dnes si v tutoriálu predstavíme dátovú štruktúru poľa a vyskúšame si, čo všetko vie.

Poľa

Predstavte si, že si chcete uložiť nejaké údaje o viac prvkoch. Napr. chcete v pamäti uchovávať 10 čísel, políčka šachovnice alebo mena 50tich užívateľov. Asi vám dôjde, že v programovaní bude nejaká lepšia cesta, než začať búšiť premenné uzivatel1, uzivatel2... až uzivatel50. Nehľadiac na to, že ich môže byť potrebné 1000. A ako by sa v tom potom hľadalo? Brrr, takto nie :)

Ak potrebujeme uchovávať väčšie množstvo premenných rovnakého typu, tento problém nám rieši poľa. Môžeme si ho predstaviť ako rad priehradiek, kde v každej máme uložený jeden prvok. Priehradky sú očíslované tzv. Indexy, prvý má index 0.

štruktúra poľa

(Na obrázku je vidieť pole ôsmich čísiel)

Programovacie jazyky sa veľmi líšia v tom, ako s poľom pracujú. V niektorých jazykoch (najmä starších, kompilovaných) nebolo možné za behu programu vytvoriť pole s dynamickou veľkosťou (napr. Mu dať veľkosť podľa nejaké premenné). Pole sa muselo deklarovať s konštantnou veľkosťou priamo v zdrojovom kóde. Toto sa obchádzalo tzv. Pointer a vlastnými dátovými štruktúrami, čo často viedlo k chybám pri manuálnej správe pamäte a nestabilite programu (napr. V C ++). Naopak niektoré interpretované jazyky umožňujú nielen deklarovať pole s ľubovoľnou veľkosťou, ale dokonca túto veľkosť na už existujúcom poli meniť (napr. PHP). My vieme, že Java je virtuálny stroj, teda čosi medzi kompilerem a interpretom. Preto môžeme pole založiť s veľkosťou, ktorú dynamicky zadáme až za behu programu, ale veľkosť existujúceho poľa modifikovať nemôžeme. Možno to samozrejme obísť alebo použiť iné dátové štruktúry, ale k tomu sa dostaneme.

Možno vás napadá, prečo sa tu zaoberáme s poľom, keď má evidentne veľa obmedzení a existujú lepšie dátové štruktúry. Odpoveď je prostá: poľa je totiž jednoduché. Nemyslím pre nás na pochopenie (to tiež), ale najmä pre Javu. Rýchlo sa s ním pracuje, pretože prvky sú v pamäti jednoducho uložené za sebou, zaberajú všetky rovnako miesta a rýchlo sa k nim pristupuje. Mnoho vnútorných funkčnosťou v Jave preto nejako pracuje s poľom alebo poľa vracia. Je to kľúčová štruktúra.

Pre hromadnú manipuláciu s prvkami poľa sa používajú cykly.

Pole deklarujeme pomocou hranatých zátvoriek:

int[] pole;

Slovo pole je samozrejme názov našej premennej. Teraz sme však len deklarovali, že v premennej bude pole prvkov typu int. Teraz ho musíme založiť, aby sme ho mohli používať. Použijeme na to kľúčové slovo new, ktoré zatiaľ nebudeme vysvetľovať. Uspokojme sa s tým, že je to kvôli tomu, že je pole referenčná dátový typ (môžeme chápať ako zložitejšie typ):

int[] pole = new int[10];

Teraz máme v premennej pole poľa veľkosti desiatich čísel typu int.

Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

K prvkom poľa potom pristupujeme cez hranatú zátvorku, poďme na prvý index (teda index 0) uložiť číslo 1.

int[] pole = new int[10];
pole[0] = 1;

Plniť pole takhle ručne by bolo príliš pracné, použijeme cyklus a naplníme si pole číslami od 1 do 10. K naplneniu použijeme for cyklus:

int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++) {
    pole[i] = i + 1;
}

Aby sme pole vypísali, môžeme za predchádzajúci kód pripísať:

for (int i = 0; i < pole.length; i++) {
    System.out.print(pole[i] + " ");
}

Všimnite si, že pole má konštantu length, kde je uložená jeho dĺžka, teda počet prvkov. Rovnako tak môžeme použiť metódu size(), ktorá vráti rovnaký výsledok.

Konzolová aplikácia
1 2 3 4 5 6 7 8 9 10

Môžeme použiť zjednodušenú verziu cyklu pre prácu s kolekciami, známu ako foreach. Ten prejde všetky prvky v poli a jeho dĺžku si zistí sám. Jeho syntax je nasledujúca:

for (datovytyp premenna : kolekcia) {
    // príkazy
}

Cyklus prejde prvky v kolekcii (to je všeobecný názov pre štruktúry, ktoré obsahujú viac prvkov, u nás to bude údaj) postupne od prvého do posledného. Prvok máme v každej iterácii cyklu uložený v danej premennej.

Prepíšme teda náš doterajší program pre foreach. Foreach nemá riadiace premennú, nie je teda vhodný pre vytvorenie nášho poľa a použijeme ho len pre výpis.

int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++) {
    pole[i] = i + 1;
}
for (int i : pole) {
    System.out.print(i + " ");
}

Výstup programu:

Konzolová aplikácia
1 2 3 4 5 6 7 8 9 10

Pole samozrejme môžeme naplniť ručne a to aj bez toho, aby sme dosadzovali postupne do každého indexu. Použijeme na to zložených zátvoriek a prvky oddeľujeme čiarkou:

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};

Pole často slúži na ukladanie medzivýsledkov, ktoré sa potom ďalej v programe používajú. Keď niečo potrebujeme 10x, tak to nebudeme 10x počítať, ale spočítame to raz a uložíme do poľa, odtiaľ potom výsledok len načítame.

Metódy na triede Arrays

Java nám poskytuje triedu Arrays, ktorá obsahuje pomocné metódy pre prácu s poľami.

K jej použitie je potrebné ju naimportovať:

import java.util.Arrays;

Poďme sa na ne pozrieť:

Sort ()

Ako už názov napovedá, metóda nám poľa zoradí. Jej jediný parameter je pole, ktoré chceme zoradiť. Je dokonca tak múdra, že pracuje podľa toho, čo máme v poli uložené. String y triedi podľa abecedy, čísla podľa veľkosti. Skúsme si zoradiť a vypísať našu rodinku Simpson:

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Arrays.sort(simpsonovi);
for (String s : simpsonovi) {
    System.out.print(s + " ");
}

Konzolová aplikácia
Bart Homer Lisa Maggie Marge

Skúste si urobiť polia čísel a vyskúšajte si, že to naozaj funguje aj pre nich.

BinarySearch ()

Keď pole zoradíme, umožní nám v ňom Java vyhľadávať prvky. Metóda binarySearch() nám vráti index prvého nájdeného prvku. V prípade nenájdenia prvku vráti -1. Metóda berie dva parametre, prvým je pole, druhým hľadaný prvok. Umožníme užívateľovi zadať meno Simpsons a potom skontrolujeme, či je to naozaj Simpson. Pole musí byť naozaj zotriedené, než metódu zavoláme!

Scanner sc = new Scanner(System.in, "Windows-1250");

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
System.out.println("Zadaj Simpsnovi (z rodiny Simpson): ");
String simpson = sc.nextLine();

Arrays.sort(simpsonovi);
int pozice = Arrays.binarySearch(simpsonovi, simpson);
if (pozice >= 0)
        System.out.println("Jo, to je Simpson!");
else
        System.out.println("Hele, toto nie je Simpson!");

Konzolová aplikácia
Zadaj Simpsnovi (z rodiny Simpson):
Homer
Jo, to je Simpson!

CopyOfRange ()

Metóda copyOfRange() už podľa názvu skopíruje časť poľa do iného poľa. Prvým parametrom je zdrojové pole, druhým štartovej pozície a tretím konečná pozícia. Metóda vracia nové pole, ktoré je výsekom pôvodného poľa.

Premenná dĺžka poľa

Hovorili sme si, že dĺžku poľa môžeme definovať aj za behu programu, poďme si to skúsiť:

Scanner sc = new Scanner(System.in, "Windows-1250");

System.out.println("Ahoj, spočítám ti priemer známok. Koľko známok zadáš?");
int pocet = Integer.parseInt(sc.nextLine());
int[] cisla = new int[pocet];
for (int i = 0; i < pocet; i++) {
        System.out.printf("Zadajte %d. číslo: ", i + 1);
        cisla[i] = Integer.parseInt(sc.nextLine());
}
// spočítanie priemeru
int soucet = 0;
for (int i: cisla) {
        soucet += i;
}
float prumer = soucet / (float)cisla.length;

System.out.printf("Priemer tvojich známok je: %f", prumer);

Konzolová aplikácia
Ahoj, spočítám ti priemer známok. Koľko známok zadáš?
5
Zadajte 1. číslo: 1
Zadajte 2. číslo: 2
Zadajte 3. číslo: 2
Zadajte 4. číslo: 3
Zadajte 5. číslo: 5
Priemer tvojich známok je: 2.6

Tento príklad by išiel samozrejme napísať aj bez použitia poľa, ale čo keby sme chceli spočítať napr. Medián? Alebo napr. Vypísať zadané čísla pospiatky? To už by bez poľa nešlo. Takto máme k dispozícii v poli pôvodnej hodnoty a môžeme s nimi neobmedzene a jednoducho pracovať.

U výpočtu priemeru si všimnite, že pri delení je pred jedným operandom napísané (float), tým hovoríme, že chceme deliť neceločíselné. Iste si spomínate, že pri zadávaní čísel pri delení sme pri 3 / 2 dostali výsledok 1 a pri 3 / 2.0F dostali výsledok 1.5. Tu je princíp rovnaký.

To by pre dnešok stačilo, môžete si s poľom hrať. V budúcej lekcii, Riešené úlohy k 7. lekcii Javy , na vás čaká prekvapenie ;-)

V nasledujúcom cvičení, Riešené úlohy k 7. lekcii Javy, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 993x (12.31 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java

 

Predchádzajúci článok
Riešené úlohy k 6. lekcii Javy
Všetky články v sekcii
Základné konštrukcie jazyka Java
Článok pre vás napísal David Čápka
Avatar
Ako sa ti páči článok?
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity

 

 

Komentáre

Avatar
Alesh
Překladatel
Avatar
Alesh:30. júla 10:11

ASCII tabulka je pole znaků, na indexu 97 je hodnota 'a'.

ascii[97] = 'a';
 
Odpovedať
30. júla 10:11
Avatar
Robert Vyskup:9. augusta 15:22

Absolutně nechápu, kde mám problém u té proměnné délky pole, mám to napsané vpodstatě stejně:

Scanner sc = new Scanner(System.in, "Windows-1250");
        System.out.println("Ahoj, spočítám ti průměr známek. Kolik známek zadáš?");
        int pocet = Integer.parseInt(sc.nextLine());
        int[] znamky = new int[pocet]; //převedení počtu známek na pole prvků
        for(int i = 0; i < pocet; i++) { //projedeme celé pole
            System.out.printf("Zadejte %d. číslo: ", i + 1); //vytiskneme jednotlivé indexy pro daný prvek, musíme přičíst jedna, abychom nezačínali od nuly
            znamky[i] = Integer.parseInt(sc.nextLine()); //číslo jednotlivého prvku(známky) hodíme do pole
        }
        int soucet = 0; //součet musí být ustanoven před cyklem, v cyklu ho už ustanovit nejde
        for(int i : znamky) { //vybereme jedntlivé známky z pole
            soucet += i; //a sečteme je
        }
        float prumer = soucet / (float)znamky.length; //uděláme průměr, musí zde být změna z int na float u pole znamky
        System.out.printf("Průměr tvých známek je: %f", prumer);

Zobrazí to první větu, já zadám počet známek a nic. Program běží a nic. Předtím jsem ten file i se souborem přejmenovával, ale toto je už úplně nový file i soubor a pořád to samé. Hodí mi to hlášku Unexpected Exception. Pak se běh programu zastaví a zobrazí se toto hlášení:

Exception in thread "main" java.lang.NumberFormatException: For input string: ""
        at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
        at java.base/java.lang.Integer.parseInt(Integer.java:670)
        at java.base/java.lang.Integer.parseInt(Integer.java:778)
        at cz.itnetwork.prumero.prumero.main(prumero.java:18)
Zadejte 1. číslo: [ERROR] Command execution failed.
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
    at org.apache.commons.exec.DefaultExecutor.executeInternal (DefaultExecutor.java:404)
    at org.apache.commons.exec.DefaultExecutor.execute (DefaultExecutor.java:166)
    at org.codehaus.mojo.exec.ExecMojo.executeCommandLine (ExecMojo.java:982)
    at org.codehaus.mojo.exec.ExecMojo.executeCommandLine (ExecMojo.java:929)
    at org.codehaus.mojo.exec.ExecMojo.execute (ExecMojo.java:457)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:78)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:567)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.0.0:exec (default-cli) on project prumero: Command execution failed.: Process exited with an error: 1 (Exit value: 1) -> [Help 1]

To see the full stack trace of the errors, re-run Maven with the -e switch.
Re-run Maven using the -X switch to enable full debug logging.

For more information about the errors and possible solutions, please read the following articles:
[Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
 
Odpovedať
9. augusta 15:22
Avatar
Robert Vyskup:9. augusta 19:02

Tak nic omlouvám se vyřešeno tam mi jenom u

System.out.printf("Zadejte %d. číslo: ", i + 1);

chybělo před druhýma uvozovkama \n
Což tu také není v originále, a nováčka jako jsem já to může řádně potrápit. Na druhou stranu si už to celé řešení budu pamatovat až nadosmrti.

 
Odpovedať
9. augusta 19:02
Avatar
Robert Vyskup:22. augusta 18:10

Může mi někdo vysvětlit jak přesně funguje binarySearch() spolu s Arrays.sort(). Vezněme si ten příklad Simpsonových. Když to pole neseřadím pomocí Arrays.sort tak když zadám Bart, tak to Barta najde a vypíše: "Jo, to je Simpson!", když však zadám Homer, tak ho to nenajde a vypíše to "Hele, tohle není Simpson!" Pak když pole seřadím tak to najde oba. Co se tam přesně děje.

 
Odpovedať
22. augusta 18:10
Avatar
Atrament
Super redaktor
Avatar
Odpovedá na Robert Vyskup
Atrament:22. augusta 18:52

Je to kvůli tomu jak funguje binary search - více zde

 
Odpovedať
22. augusta 18:52
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
Odpovedá na Atrament
Robert Vyskup:22. augusta 19:49

Chápu, že to najde Barta v tom nesetříděném poli, protože je přesně uprostřed. A pak to najde Lisu a Maggie, jelikož to začne hledat v té druhé půlce, když je nenajde přesně uprostřed. Co se změní v případě, kdy to setřídím pomocí Arrays.sort()? Vždyť pak je přece Bart první abecedně a Homer druhý a stejně je to najde. Co se tam změní, že je to po setřídění najde?

 
Odpovedať
22. augusta 19:49
Avatar
Atrament
Super redaktor
Avatar
Odpovedá na Robert Vyskup
Atrament:22. augusta 20:10

Změní se to, že po Arrays.sort() je to pole setřízené takže Homer bude na 'správné' straně když se v rámci binary search podíváš na prostřední prvek a porovnáš ho s Homerem - u nesetřízeného pole, tak jak je v ukázce v lekci koukne na prostředek, najde Barta a ten je v abecedě před Homerem, tak usoudí že Homer musí být někde napravo od něj, zahodí všechno nalevo od Bárta a pokračuje v hledání napravo, kde ale Homer ve skutečnosti není, protože to pole nebylo setřízené. Proto ho nikdy nenajde. Proto je nutné to pole nejprve setřídit, aby to vůbec mohlo fungovat.

 
Odpovedať
22. augusta 20:10
Avatar
Odpovedá na Robert Vyskup
Jakub Žitný:9. septembra 13:05

Díky moc! Po hodině hledání problému jsi mě zachránil před pořádným vztekáním :D

 
Odpovedať
9. septembra 13:05
Avatar
Tomáš Rosprim:18. septembra 16:56

Nerozumím chybě v syntaxi, která je i zde v uvedeném příkladu známek, konkrétně toto:
System.out.prin­tf("Zadejte %d. číslo: ", i + 1);

Při vpisování známek se mi neobjeví požadovaná hláška, až když vyplním počet n známek(délka pole), vypíše mi to všechny hlášky s číslem n + průměr do jednoho řádku.
Moje řešení je: System.out.prin­tln("Zadejte " + (i+1) + ". číslo: ");

Byl bych rád, kdyby mi někdo objasnil, proč to nefunguje? Používám NetBeans, může to být způobeno tím? Díky!

 
Odpovedať
18. septembra 16:56
Avatar
Odpovedá na Tomáš Rosprim
Tomáš Rosprim:18. septembra 17:05

Zajímavé, takže je to způsobeno pouze chybějícím odřádkováním ...
Správná syntaxe je:

System.out.prin­tf("Zadejte %d. číslo: \n", i + 1);

 
Odpovedať
18. septembra 17:05
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!