Datové struktury a algoritmy v Javě, část 2, představily řadu technik pro vyhledávání a třídění jednorozměrných polí, což jsou nejjednodušší pole. V tomto kurzu prozkoumáte vícerozměrná pole. Ukážu vám tři způsoby, jak vytvořit vícerozměrná pole, poté se naučíte, jak používat algoritmus Matrix Multiplication k množení prvků v dvourozměrném poli. Také představím otrhaná pole a dozvíte se, proč jsou populární pro aplikace s velkými daty. Nakonec zvážíme otázku, zda pole je nebo není objekt Java.
Tento článek vás seznámí s částí 4, která zavádí vyhledávání a třídění pomocí jednotlivě propojených seznamů.
Vícedimenzionální pole
A vícerozměrné pole přidruží každý prvek v poli k více indexům. Nejběžněji používaným vícerozměrným polem je dvourozměrné pole, také známý jako a stůl nebo matice. Dvourozměrné pole přidruží každý ze svých prvků ke dvěma indexům.
Můžeme konceptualizovat dvourozměrné pole jako obdélníkovou mřížku prvků rozdělených do řádků a sloupců. Používáme (řádek sloupec)
zápis k identifikaci prvku, jak je znázorněno na obrázku 1.
Protože jsou dvourozměrná pole tak běžně používána, zaměřím se na ně. To, co se dozvíte o dvourozměrných polích, lze zobecnit na ty vyšší.
Vytváření dvourozměrných polí
Existují tři techniky pro vytvoření dvourozměrného pole v Javě:
- Pomocí inicializátoru
- Pomocí klíčového slova
Nový
- Pomocí klíčového slova
Nový
s inicializátorem
Použití inicializátoru k vytvoření dvourozměrného pole
Přístup pouze k inicializaci k vytvoření dvourozměrného pole má následující syntaxi:
'{' [rowInitializer (',' rowInitializer)*] '}'
rowInitializer
má následující syntaxi:
'{' [expr (',' expr)*] '}'
Tato syntaxe uvádí, že dvourozměrné pole je volitelný seznam inicializátorů řádků oddělených čárkami, které se objevují mezi znaky otevřené a zavřené závorky. Kromě toho je každý inicializátor řádků volitelným seznamem výrazů oddělených čárkami, které se objevují mezi znaky otevřené a zavřené závorky. Stejně jako jednorozměrná pole musí být všechny výrazy vyhodnoceny na kompatibilní typy.
Zde je příklad dvourozměrného pole:
{ { 20.5, 30.6, 28.3 }, { -38.7, -18.3, -16.2 } }
Tento příklad vytvoří tabulku se dvěma řádky a třemi sloupci. Obrázek 2 představuje koncepční pohled na tuto tabulku spolu se zobrazením paměti, které ukazuje, jak Java vyloží tuto (a všechny) tabulky v paměti.
Obrázek 2 ukazuje, že Java představuje dvourozměrné pole jako jednorozměrné pole řádků, jehož prvky odkazují na jednorozměrná pole sloupců. Index řádků identifikuje pole sloupců; index sloupce identifikuje datovou položku.
Vytvoření pouze nového klíčového slova
Klíčové slovo Nový
přidělí paměť pro dvourozměrné pole a vrátí jeho odkaz. Tento přístup má následující syntaxi:
'Nový' typ '[' int_expr1 ']' '['int_expr2 ']'
Tato syntaxe uvádí, že dvourozměrné pole je oblast (pozitivní) int_expr1
řádkové prvky a (kladné) int_expr2
prvky sloupců, které sdílejí všechny stejné typ
. Kromě toho jsou všechny prvky vynulovány. Zde je příklad:
nový double [2] [3] // Vytvořte tabulku dvou řádků po třech sloupcích.
Vytvoření nového klíčového slova a inicializátoru
Klíčové slovo Nový
s přístupem inicializátoru má následující syntaxi:
'Nový' typ '[' ']' [' ']' '{' [rowInitializer (',' rowInitializer)*] '}'
kde rowInitializer
má následující syntaxi:
'{' [expr (',' expr)*] '}'
Tato syntaxe spojuje předchozí dva příklady. Protože počet prvků lze určit ze seznamů výrazů oddělených čárkami, neposkytujete int_expr
mezi dvojicí hranatých závorek. Zde je příklad:
nový double [] [] {{20.5, 30.6, 28.3}, {-38,7, -18,3, -16,2}}
Dvourozměrná pole a proměnné pole
Samo o sobě je nově vytvořené dvourozměrné pole zbytečné. Jeho odkaz musí být přiřazen k proměnná pole kompatibilního typu, buď přímo, nebo prostřednictvím volání metody. Následující syntaxe ukazují, jak byste deklarovali tuto proměnnou:
typvar_name '[' ']' '[' ']' typ '[' ']' '[' ']' var_name
Každá syntaxe deklaruje proměnnou pole, která ukládá odkaz na dvourozměrné pole. Upřednostňuje se umístit hranaté závorky za typ
. Zvažte následující příklady:
double [] [] teploty1 = {{20,5, 30,6, 28,3}, {-38,7, -18,3, -16,2}}; double [] [] temperature2 = nový double [2] [3]; double [] [] teploty3 = nový double [] [] {{20.5, 30.6, 28.3}, {-38,7, -18,3, -16,2}};
Stejně jako proměnné jednorozměrného pole je proměnná dvourozměrného pole spojena s a .délka
vlastnost, která vrací délku řady řádků. Například, teploty 1. délka
vrací 2. Každý prvek řádku je také proměnnou pole s a .délka
vlastnost, která vrací počet sloupců pro pole sloupců přiřazené k prvku řádku. Například, teploty1 [0] .délka
vrátí 3.
Vzhledem k proměnné pole můžete přistupovat k jakémukoli prvku v dvourozměrném poli zadáním výrazu, který souhlasí s následující syntaxí:
pole_var '[' řádek_index ']' '[' col_index ']'
Oba indexy jsou kladné int
s, které se pohybují od 0 do jedné menší než hodnota vrácená z příslušných .délka
vlastnosti. Zvažte další dva příklady:
dvojnásobná teplota = teploty1 [0] [1]; // Získejte hodnotu. teploty1 [0] [1] = 75,0; // Nastavit hodnotu.
První příklad vrací hodnotu ve druhém sloupci prvního řádku (30.6
). Druhý příklad nahradí tuto hodnotu 75.0
.
Pokud zadáte záporný index nebo index, který je větší nebo roven hodnotě vrácené proměnnou pole .délka
vlastnost, Java vytvoří a hodí ArrayIndexOutOfBoundsException
objekt.
Násobení dvourozměrných polí
Násobení jedné matice jinou maticí je běžná operace v oblastech od počítačové grafiky, přes ekonomiku až po dopravní průmysl. Vývojáři pro tuto operaci obvykle používají algoritmus Matrix Multiplication.
Jak funguje násobení matic? Nechť A představuje matici s m řádky a p sloupce. Podobně nechť B představuje matici s p řádky a n sloupce. Vynásobte A číslem B a vytvořte matici C s m řádky a n sloupce. Každý cij položka v C se získá vynásobením všech položek v A i řádek odpovídajícími položkami v B. jth sloupec a poté přidejte výsledky. Obrázek 3 ilustruje tyto operace.
Sloupce levé matice se musí rovnat řádkům pravé matice
Násobení matic vyžaduje, aby se počet sloupců (p) v levé matici (A) rovnal počtu řádků (p) v pravé matici (B). Jinak tento algoritmus nebude fungovat.
Následující pseudokód vyjadřuje Matrix Multiplication v kontextu 2-řádků po 2 sloupcích a 2 řádků po 1 sloupcích. (Připomeňme, že jsem v části 1 zavedl pseudokód.)
// == == == == == == // | 10 30 | | 5 | | 10 x 5 + 30 x 7 (260) | // | | X | | = | | // | 20 40 | | 7 | | 20 x 5 + 40 * 7 (380) | // == == == == == == DECLARE INTEGER a [] [] = [10, 30] [20, 40] DECLARE INTEGER b [] [] = [5, 7] DECLARE INTEGER m = 2 // Počet řádků v levé matici (a) DECLARE INTEGER p = 2 // Počet sloupců v levé matici (a) // Počet řádků v pravé matici (b) DECLARE INTEGER n = 1 // Počet sloupců v pravé matice (b) DECLARE INTEGER c [m] [n] // c obsahuje 2 řádky po 1 sloupci // Všechny prvky se inicializují na 0 FOR i = 0 TO m - 1 FOR j = 0 TO n - 1 FOR k = 0 TO p - 1 c [i] [j] = c [i] [j] + a [i] [k] * b [k] [j] DALŠÍ k DALŠÍ j DALŠÍ i KONEC
Kvůli těm třem PRO
smyčky, Matrix Multiplication má časovou složitost Ó(n3)
, který se vyslovuje „Big Oh of n krychle. "Maticové násobení nabízí kubický výkon, který je časově nákladný, když se násobí velké matice. Nabízí prostorovou složitost Ó(nm)
, který se vyslovuje „Big Oh of n*m, "pro uložení další matice n řádky podle m sloupce. Toto se stává Ó(n2)
pro čtvercové matice.
Vytvořil jsem MatMult
Java aplikace, která vám umožní experimentovat s Matrix Multiplication. Výpis 1 představuje zdrojový kód této aplikace.
Výpis 1. Java aplikace pro experimentování s Matrix Multiplication (MatMult.java)
public final class MatMult {public static void main (String [] args) {int [] [] a = {{10, 30}, {20, 40}}; int [] [] b = {{5}, {7}}; výpis (a); System.out.println (); skládka (b); System.out.println (); int [] [] c = násobení (a, b); výpis (c); } výpis soukromé statické void (int [] [] x) {if (x == null) {System.err.println ("pole je null"); vrátit se; } // Vypíše hodnoty prvků matice na standardní výstup v tabulkovém // pořadí. for (int i = 0; i <x.length; i ++) {for (int j = 0; j <x [0] .length; j ++) System.out.print (x [i] [j] + "" ); System.out.println (); }} soukromý statický int [] [] násobit (int [] [] a, int [] [] b) {// ======================= =============================================== // 1. a.length obsahuje počet řádků a // // 2. a [0] .length (nebo jakýkoli jiný a [x] .length pro platné x) obsahuje a's // počet sloupců // // 3. b.length obsahuje počet řádků b // // 4. b [0] .length (nebo jakýkoli jiný b [x] .length pro platné x) obsahuje počet b sloupců // // ============= ================================================== ====== // Pokud je počet sloupců a!! = Počet řádků b, zachraňte záchranu if (a [0] .length! = B.length) {System.err.println („Počet sloupců a! "); vrátit null; } // Přiřaďte výslednou matici s velikostí rovnou počtu řádků a počet krát b // počet sloupců int [] [] result = new int [a.length] []; for (int i = 0; i <result.length; i ++) result [i] = new int [b [0] .length]; // Proveďte násobení a sčítání pro (int i = 0; i <a.length; i ++) pro (int j = 0; j <b [0] .length; j ++) pro (int k = 0; k <a [0] .length; k ++) // nebo k <b.length výsledek [i] [j] + = a [i] [k] * b [k] [j]; // Vrátit výslednou matici vrátit výsledek; }}
MatMult
deklaruje dvojici matic a vypíše jejich hodnoty na standardní výstup. Poté znásobí obě matice a vypíše výslednou matici na standardní výstup.
Kompilace výpisu 1 následovně:
javac MatMult.java
Výslednou aplikaci spusťte následovně:
java MatMult
Měli byste dodržovat následující výstup:
10 30 20 40 5 7 260 380
Příklad násobení matic
Prozkoumejme problém, který se nejlépe vyřeší násobením matic. V tomto scénáři naloží pěstitel ovoce na Floridě několik návěsů s 1250 krabicemi pomerančů, 400 krabic broskví a 250 krabic grapefruitu. Obrázek 4 ukazuje graf tržní ceny za krabici pro každý druh ovoce ve čtyřech různých městech.
Naším problémem je určit, kam by mělo být ovoce odesláno a prodáno pro maximální hrubý příjem. Abychom tento problém vyřešili, nejprve rekonstruujeme graf z obrázku 4 jako cenovou matici se čtyřmi řádky a třemi sloupci. Z toho můžeme sestrojit třířadou matici s jedním sloupcem kvantity, která se objeví níže:
== == | 1250 | | | | 400 | | | | 250 | == ==
S oběma maticemi po ruce jednoduše vynásobíme cenovou matici kvantitativní maticí, abychom vytvořili matici hrubého příjmu:
== == == == | 10,00 8,00 12,00 | == == | 18700,00 | New York | | | 1250 | | | | 11,00 8,50 11,55 | | | | 20037,50 | Los Angeles | | X | 400 | = | | | 8,75 6,90 10,00 | | | | 16197,50 | Miami | | | 250 | | | | 10,50 8,25 11,75 | == == | 19362,50 | Chicago == == == ==
Odeslání obou návěsů do Los Angeles přinese nejvyšší hrubý příjem. Ale když vezmeme v úvahu vzdálenost a náklady na pohonné hmoty, možná je New York lepší sázka na získání nejvyššího příjmu.
Členité pole
Když jste se dozvěděli o dvourozměrných polích, možná vás zajímá, zda je možné přiřadit jednorozměrná sloupcová pole s různými délkami prvkům řady řádků. Odpověď je ano. Zvažte tyto příklady:
double [] [] teploty1 = {{20,5, 30,6, 28,3}, {-38,7, -18,3}}; double [] [] temperature2 = nový double [2] []; double [] [] teploty3 = nový double [] [] {{20,5, 30,6, 28,3}, {-38,7, -18,3}};
První a třetí příklad vytvoří dvourozměrné pole, kde první řádek obsahuje tři sloupce a druhý řádek obsahuje dva sloupce. Druhý příklad vytvoří pole se dvěma řádky a neurčeným počtem sloupců.
Po vytvoření teplota2
řádkové pole, jeho prvky musí být vyplněny odkazy na nová pole sloupců. Následující příklad ukazuje, přiřazení 3 sloupců k první řadě a 2 sloupce k druhé řadě:
temperature2 [0] = nový dvojitý [3]; temperature2 [1] = nový dvojitý [2];
Výsledné dvourozměrné pole je známé jako členité pole. Zde je druhý příklad: