Osah 5. přednášky: Pole - motivace Deklarace, vytvoření, inicializace pole Mechanismus vytváření pole, reference Pole jako parametr či návratová hodnota Změna pole daného parametrem Kopie polí Pole reprezentující množinu Vícerozměrná pole, matice Dynamické rozšiřování pole Tato tematika je zpracována v Záznamy přednášek: str. 91-110 Prolém: Proveďte jednoduchou analýzu zadaného textu (četnost výskytu písmen). Zadání a nástin řešení ude uveden na konci přednášky. Přednášky KIV/PPA1, A. Netrvalová, 2011 5. přednáška
Pole - motivace Úkol zjistit četnost číslic v jednořádkovém textu. int nula = 0; int jedna = 0; int dva = 0;... int osm = 0; int devet = 0; Řešení pomocí přepínače = zdlouhavé, otížná modifikace, např. pro písmena,... NE!!! String text = sc.nextline(); int i=0; while(i<text.length()){ char znak = text.charat(i); if(znak >= '0' && znak <= '9'){ switch (znak){ case '0': nula++; reak; case '1': jedna++; reak; case '2': dva++; reak;... case '8': osm++; reak; case '9': devet++; reak; default: reak; i++; System.out.println("0: " + nula); System.out.println("1: " + jedna); System.out.println("2: " + dva);... System.out.println("8: " + osm); System.out.println("9: " + devet); d123y 662098 0: 1 1: 1 2: 2 3: 1 4: 0 5: 0 6: 2 7: 0 8: 1 9: 1 Strana 2 (celkem 20)
Pole - terminologie - strukturovaný datový typ - pevné délky (počet prvků, dán při vzniku) - prvky (položky) pole - typ: liovolný, ale pro všechny prvky stejný typ (homogenní datová struktura) - index: přístup k prvkům, typicky int (0 počet-1) Deklarace, vytvoření, inicializace Deklarace datovytyp[] jmenopole; Příklad: int [] mepole; Vytvoření (v Javě se s polem pracuje jako s ojektem) jmenopole = new datovytyp [velikostpole]; Příklad: tyden = new int [7]; Deklarace a vytvoření současně: datovytyp[] jmenopole = new datovytyp [velikostpole]; Příklad: doule [] teplota = new doule [5]; Inicializace Užitím cyklu: for (int i = 0; i < teplota.length; i++) teplota[i] = 37 + (doule)i/10; Výčtem hodnot: proměnná udávající počet prvků pole doule [] teplota = {37.0, 37.1, 37.2, 37.3, 37.4; Strana 3 (celkem 20)
Mechanismus vytváření pole, reference Deklarace má tento efekt: int [ ] a = new int[3]; lokální proměnné a se přidělí paměťové místo v zásoníku, které však neosahuje prvky pole, ale je dimenzováno na uložení čísla reprezentujícího adresu jiného paměťového místa operátorem new se v jiné paměťové olasti rezervuje (alokuje) úsek potřený pro pole 3 prvků typu int adresa tohoto úseku se uloží do a, při grafickém znázornění reprezentace v paměti místo adres kreslíme šipky Poznámka: reprezentace pole je zjednodušená, chyí ještě počet prvků. Pozor: referenční proměnnou lze deklarovat i ez vytvoření pole int [ ] ; V tom případě se zavede referenční proměnná, která má nedefinovanou hodnotu, jde-li o lokální proměnnou, neo speciální hodnotu null, která neukazuje nikam, jde-li o statickou proměnnou. Strana 4 (celkem 20)
Lze přiřadit jedné referenční proměnné pole jinou referenční proměnnou pole, ale tato pole musí ýt stejného typu Po přiřazení pak oě proměnné referencují totéž pole! int[] x = new int [3]; Příklad: int[] y = x; y[1] = -6; -6 System.out.println(x[1]); Poznámka: Přiřazení mezi dvěma poli není v Javě definováno, je řešeno prostřednictvím kopie pole (viz dále). Nyní můžeme použít pole pro již dříve uvedený příklad na výpočet četnosti číslic. Strana 5 (celkem 20)
import java.util.*; pulic class CetnostCislicPole { static private Scanner sc = new Scanner(System.in); pulic static void main(string[] args) { int cetnost [] = new int[10]; String s = sc.nextline(); int k=0; while(k<s.length()) { char znak = s.charat(k++); if(znak >= '0' && znak <= '9'){ cetnost[(znak - (int)'0')]++; for (int i=0; i<cetnost.length; i++) { System.out.println(i + ": " + cetnost[i]); Poznámka: příkaz for each přístup postupně ke všem prvkům pulic class ForEach { pulic static void main(string[] args) { pulic class ForEach { pulic static void main(string[] args) { int pole [] [] = = {1,2,3,4,5; int int soucet soucet = = 0; 0; for(int i :pole) { for(int i :pole) { soucet += i; soucet += i; System.out.println("soucet = " + soucet); 110w2 t3383g476 0: 1 1: 2 2: 1 3: 3 4: 1 5: 0 6: 1 7: 1 8: 1 9: 0 System.out.println("soucet = " + soucet); soucet = 15 soucet = 15 Strana 6 (celkem 20)
Pole - parametr či návratová hodnota Reference pole může ýt parametrem metody (metoda vypispole()) či návratovou hodnotou (metoda nactipole()) - viz následující příklad. import java.util.*; pulic class PoleParametrANavrat { static private Scanner sc = new Scanner(System.in); static int [] nactipole(int pocet, Scanner sc){ //zde int[] pole = new int [pocet]; for(int i=0; i<pole.length; i++){ System.out.print("Zadej a[" + i + "]: "); pole[i] = sc.nextint(); return pole; static int [] vynulujpole(int [] pole){ // zmena pole for(int i=0; i<pole.length; i++){ pole[i] = 0; return pole; static void vypispole(string s, int [] pole){ //zde for(int i=0; i<pole.length; i++){ System.out.println(s + "[" + i + "] = " + pole[i]);... pokračování na dalším slajdu Strana 7 (celkem 20)
pulic static void main(string[] args) { System.out.print("Zadej pocet prvku: "); int pocetprvku = sc.nextint(); int a [] = new int [pocetprvku]; a = nactipole(pocetprvku, sc); vypispole("a" + a); System.out.println(Arrays.toString(a)); vynulujpole(a); vypispole("a" + a); System.out.println(Arrays.toString(a)); // vypis pole a najednou //System.out.println(Arrays.toString(a)); Změna pole daného parametrem V metodě vynulujpole() jsme nevytvořili nové pole, ale vynulovali pole dané parametrem. Proč to funguje? Protože metoda vynulujpole() dostala referenci na stejné pole, na které ukazuje proměnná a. Kopie polí Zadej pocet prvku: 3 Zadej a[0]: 1 Zadej a[1]: 2 Zadej a[2]: 3 a[0] = 1 a[1] = 2 a[2] = 3 [1, 2, 3] a[0] = 0 a[1] = 0 a[2] = 0 [0, 0, 0] - použitím cyklu - metodou třídy System arraycopy(zdroj, odzdroj, kopie, odkopie, length); Strana 8 (celkem 20)
Příklad: různé způsoy kopie pole - pole prvni je prekopirováno do pole druhe - do pole treti od indexu 0 jsou nakopírovány 2 prvky pole prvni od indexu 2 import java.util.*; pulic class KopiePoli{ pulic static void main(string [] args){ int[] prvni = {2, 3, 1, 5, 10; int[] druhe = new int[prvni.length]; int[] treti = new int[3]; System.out.println("prvni:" + Arrays.toString(prvni)); System.out.println("druhe:" + Arrays.toString(druhe)); System.out.println("Kopirovani"); for (int i = 0; i < prvni.length; i++){ druhe[i] = prvni[i]; System.arraycopy(prvni, 2, treti, 0, 2); System.out.println("prvni:" + Arrays.toString(prvni)); System.out.println("druhe:" + Arrays.toString(druhe)); System.out.println("treti:" + Arrays.toString(treti)); prvni:[2, 3, 1, 5, 10] druhe:[0, 0, 0, 0, 0] Kopirovani prvni:[2, 3, 1, 5, 10] druhe:[2, 3, 1, 5, 10] treti:[1, 5, 0] Strana 9 (celkem 20)
Pole reprezentující množinu - pole typu oolean, je-li prvek součástí množiny, má hodnotu true, není-li součástí má hodnotu false Úloha: vypsat všechna prvočísla menší neo rovna zadanému max Prvočíslo - přirozené číslo, které je eze zytku dělitelné právě dvěma různými přirozenými čísly, a to číslem jedna a seou samým (tedy 1 není prvočíslo) 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,... Čínský algoritmus je číslo prvočíslem? Zjisti, zda N je dělitelem čísla 2 N -2: je-li, N je prvočíslo není-li, N není prvočíslo (funguje pro množinu přípustných dat: 340) Eratosthenovo síto - jednoduchý algoritmus pro nalezení všech prvočísel menších než zadaná horní mez - pojmenování po řeckém matematikovi Eratosthenovi z Kyrény (276 194 př.n.l.) Strana 10 (celkem 20)
Eratosthenovo síto Algoritmus: Vytvoříme množinu osahující přirozená čísla od čísla 2 do max. Z množiny vypustíme všechny násoky čísla 2. Najdeme nejližší číslo k tomu, jehož násoky jsme v předchozím kroku vypustili, a vypustíme všechny násoky tohoto čísla. Opakujeme předchozí krok tak dlouho, dokud číslo, jehož násoky jsme vypustili, není větší než max. Čísla, která v množině zůstanou, jsou hledaná prvočísla. Časová složitost algoritmu: O(N*log(log N)), kde N je horní mez rozsahu Pro reprezentaci množiny čísel použijeme pole prvků typu oolean prvek mnozina[x] ude udávat, zda číslo x v množině je (true) neo není (false) Strana 11 (celkem 20)
pulic class Sito { static final int MAX = 17; static oolean [] vytvormnozinu (int max){ oolean [] mnozina = new oolean [max+1]; for(int i=0; i< mnozina.length; i++){ mnozina[i] = true; return mnozina; static void sito (oolean [] mnozina){ int max = (int) Math.sqrt(mnozina.length); for(int i=2; i<=max; i++){ if(mnozina[i] == false){ continue; for(int j=2*i; j<mnozina.length; j += i){ mnozina[j] = false; static void vypisprvocisla (oolean [] mnozina){ for(int i=2; i<mnozina.length; i++){ if(mnozina[i]){ System.out.print(i + ", "); System.out.println(); Strana 12 (celkem 20)
pulic static void main(string [] args){ oolean [] prvocisla = vytvormnozinu(max); sito(prvocisla); vypisprvocisla(prvocisla); 2, 3, 5, 7, 11, 13, 17, Vícerozměrná pole, matice - přístup prostřednictvím více indexů - práce jako s jednorozměrnými poli (prvky jsou opět pole pole s nestejnou délkou řádek) - deklarace stejná, pouze více rozměrů ([]) Celočíselné dvourozměrné pole [] [] pole [0] 2 4 0 1 pole [1] 1 8 0 1 pole [2] 2 9 1 3 0 1 2 3 null null 0 1 2 3 4 pole Strana 13 (celkem 20)
int[][] pole = new int [5][]; pole[0] = new int [2]; pole[0][0] = 2; pole[0][1] = 4; pole[1] = new int[2]; pole[1][0] = 1; pole[1][1] = 8; pole[2] = new int[4]; pole[2][0] = 2; pole[2][1] = 9; pole[2][2] = 1; pole[2][3] = 3; 2 4 1 8 2 9 1 3?? Odélníková matice o m řádcích a n sloupcích int m = 3; int n = 4; int [][] matice = new int [m][n]; Rozměry matice matice.length = počet řádků matice[0].length = počet sloupců Inicializace matice 3x3 int [][] mat = {{1,0,0,{0,1,0,{0,0,1; Strana 14 (celkem 20)
Příklad: součin matic a a 11 21 a a 12 22 a a 13 23 11 21 31 12 22 32 13 23 33 14 24 34 a a 11 21 11 11 a a 12 22 21 21 a a 13 23 31 31 c c 12 22 c c 13 23 c c 14 24 import java.util.*; pulic class SoucinMatic { static private Scanner sc = new Scanner(System.in); /* static int c[][] = new int [3][4]; static int a[][] = {{1, 1, 1, 1, 1, {1, 1, 1, 1, 1, {1, 1, 1, 1, 1; static int [][] = {{1, 1, 1, 1, {1, 1, 1, 1, {1, 1, 1, 1, {1, 1, 1, 1, {1, 1, 1, 1; */ Strana 15 (celkem 20)
static int [][] nactimatici(scanner sc, int radky, int sloupce){ int [][] matice = new int[radky][sloupce]; for (int i = 0; i < matice.length; i++){ for (int j = 0; j < matice[i].length; j++) { matice[i][j] = sc.nextint(); return matice; static void vypismatici(int [][] matice){ for (int i = 0; i < matice.length; i++){ for (int j = 0; j < matice[i].length; j++) { System.out.print(matice[i][j] + " "); System.out.println(); static int [][] vynasomatice(int[][] a, int [][] ){ int [][] c = new int[a.length][[0].length]; for (int i = 0; i < a.length; i++) { for (int j = 0; j < [i].length; j++) { int s=0; for (int k = 0; k < a[i].length ; k++){ s += a[i][k] * [k][j]; c[i][j] = s; return c; Strana 16 (celkem 20)
pulic static void main(string[] args) { int m = sc.nextint(); int n = sc.nextint(); int p = sc.nextint(); int [][] a = new int [m][n]; int [][] = new int [n][p]; int [][] c = new int [m][p]; a = nactimatici(sc, m,n); = nactimatici(sc, n,p); c = vynasomatice(a, ); vypismatici(a); vypismatici(); vypismatici(c); 2 3 4 1 1 1 // A 1 1 1 1 1 1 1 // B 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 // C 3 3 3 3 Strana 17 (celkem 20)
Dynamické rozšiřování pole Před započetím práce s polem určení velikosti Komplikace udoucí potřea většího pole - kdy? - kolik? Řešení - test indexu pole a následné dynamické rozšíření - technika rozšíření pole = programová sekvence Myšlenka je založena na tom, že původní pole a ude referencováno též proměnnou x a na proměnné a vytvoříme větší pole, např. dvakrát tak velké jako ylo pole původní. Hodnoty prvků pole a jsou teď implicitně nastaveny na 0 (pole je ojekt). Původní hodnoty tudíž zkopírujeme z pole x. Pro ilustraci přiřadíme hodnoty i ostatním prvkům pole a. a x 0 1 2 3 x 0 1 2 3 a 0 1 2 3 4 5 6 7 Strana 18 (celkem 20)
class DynamickePole { pulic static void main (String[] args) { int maxn = 4; int[] a = new int[maxn]; for(int i = 0; i < a.length; i++) { a[i] = i; int[] x = a; a = new int[2*a.length]; for(int i = 0; i < x.length; i++) { a[i] = x[i]; for(int i = maxn; i < a.length; i++){ a[i] = i; for(int i=0; i < a.length; i++) System.out.println(a[i]); Z kódu je patrné, že není výhodné přidávat často pouze po jednom prvku, ale jednou za čas a větší počet prvků. [zdroj: Dynamické rozšíření pole - PPA2 ebook] Upozornění (informatici): Pokud je však přidělen např. velký úsek paměti, není vhodné rozšiřovat o 100%, ale přidělit jen úsek potřené velikosti! Strana 19 (celkem 20)
Prolém Proveďte jednoduchou analýzu zadaného textu. První řádek vstupu osahuje kladné celé číslo n (1 n 1000). Toto číslo představuje počet následujících řádek vstupu. Dalších n řádek uď neude osahovat žádný znak neo ude osahovat jeden či více znaků (přípustné jsou i mezery). Tyto řádky tvoří text, který má ýt analyzován. Můžete předpokládat, že písmena se v textu jsou pouze z anglické aecedy. Každý řádek výstupu ude osahovat jedno velké písmeno, následované mezerou a kladným celým číslem, které vyjadřuje počet, kolikrát se toto písmeno ojevilo v textu. Velká a malá písmena jsou považována za totožná. Kromě písmen neudou vyhodnocovány žádné jiné znaky. Písmena musí ýt na výstupu seřazena sestupně podle jejich četnosti výskytu, tzn. nejfrekventovanější písmeno ude na prvním řádku a poslední řádek ude osahovat nejméně frekventované písmeno. Pokud ude existovat více písmen se stejnou frekvencí výskytu, pak udou řazena vzestupně podle aecedy. Pokud se písmeno v textu nevyskytlo, nesmí se ojevit ani na výstupu. Prolém je možno automaticky validovat na: http://uva.onlinejudge.org/ Co je nutno udělat? - registrace, pokud již zaregistrováni nejste - přečíst zadání (10008 What is Cryptanalysis) - napsat zdrojový kód - odevzdat zdrojový kód - pozor třída i souor je nutno pojmenovat Main! - kontrola validace, održíte i validační e-mail Strana 20 (celkem 20)