10. Vícerozměrná pole

Dvourozměrné pole

Jednorozměrná pole jsme vnímali jako seznam jednotlivých prvků. Pole ale může mít více než jednu dimenzi. Zaměřme se nyní na deklaraci např. dvourozměrného pole označované jako matice (dimenze takového pole je tedy rovna 2). Do prvků matice lze ukládat různé datové typy. Pokud bychom chtěli např. do matice ukládat celá čísla, deklarace takové matice by vypadala následovně - viz Kód 1. 

//Deklarace dvourozměrného pole
int[,] matice;

Kód 1: Příklad deklarace dvourozměrného pole

Dvourozměrné pole si lze si představit jako tabulku o řádcích a sloupcích, nebo také jako více jednorozměrných polí uspořádaných za sebou. Pro přístup k jednotlivým prvkům matice je zapotřebí dvou celočíselných indexů - viz Obrázek 1.

  • První celočíselný index pro řádky např.  i  (index řádky je číslován od 0. Počet řádků matice můžeme označit např.  m )
  • Druhý celočíselný index pro sloupce např.   j   (index sloupce je číslován od 0. Počet sloupců matice můžeme označit např.  n )

Deklarace dvourozměrného pole

Obrázek 1: Podstata dvourozměrného pole - matice (rozměr m × n)

Pro tvorbu instance dvourozměrného pole o velikosti  m \times n   bychom použili následující kód – viz Kód 2.

//Vytvoření instance dvourozměrného pole o specifikované velikosti (rozměr m x n)
int[,] matice = new int[m, n];

Kód 2: Deklarace dvourozměrného pole matice (rozměr m × n)

Abychom přistoupili k hodnotě uložené v prvku dvourozměrného pole, využijeme indexů uzavřených v hranatých závorkách, které odrážejí polohu prvku pole, např.  matice[i,j] . Následující obrázek vyjadřuje podstatu indexování jednotlivých prvků dvourozměrného pole o rozměrech  m \times n  - viz Obrázek 2.

Indexování prvků dvourozměrného pole

Obrázek 2: Indexování prvků dvourozměrného pole matice (rozměr m × n)

Pokud je matice symetrická  m=n , označujeme úhlopříčnou spojnici protilehlých míst (prvního prvku a posledního prvku) jako hlavní diagonálu - viz Obrázek 3. Pro prvky na hlavní diagonále platí, že jejich index řádku  i je roven indexu sloupce  j , tj.  i=j . 

Indexování prvků na hlavní diagonále ve dvourozměrném poli

Obrázek 3: Indexování prvků na hlavní diagonále ve dvourozměrném poli

Pokud je matice symetrická  m=n , označujeme protilehlou úhlopříčnou spojnici protilehlých míst (posledního prvku prvního řádku a prvního prvku posledního řádku) jako vedlejší diagonálu - viz Obrázek 4. Pro prvky na vedlejší diagonále platí, že jejich index řádku  i je roven indexu sloupce tehdy, když  j=(n-i-1).  Pro případ matice o rozměru např.  4 \times 4  jsou prvky umístěné na vedlejší diagonále označeny modře. 

Indexování prvků na vedlejší diagonále ve dvourozměrném poli (rozměr 4 x 4)

Obrázek 4: Indexování prvků na vedlejší diagonále ve dvourozměrném poli ( 4 \times 4 )


Ilustrativní příklad MaticeVedlejsiDiagonala

Program MaticeVedlejsiDiagonala
  • Popis: Deklarace dvourozměrného pole, velikost pole, instance pole, vedlejší diagonála
  • Zadání: Deklarujte symetrické dvourozměrné pole s názvem matice. Toto pole bude obsahovat celočíselné hodnoty. Pomocí statické metody VytvorMatici, kde matice je výstupním parametrem, automaticky naplňte matici příslušnými hodnotami, které budou vzrůstat po sloupcích v každém řádku, tzn. první prvek první řádky, tj. vlevo nahoře, obsahuje hodnotu 1, další prvek v sousedním sloupci vpravo bude obsahovat 2, atd. Přiřazení hodnoty aktuálnímu prvku proveďte pomocí proměnné hodnotaPrvku. Plnění proveďte pomocí dvou cyklů s krokem - cyklus pro procházení řádek a další vnořený cyklus pro procházení sloupců. V metodě VytvorMatici také načtěte rozměry matice - proměnná m bude obsahovat počet řádků matice, proměnná n bude obsahovat počet sloupců matice. Pro výpis hodnot prvků na vedlejší diagonále použijte statickou metodu VedlejsiDiagonala do níž matici předejte. U výpisu každého prvku na vedlejší diagonále uveďte v hranaté závorce index řádku a index sloupce oddělené čárkou. Obě metody jsou volány v hlavní metodě Main
  • Řešení: MaticeVedlejsiDiagonala_Main


Nejprve si ve zdrojovém kódu metody VytvorMatici s výstupním parametrem představující vytvořenou výstupní matici (klíčové slovo out deklaruje výstupní parametr, datový typ int deklaruje, že se jedná o celočíselnou matici a čárka mezi hranatými závorkami deklaruje, že se jedná o dvourozměrné pole s názvem matice). V metodě deklarujeme proměnnou, jejíž hodnotu budeme zvedat po přiřazení této hodnoty každému prvku matice - viz Kód 3.  

//Deklarace metody, kde dvourozměrné pole je deklarováno jako výstupní parametr metody
public static void VytvorMatici(out int[ , ] matice)
{
    <span style="color:green;">// Deklarace proměnné: 'hodnota' - hodnota v prvku</span>
    <span style="color:blue;">int</span> <span style="color:#1f377f;">hodnotaPrvku</span> = 1;
}

Kód 3: Deklarace metody VytvorMatici s výstupním parametrem matice

V těle metody vybídneme uživatele pro zadání celkového počtu řádků matice - viz Kód 4. Tento zadaný rozměr matice si načteme do proměnné m. 

//Výpis textu pro zadání počtu řádků matice
Console.Write("Zadejte počet řádků matice: ");
/* Deklarace proměnné 'm' - počet řádků matice
 * + konverze zadaného textu na číslo */
int m = int.Parse(Console.ReadLine());

Kód 4: Vypsání textu pro zadání počtu řádků matice včetně načtení a konverze zadaného textu na celé číslo

Abychom splnili zadání symetrické matice, tj. m = n, vytvoříme v dalším kroku cyklus, který vybídne uživatele k zadání celkového počtu sloupců matice. Pokud uživatel zadá hodnotu počtu sloupců (uložené do proměnné n) různou od hodnoty uložené v proměnné m, je provedena znovu smyčku cyklu pro zadání hodnoty n - viz Kód 5. Proměnnou n jsme deklarovali již před cyklem, abychom v cyklu pouze zajistili zadání validní hodnoty této proměnné a nevytvářeli znovu a znovu novou proměnnou.

// Deklarace proměnné: 'n' - celkový počet sloupců matice
int n;
do
{            
    <span style="color:green;">//Výpis textu pro zadání počtu sloupců matice</span>
    <span style="color:#2b91af;">Console</span>.<span style="color:#74531f;">Write</span>(<span style="color:#a31515;">"Zadejte počet sloupců matice: "</span>);
    <span style="color:green;">/* Deklarace proměnné 'n' - počet sloupců matice
       * + konverze zadaného textu na číslo */</span>
     <span style="color:#1f377f;">n</span> = <span style="color:blue;">int</span>.<span style="color:#74531f;">Parse</span>(<span style="color:#2b91af;">Console</span>.<span style="color:#74531f;">ReadLine</span>());
}
//Prováděj cyklus pokud n je různé od m
while (n != m);

Kód 5: Načtení validní hodnoty počtu sloupců matice

Pro vytvoření instance dvourozměrného pole o rozměru m × n využijeme následující kód - viz Kód 6. K vytvoření instance pole se užívá klíčové slovo new. Tento operátor vrátí odkaz na nově vytvořené pole. Za operátorem new se uvádí datový typ prvků. Za datovým typem se uvádí v hranatých závorkách počet prvků dvourozměrného pole v každé ose.

//Vytvoření instance dvourozměrného pole o specifikované velikosti
matice = new int[m, n];

Kód 6: Vytvoření instance dvourozměrného pole o specifikované velikosti

Pokud by celkový počet řádků matice, uložený v proměnné m, byl roven 4 a celkový počet sloupců v proměnné n byl také roven hodnotě 4, měla by výsledná matice vypadat následovně - viz Obrázek 5. 

Naplnění dvourozměrného celočíselného pole (rozměr 4 x 4)

Obrázek 5: Naplnění dvourozměrného celočíselného pole matice (rozměr 4 x 4)

Pro přiřazení hodnoty aktuálně procházeného prvku pomocí celočíselné proměnné hodnotaPrvku (v našem případě prvky budou nabývat hodnot 1 ÷ 16)  budeme používat dva cykly s krokem (víme, kolik iterací má proběhnout). Proměnnou hodnotaPrvku jsme inicializovali hodnotou 1 již při její deklaraci (toto je hodnota prvku v prvním řádku a prvním sloupci, tj. matice[0, 0]). První cyklus obsahuje řídící proměnnou i, která nám určuje pozici řádku právě procházeného prvku. Ve vnitřním (vnořeném)  cyklu s řídící proměnnou j, budeme procházet sloupce matice. Index j nám tedy určuje aktuální sloupec procházeného prvku - viz Kód 7. 

//Cyklus procházející jednotlivé řádky matice
for (int i = 0; i < m; i++)
{
    <span style="color:green;">//Cyklus procházející jednotlivé sloupce matice</span>
    <span style="color:#8f08c4;">for</span> (<span style="color:blue;">int</span> <span style="color:#1f377f;">j</span> = 0; <span style="color:#1f377f;">j</span> < <span style="color:#1f377f;">n</span>; <span style="color:#1f377f;">j</span>++)
    {
        <span style="color:green;">//Přiřazení hodnoty prvku matice</span>
        <span style="color:#1f377f;">matice</span>[<span style="color:#1f377f;">i</span>, <span style="color:#1f377f;">j</span>] = <span style="color:#1f377f;">hodnotaPrvku</span>++;
    }
}

Kód 7: Přiřazení hodnot prvkům matice

Pro výpis prvků na vedlejší diagonále matice deklarujeme metodu bez návratu s názvem VedlejsiDiagonala. Tato metoda obsahuje formální vstupní parametr matice. Deklarace tohoto parametru je stejná jako v předchozí metodě VytvorMatici (samozřejmě bez klíčového slova out - matici nevytváříme, potřebujeme pouze projít její prvky a vypsat je v konzole). V této metodě využijeme znovu vnořený cyklus s krokem (namísto cyklu foreach - máme totiž uživatele informovat o aktuálním indexu řádku a sloupce právě vypisovaného prvku na vedlejší diagonále matice). Tyto indexy mají být uzavřeny do hranatých závorek.

//Deklarace metody vypisující obsah všech prvků na vedlejší diagonále dvourozměrného pole
public static void VedlejsiDiagonala(int[ , ] matice)
{
    <span style="color:green;">//Cyklus procházející jednotlivé řádky matice</span>
    <span style="color:#8f08c4;">for</span> (<span style="color:blue;">int</span> <span style="color:#1f377f;">i</span> = 0; <span style="color:#1f377f;">i</span> < <span style="color:#1f377f;">matice</span>.<span style="color:#74531f;">GetLength</span>(0); <span style="color:#1f377f;">i</span>++)
    {
        <span style="color:green;">//Cyklus procházející jednotlivé sloupce matice</span>
        <span style="color:#8f08c4;">for</span> (<span style="color:blue;">int</span> <span style="color:#1f377f;">j</span> = 0; <span style="color:#1f377f;">j</span> < <span style="color:#1f377f;">matice</span>.<span style="color:#74531f;">GetLength</span>(1); <span style="color:#1f377f;">j</span>++)
        {
            <span style="color:green;">//Pokud se prvek nachází ve vedlejší diagonále</span>
            <span style="color:#8f08c4;">if</span> (<span style="color:#1f377f;">j</span> == <span style="color:#1f377f;">matice</span>.<span style="color:#74531f;">GetLength</span>(1) - <span style="color:#1f377f;">i</span> - 1)                    
                <span style="color:green;">//Výpis textu s obsahem prvku včetně pozice prvku</span>
                <span style="color:#2b91af;">Console</span>.<span style="color:#74531f;">WriteLine</span>(<span style="color:#a31515;">"Hodnota prvku matice[{0}, {1}]: {2}", i, j, matice[i, j]);
        }
    }
}

Kód 8: Deklarace metody VedlejsiDiagonala

V hlavní metodě Main jsme nejprve vytvořili dvourozměrné pole pomocí metody VytvorMatici s výstupním parametrem matice. Tato metoda vytváří instanci dvourozměrného pole a zároveň toto pole naplní hodnotami pořadových čísel prvků v matici (za předpokladu, že procházíme jednotlivé řádky matice zleva doprava). Po vytvoření matice stačilo již vypsat prvky na vedlejší diagonále matice pomocí metody bez návratu s názvem VedlejsiDiagonala - viz Kód 9.

static void Main(string[] args)
{
    <span style="color:green;">//Zavolání metody s výstupním parametrem matice</span>
    <span style="color:#74531f;">VytvorMatici</span>(<span style="color:blue;">out</span> <span style="color:blue;">int</span>[,] <span style="color:#1f377f;">matice</span>);
 
    <span style="color:green;">//Zavolání metody pro vypsání prvků na vedlejší diagonále matice</span>
    <span style="color:#74531f;">VedlejsiDiagonala</span>(<span style="color:#1f377f;">matice</span>);
 
    <span style="color:green;">//Čekání na stisk klávesy -> ukončení programu</span>
    <span style="color:#2b91af;">Console</span>.<span style="color:#74531f;">ReadKey</span>();
}

Kód 9: Deklarace hlavní metody Main

Na výpisu v konzoli vidíme výstup našeho programu. Na druhém řádku výpisu je zaznamenán pokus o zadání jiného počtu sloupců, než byla hodnota celkového počtu řádků matice. Zde zafungoval cyklus, který uživateli nedovolí zadat jinou celočíselnou hodnotu, než je počet řádků matice. Při správném zadání celkového počtu sloupců tj. rozměru matice 4 x 4 jsou vypsány hodnoty všech prvků na vedlejší diagonále včetně indexu řádku a sloupce těchto prvků - viz Výstup programu -  MaticeVedlejsiDiagonala_Main.

Zadejte počet řádků matice: 4
Zadejte počet sloupců matice: 5
Zadejte počet sloupců matice: 4
Hodnota prvku matice[0, 3]: 4
Hodnota prvku matice[1, 2]: 7
Hodnota prvku matice[2, 1]: 10
Hodnota prvku matice[3, 0]: 13

Výstup programu - MaticeVedlejsiDiagonala_Main: Výpis prvků dvourozměrné pole - matice (rozměr 4 x 4) 


Trojrozměrná a vícerozměrná pole

Pokud bychom chtěli vytvořit tzv. kostku (anglicky "Cube"), tedy trojrozměrné symetrické pole, stačí pouze v deklaraci pole přidat do hranaté závorky další čárku. Tím definujeme další třetí rozměr pole. Pomocí následujícího kódu vytvoříme instanci trojrozměrné pole o rozměru (5 × 5 × 5) - viz Kód 10.

//Deklarace trojrozměrného pole
int[,,] kostka = new int[5, 5, 5];

Kód 10: Příklad deklarace trojrozměrného pole a vytvoření instance tohoto typu pole (kostky)

Lze si tedy odvodit, že pro přístup k jednotlivým prvkům tohoto pole je zapotřebí 3 indexů. Např. Pokud potřebujeme přiřadit hodnotu 1 prvnímu prvku levého horního rohu kostky budeme postupovat následujícím způsobem - viz Kód 11.

//Přiřazení hodnoty prvku levého horního rohu kostky
kostka[0, 0, 0] = 1;

Kód 11: Příklad přiřazení hodnoty prvku levého horního rohu kostky

Stejným způsobem bychom deklarovali další vícerozměrná pole. Počet dimenzí, které můžete u pole zadat, není nijak omezen, ale je také důležité zdůraznit opatrnost při vytváření polí s větším dimenzí než 3. Taková pole spotřebují mnoho paměti např. kostka o rozměrech 5 × 5 × 5 bude obsahovat 125 prvků. Pokud budeme vytvářet čtyřdimenzionální pole 5 × 5 × 5 × 5, tak toto pole bude obsahovat již 625 prvků. Proto buďte opatrní a zkuste využívat zpracování výjimky typu OutOfMemoryException.