2018. november 13., kedd

Eldöntés. Gyakorló feladatok

Tömbök


Gyakran van szükségünk arra, hogy több azonos típusú objektumot tároljunk el, ilyenkor kényelmetlen lenne mindegyiknek külön változót foglalnunk (képzeljünk el 30 darab int típusú változót, még leírni is egy örökkévalóság lenne). De ezt nem is kell megtennünk, hiszen rendelkezésünkre áll a tömb adatszerkezet. A tömb meghatározott számú, azonos típusú elemek halmaza. Minden elemre egyértelműen mutat egy index (egész szám). A tömbök referenciatípusok. A C# mindig folytonos memóriablokkokban helyezi el egy tömb elemeit. Tömböt a következőképpen deklarálhatunk:

int[] array = new int[10];

Ez a tömb tíz darab int típusú elem tárolására alkalmas. A tömb deklarációja után az egyes indexeken lévő elemek automatikusan a megfelelő null értékre inicializálódnak (ebben az esetben 10 darab nullát fog tartalmazni a tömbünk). Ez a szabály referenciatípusoknál kissé máshogy működik, mivel ekkor a tömbelemek null-ra inicializálódnak. Ez nagy különbség, mivel értéktípusok esetében szimpla nullát kapnánk vissza az általunk nem beállított indexre hivatkozva (vagyis ez egy teljesen szabályos művelet), míg referenciatípusoknál ugyanez NullReferenceException típusú kivételt fog generálni.

Az egyes elemekre az indexelő operátorral (szögletes zárójelek: [ ]) és az elem indexével (sorszámával) hivatkozunk. A számozás mindig nullától kezdődik, így a legutolsó elem indexe: az elemek száma mínusz egy. A következő példában feltöltünk egy tömböt véletlen számokkal és kiíratjuk a tartalmát:

using System;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
int[] array = new int[10];
Random r = new Random();
for (int i = 0; i < array.Length; ++i)
{
array[i] = r.Next(0, 100);
}
foreach (int item in array)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
}

A példában a ciklusfeltétel megadásakor a tömb Length nevű tulajdonságát használtuk, amely visszaadja a tömb hosszát. Látható az indexelő-operátor használata is, az array[i] a tömb i–edik elemét jelenti. Az indexeléssel vigyázni kell, ugyanis a fordító nem ellenőrzi fordítási időben az indexek helyességét, viszont helytelen indexelés esetén futás időben IndexOutOfRangeException kivételt fog dobni a program.
A tömb adott elemét az értékadással egy időben is kiírhattuk volna, a példában csak szemléltetés céljából használtunk kétféle ciklust.
Egy tömböt akár a deklaráció pillanatában is feltölthetünk a nekünk megfelelő értékekkel:

char[] charArray = new char[] { 'b', 'd', 'a', 'c' };

Egy tömb által tárolható elemek számát a deklarációval azonnal meghatározzuk, ezen a későbbiekben nem lehet változtatni.
Minden tömb a System.Array osztályból származik, ezért néhány hasznos művelet azonnal  rendelkezésünkre áll (pl. rendezhetünk egy tömböt a Sort metódussal):

chararray.Sort(); // tömb rendezése

TÖBBDIMENZIÓS TÖMBÖK


Eddig az ún. egydimenziós tömböt (vektort) használtuk. Lehetőségünk van azonban többdimenziós tömbök létrehozására is, ekkor nem egy indexszel hivatkozunk egy elemre, hanem annyival, ahány dimenziós a tömb.
Vegyük például a matematikából már ismert mátrixot:
          12, 23, 2
A = [ 13, 67, 52 ]
           45, 55, 1
Ez egy kétdimenziós tömbnek (mátrix) felel meg, az egyes elemekre két indexszel hivatkozunk, első helyen a sor áll és utána az oszlop. Így a 45 indexe: [2, 0] (ne feledjük, még mindig nullától indexelünk).
Multidimenziós tömböt a következő módon hozunk létre C# nyelven:

int[,] matrix = new int[3, 3];

Ez itt egy 3x3–as mátrix, olyan, mint a fent látható. Itt is összeköthetjük az elemek megadását a deklarációval, bár egy kicsit trükkösebb a dolog:

int[,] matrix = new int[,]
{
{12, 23, 2},
{13, 67, 52},
{45, 55, 1}
};

Az elemszám most is meghatározott, nem változtatható.
Nyilván nem akarjuk mindig kézzel feltölteni a tömböket, viszont ezúttal nem olyan egyszerű a dolgunk, hiszen egy ciklus biztosan nem lesz elég ehhez, vagyis gondolkodnunk kell: az index első tagja a sort, a második az oszlopot adja meg, pontosabban az adott sorban elfoglalt indexét. Ez alapján pedig jó ötletnek tűnik, ha egyszerre csak egy dologgal foglalkozunk, azaz szépen végig kell valahogyan mennünk minden soron egyesével. Erre a megoldást az ún. egymásba ágyazott ciklusok jelentik: a külső ciklus a sorokon megy át, a belső pedig a sorok elemein:

using System;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
int[,] matrix = new int[3, 3];
Random r = new Random();
for (int i = 0; i < matrix.GetLength(0); ++i) // sorok
73
{
for (int j = 0; j < matrix.GetLength(1); ++j) // oszlopok
{
matrix[i, j] = r.Next(0, 100);
}
}
Console.ReadKey();
}
}
}

Most nem írjuk ki a számokat, ez már nem okozhat gondot az olvasónak. A tömbök GetLength metódusa a paraméterként megadott dimenzió hosszát adja vissza (nullától számozva), tehát a példában az első esetben a sor, a másodikban az oszlop hosszát adjuk meg a ciklusfeltételben.

A többdimenziós tömbök egy variánsa az ún. egyenetlen (jagged) tömb. Ekkor legalább egy dimenzió hosszát meg kell adnunk, ez konstans marad, viszont a belső tömbök hossza tetszés szerint megadható:

int[][] jarray = new int[3][];

Készítettünk egy három sorral rendelkező tömböt, azonban a sorok hosszát (az egyes sorok maguk is önálló vektorok) ráérünk később megadni, és nem kell ugyanolyan hosszúnak lenniük.

using System;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
int[][] jarray = new int[3][];
Random r = new Random();
for (int i = 0; i < 3; ++i)
{
jarray[i] = new int[r.Next(1, 5)];
for (int j = 0; j < jarray[i].Length; ++j)
{
jarray[i][j] = i + j;
Console.Write("{0}, ", jarray[i][j]);
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}

Véletlenszám-generátorral adtuk meg a belső tömbök hosszát, persze értelmes kereteken belül. A belső ciklusban jól látható, hogy a tömb elemei valóban tömbök, hiszen használtuk a Length tulajdonságot (persze a hagyományos többdimenziós tömbök esetében is ez a helyzet, de ott nem lenne értelme külön elérhetővé tenni az egyes sorokat).
Az inicializálás a következőképpen alakul ebben az esetben:

int[][] jarray = new int[][]
{
new int[]{ 1, 2, 3, 4, 5 },
new int[]{ 1, 2, 3 },
new int[]{ 1 }
};

Nincsenek megjegyzések:

Megjegyzés küldése