Developedia
Developedia
Sorozatok rendezése

Sorozatok rendezése

Láttuk, hogy sorba rendezni egy listát a “rendezés”, azaz list.Sort() függvénnyel lehetett: Listák és a Foreach ciklusListák és a Foreach ciklus

Ehhez hasonlóan létezik egy Array.Sort(array) metódus is, ami hasonlóképp rendez, mint a korábban megismert listás változat, ám azzal szemben, ami egy tagmetódus, a tömb rendező egy statikus metódus, ami paraméterben várja a rendezni kívánt tömböt. Ennek túl nagy jelentősége nincs, csak egy kis szintaktikai különbség.

List<int> numberList = new List<int> {3, 7, 5, 1, 4};
int[] numberArray = {3, 7, 5, 1, 4};

numberList.Sort();         // Lista rendezése
Array.Sort(numberArray);   // Tömb rendezése

Ám mindez csak akkor működik, ha definiált, hogy mit jelent az, hogy a típus két eleme közül melyik az “alacsonyabb”, és melyik a “nagyobb” értékű.

Ez bizonyos típusok esetén triviális:

Számok: Nagyobb szám magasabb értékű Sztringek: Amelyik előrébb áll az ABC sorrendben az alacsonyabb értékű

Ez alapján történik a rendezés is:

List<int> numbers = new List<int> {3, 7, 5, 1, 4};
numbers.Sort(); // {1, 3, 4, 5, 7}

List<string> strings = new List<string> {"datolya", "banán", "alma", "citrom"};
numbers.Sort(); // {"alma", "banán", "citrom", "datolya"};

Egyéb esetekben nem ilyen könnyű eldönteni, hogyan viszonyul egymáshoz két eleme egy típusnak. Ezek közé tartozik minden általunk definiált összetett típus is

Vegyük a klasszikus Dog (kutya) példát.

struct Dog
{
	public string name;   // Neve
	public int age;       // Kora
	public float speed;   // Sebessége
	public bool doesBite; // Harap-e?
}

Hogy állítunk sorba egy ilyen kutyákat tartalmazó sorozatot? Név szerint ABC sorrendben vagy a kor szerint? Természetesen mindkét módon megtehetjük ezt, sőt tetszőleges egyéb stratégiát is használhatunk, de először definiálnunk kell a rendezési szempontot, hiszen a számítógép nem tudja magától kitalálni, most épp mire is van szükségünk.

A rendezés szempontját egy összehasonlító más néven Compare metódussal tudjuk definiálni, ami két objektumot kap az adott típusból és eldönti, egymáshoz képest melyik van előrébb a sorozatban. A két paramétert nevezzük sorrendben A-nak és B-nek!

A függvény egy int-tel tér vissza, aminek értéke:

-1: Ha az A paraméter alacsonyabb értékű, mint a B. (Rendezve A van elől)

0: Ha a két paraméter azonos szintű. (Sorrendjük nem számít)

1: Ha az A paraméter magasabb értékű, mint a B. (Rendezve A van hátul)

Ha megírunk egy ilyen metódust egy tetszőleges típusra, akkor automatikusan sorba tudjuk rendezni azt, akkor is, ha a típuson nincsen alapértelmezve, hogy melyik magasabb.

// Kutyák sorba rendezése sebesség szerint növekedve
static int CompareDog(Dog a, Dog b)
{
		if (a.speed < b.speed) return -1;
		if (a.speed > b.speed) return 1;
		return 0;
}

Ezután átadható ez a metódus a Sort() metódusnak extra paraméterként.

List<Dog> dogs = new List<Dog>();
dogs.Sort(CompareDog);   // Metódus átadása paraméterként

Igen, ilyet is lehet csinálni. Ennek részleteiről itt: Metódus mint objektum (Hamarosan)Metódus mint objektum (Hamarosan)

Elérhető, hogy egy típus listáján automatikusan működjön a paraméter nélküli Sort() függvény is.

Ehhez meg kell valósítani a típuson a IComparable<T> interface-t. Hogy ez mit jelent és hogyan kell elvégezni, ahhoz meg kell érteni az interface-ek és generikusok fogalmát és használatát: Interface-ek (Hamarosan)Interface-ek (Hamarosan), Generikusok (Hamarosan)Generikusok (Hamarosan)

Primitív típusok Compare metódusai

A beépített típusoknak is vannak összehasonlító metódusai. Ezt használja a C# a háttérben, amikor mi az egyszerű paraméter nélküli Sort() metódussal rendezünk.

int compareInts = 44.CompareTo(-95);        // A = 44f,    B = -95
int compareFloats = 12.4f.CompareTo(22.5f);   // A = 12.4f,    B = 22.5f
int compareStrings = 12.4f.CompareTo(22.5f);   // A = 12.4f,    B = 22.5f
int compareEnums = Direction.Up.CompareTo(Direction.Down);   // A = Up,    B = Down
// ...
// Eredmény minden típusra int: -1 vagy 0 vagy 1

Gyakran kapóra jöhet felhasználni ezeket a saját Compare függvényünkhöz is.

// Kutyák sorba rendezése ABC sorrendben. Ha a név egyezik, akkor kor szerint növekedve
static int CompareDog(Dog a, Dog b)
{
		int compareByName = a.name.CompareTo(b.name);    // string comparer

		if (compareByName == 0)
				return a.age.CompareTo(b.age);               // int comparer
		else 
				return compareByName;
}

Rendező algoritmusok

Eddig azt tekintettük át, hogy milyen módon tudjuk megadni a rendezési szempontot. Érdemes pár szót arra is áldozni, hogy hogyan is működik a sorba tétel maga.

Sok féle rendező algoritmus létezik:

  • Insertion Sort
  • Selection Sort
  • Bubble Sort
  • Shell Sort
  • Heap Sort
  • Quicksort
  • és még sok másik…

Ezek közül mindnek megvan az előnye a többihez képest attól függően, hogy milyen méretű, és kevertségű sorozaton alkalmazzuk őket.

image

Részletesen nem fogjuk átnézni a különböző rendezőalgoritmusok működését, itt most egyedül a Quicksort, azaz gyors rendező algoritmusra fordítunk pár szót mivel a C# ezt használja fel tömb és lista rendezésre egyaránt.

Elsőre csupán annyit érdemes tudni, hogy az algoritmus alapja, hogy először szétválasztja a sorozatot két csoportra és gondoskodik róla, hogy a kisebb elemek az első részben legyenek, míg a nagyobbak a másodikban. Mindezt úgy, hogy az első rész legnagyobb eleme is kisebb legyen, mint a második csoport legkisebbike. Ezután rekurzívan ismétli ezt a műveletet a csoportokra, addig, amíg egy csoport már csak egy elemből nem áll.

Azért erre esett a C# fejlesztőinek választása mert a módszer elég jó idővel végez kis és nagy méretű sorozatokkal is és többé kevésbé független a sebessége a rendezettség szintjétől.

A rendezési problémák 99.9%-ában nincs szükség arra, hogy máshoz folyamodjatok.

Ha nem sorba rendezni, hanem keverni szeretnél egy listát: VéletlenekVéletlenek

Logo

Főoldal

Blog

Elmélet

3D Studio

Adatvédelmi nyilatkozat

GY.I.K.

Házirend

Szerző: Marosi Csaba / marosi.csaba@3d-studio.hu

DiscordGitHubLinkedIn