ProgaOra/adatstrukturak

257 lines
14 KiB
Plaintext
Raw Normal View History

2024-11-13 11:52:21 +00:00
Adatstruktúrák és algoritmusok
A problémamegoldás menete
Való problémák => absztrakt modellezés => algoritmus => program
Algoritmus
Az algoritmus egy hatékony eljárás egy feladat vagy probléma megoldására, melynek helyessége bizonyítható.
Hatékonyság
A hatékonyságot a futási idő és a memóriaigény határozza meg.
Algoritmusok futásidő elemzése
Futási idő: Egy bizonyos bemenetre a végrehajtott (gépfüggetlen) alapműveletek, vagy lépések száma.
A lépésszám pontos meghatározása helyett általában elegendő a lépésszám nagyságrendjének meghatározása,
és ebből már (kis óvatossággal) következtetni lehet arra,
hogy az algoritmus mennyire hatékony, avagy hogyan fog viselkedni nagyobb értékekre.
Aszimptotikus Hatékonyság
Ha a bemenet mérete elég nagy, akkor az algoritmus futási idejének csak a nagyságrendje érdekes
Az O ordó jelölés
Az O jelölést arra használjuk, hogy a futási idő növekedését aszimptotikusan alulról és felülről konstans távolságra behatároljuk.
Például a bináris keresés futási ideje legrosszabb esetben O(log n), helytelen lenne azt állítani, hogy a bináris keresés futási ideje O (log n) minden esetben.
A bináris keresés futási ideje soha nem rosszabb, mint O (log n), de van amikor ennél jobb.
Jó lenne egy olyan aszimptotikus jelölés ami azt fejezné ki, hogy "a futási idő maximum ennyivel nő, de ennél lassabban is nőhet." Erre használjuk az O jelölést.
Ha a futási idő O(f(n)), akkor elég nagy n esetén a futási idő maximum k*f(n) valamilyen konstans k érték mellett.
Azt mondjuk "f(n) ordója" vagy egyszerűen "O(f(n))" (kiejtésben használatos még az "ordó f(n)" is).
Az O jelölést aszimptotikus felső korlátként használjuk, mivel a futási időt felülről korlátozza, ha az input mérete elég nagy.
Bináris keresés futási ideje: O(log<sup>2</sup>n)
Tömb
A tömb egy olyan adatszerkezet, amely menet közben nem méretezhető át.
Tehát ha új elemeket szeretnénk egy meglévő tömbhöz adni, az csak úgy fog működni,
hogy létrehozunk egy új tömböt, ami az új elemek és a meglévő elemek tárolására alkalmas,
ezután pedig bemásoljuk a meglévő elemeket és az új elemeket a teljesen új tömbünkbe.
Tömbökben referencia típusokat is alkalmazhatunk,
viszont ebben az esetben nem elég példányosítani a tömböt,
az egyes elemeket is példányosítani kell, mivel ebben az esetben a tömb csak az objektumra mutató referenciát tárolja,
így a példányosítás nélkül a tömb elemeinek értéke null lesz.
Az osztályokat nem muszáj a konstrukroruk segítségével példányosítani.
Erre a célra vezették be a nyelvben az Object Initializer szintaxist,
amivel egy osztály adattagjai úgy adhatóak meg, mint egy tömb elemei.
Ez akkor jön jól, ha van egy osztályunk, amely adattagokkal rendelkezik,
de a konstruktor az objektum minden adattagjának beállításához nagyon összetett és komplikált lenne.
Ebben az esetben nem érdemes konstruktort írni. Az objektum inicializáló szintaxis a következő:
var objektum = new osztály(){
Adattag = érték,
Adattag2 = érték,
Adattag3 = érték
};
Ez a szintaxis csak olyan adattagok esetén alkalmazható, amelyek publikusan is írhatóak.
Egyéb védelmi szinttel rendelkező adattagok nem írhatóak ezzel a módszerrel.
Ezen adattagok beállítására továbbra is a konstruktor szintaxis használható.
Az osztályokat
2024-11-15 10:16:13 +00:00
Tömbök kezelését segítő metódusok
Length{ get;}
long Length{get;}
Visszaadja az aktuális tömb elemeinek a számát hosszú egész típusban.
Akkor jön jól, ha nagyon nagy méretű tömböket szeretnénk kezelni.
int Rank{get;}
Visszaadja a tömb dimenzióinak a számát
Ezen tulajdonságokon kívül az Array osztály számos statikus metódust tartalmaz,
amelyeket felhasználhatunk tömbök kezelésére.
Ezek közül a leghasznosabbak és legfontosabbak:
Array.Clear(Array array, int index,int length);
Array.Copy(Array sourceArray, Array destinationArray, int length);
Array.Copy(Array sourceArray, Array destinationArray, long length);
//harmadik paraméter a másolandó elemek száma
Array.Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length);
int Array.IndexOf(Array array, object value);
int Array.IndexOf(Array array, object value, int startIndex);
int Array.LastIndexOf(Array array, object value);
int Array.LastIndexOf(Array array, object value, int startIndex);
Array.Reverse(Array array);
Array.Reverse(Array array, int index, int length);
// második elem a kezdőelem indexét adja meg, a harmadik az elemk számát adja meg
Array.Sort(Array array);
//Akkor ha az IComperable<T> implem,entálva van
Array.Sort(Array keys, Array items);
//Két tömb elemeinek a sorbarendezése, méghozzá úgy,hogy az első paraméterként megadott tömb kulcsokat tartalmaz,
//amelyhez a második paraméterként megadott tömb értékek társulnak.
Adatstruktúra interfészek
A kollekciókhoz kapcsolódó interfészek közül az egyik legfontosabb az IEnumerable<T> interfész.
Ez teszi lehetővé, hpgy mindegyik kollekción implementáéciótól függetlenül végig tudjuk uteráléni egy foreach ciklussal.
Az absztrakció következő szintje az IReadOnlyCollection és a ICollection interfészek.
Az ICollection<T> egy módosítható kollekciót ír le aminek at elemei törölhetőek és bővíthetőek.
A IReadOnlyCollection<T> pedig egy olyat,amiből csak olvasni tudunk, de tudjuk az elemek számát.
Az olyan típusok esetén, mint a lista halmaz és ... meg van valósítva mind a kettő.
Láncolt lista
A tömb adatszerkezet kiváló, ha előre tudjuk, hogy menni elemre van szükségünk.
A bővítés csak úgy lehetséges,ha létrehozunk egy újabb tömböt, aminek a mérete a hozzáadandó elemek számával meg van növelve.
Az új tömbbe átmásoljuk a meglévő elemeit, majd az új tömbhöz hozzáadjuk az új elemeket.
Végezetül pedig töröljük az eredeti tömböt.
Az algoritmus leírásából kiolvasható, hogy et nem éppen ideális,mivel a sebességre igen negatív hatással van a másolás.
Továbbá a másolás folyamán egy rövid időre duplázódik a programunk memóriahasználata.
Egy sokkal jobb megoldása lehet nagy mennyiségű előre nem ismert számú adat tárolására a láncolt lista szerkezet.
A láncolt lista egy eleme két részből épül fel. Egyrészt tartalmazza a tárolni kívánt adaott,
vagy adatokat és tartalmaz egy olyan mutatót, ami a lista eg másik elemét mutatja.
Ha a referencia a következő elemre nem létezik, akkor a lánc végén vagyunk.
A láncolt lista a dinamikus tömbhöz képest hátránya a közbülső elemnek elérhatőségéből ered.
Míg egy tömb esetén ha tudjuk,hogy a k. elemet szeretnénk elérnim akkor a tömb indexelésével rögtön hozzáférhefünk ehhet az adathoz, addog a láncolt listában a lista elejéről indulva a mutatókon keresztül addig kell lépkedni, míg a k. elemhez nem értünk.
A véletlenszerű lista elem megtalálása a lista hosszával arányos időt igényel.
2024-11-21 09:08:03 +00:00
Egyszeresen láncolt lista
Egyszeresen láncolt listában egy darab mutató jelöli a lista rákövetkező elemét.
Ha ismerjük a lista legelső elemét (lista feje), akkor abból elindulva a mutatók segítségével végig járhatjuk a listában tárolt elemeket.
A lista legutolsó elemének mutatójának értéke null, ez jelzi, hohgy tovább nem tudunk haladni a listában.
Láncolt lista esetén általában egyszeresen láncolt listára gondolunk.
Csomopont osztály: az adatot és a következő elemre mutató referenciát tartalmazza.
LancoltLista osztály: tartalmazza a listához szükséges főbb műveletekez:
Hozzaad: új elemet ad a lista végéhez
Torol: töröl
Kiir: kiír
Pogram osztály:
Teszteli a fenit műveleteket, létrehozza a listát, hozzáad elemeket,
töröl egy létező és egy nem létező elemet, majd kiírja a lista tartalmát.
Kétszeresen láncolt lista
Kétszeresen láncolt lsuita esetán 2db hivatkozűs van egy csomópontban,
az egyik az előző a másik a következő csomópontra mutat, C# ban kétszeresen láncolt listák vannak.
Hasonlóan mint a listák, szintén osztályból vannak létrehozva és ezért referencia típus,
természetesen referencia másolás történik értékadásnál.
Mint a listák esetében is a LinkedList beírása utám a <> jelek közé kerül a láncolt listánk típusa és a megszokott név,
egyenlőségjel a new operátor valamint újra a LinkedList és el ne felejtsük a zárójeleket!
LinkedList<string> lancoltlista = new LinkedList<string>();
Ezután a Linkedlist.AddLast(érték) metódussal tudunk a listánk végére beszúrni egy elemet,
vagy például az AddFirst(érték) metódussal pedig a lista első helyére.
Láncolt listák fontos metódusai
LinkedList.RemoveLast/First törli a lista utolsó vagy első elemét.
LinkedListNode<T> = LinkedList.Last/First
Visszaadja egy adott listában szereplő első vagy utolsó csomópontot, amelyben megtalálhatjuk a következő csinópontra mutató hivatkozást.
A LinkedList<T> objektumban minden csomópont LinkedListNode<T> típusú.
Mivel a LinkedList<T> kétszeresen kapcsolódik, minden csomópont előre mutat a köevtkező csomópontra, illetve hátra az előzőre.
LinkedList.AddAfter(LinkedListNode, value) / AddBefore
Egy csomópont elé vagy után szúr be adatot.
LinkedListNode<T> = LinkedList.Find(keresett_ertek)
Visszaadja a megadott értékhez tartozó csomópontot.
Csomópontok - LinkedListNode
Egy listából létrehozunk egy-egy csomópontot, melyben az adott csomóponthoz tartozó érték és a következő csomópontra mutató hivatkozás van.
A következő csomópontra való ugráshoz a .Next metódust kell használnunk, hogy visszafele közlekedjünk pedig a .Previous metódust kell használnunk.
A .Value metódus az adott csomópontban eltárolt adatot adja vissza.
Mivel tudjuk, hogy a láncolt listák utolsó, illetve első eleme null értékű, így egy while ciklussal is végig tudunk menni az adott láncolt listán,
a léptetéséről a Next gondoskodik.
2024-11-22 09:45:16 +00:00
Verem (stack)
A verem egy olyan adatszerkezet, amelyben az utoljára betett elemet tudjuk feldolgozni.
(LIFO)
A veremmutató mindig a legfelső elemre mutat.
A push a tetejére rak , a pop onnan vesz el.
A Stack<T> osztály fontosabb tulajdonságai és metódusai:
Stack(int capacity)
Paraméteres konstruktor. A paraméter a kiindulásként tárolni kivánt elemej számát adja meg.
Stack(IEnumerable<T> collection)
Paraméteres konstruktor.
A verem elemei aparaméterklnt megadott IEnumerable felület implementáló osztály elemei lesznek.
T Peek()
Visszaadja a verem tetején lévő elemet anélkül, hogy azt kivenne a verembol.
T Pop()
Visszaadja a verem tetején lévő elemet és az elemet eltávolítja a veremből.
void Push()
A paraméterkéntmegadott elemet beilleszti a verem tetejére.
T[] ToArray()
A verem elemeit visszaadja egy tömbben.
void TrimExcess()
Átméretezi a veremet úgy, hogy csak annyi elemnek foglaljon helyet, mint amennyi ténylegesen használva van.
2024-11-27 11:57:25 +00:00
Verem osztály
Generikus (a generikus fogalom a programozásban olyan technikára utal,
amely lehetővé teszi, hogy osztályok, metódusok, vagy adatszerkezetek különböző típusoknál ..)
program osztály:
létrehoz egy Verem<int> példányt 5 kapacitással.
Bemutatja az összes műveletet, beleértve a verem túlcsordulásának és kiürítésének kezelését.
2024-12-05 09:15:38 +00:00
Fák
#TODO egészítsd ki ezt a részt
Hash függvény, Hash tábla, Hasító tábla
A hash egy rögzített hosszúságú érték, amelyet egy matematikai képlet segítségével állítanak elő.
A hash értékeket adattömörítésben, kriptológiában stb. használják.
Az adatindexelésében a hash értéket használjuk, mert rögzített hosszúságúak, függetlenül a generálásukhoz használt értékektől.
Lehetővé teszi, hogy a ......
A hah fgvény egy matematikai algoritmust alkalmaz a kulcs hash-é alakítására.
Az ütközés akkor következik be, ha egy hash függvény ugyanazt a hash értéket állítja elő több kulcshoz.
Hash tábla
A hash tábla egy olyan adatstruktúra, amely kulcs értékpár használatával értéket tárol.
Minden értékhez egydi kulcs van hozzárendelve, amelyet egy hash függvény segítségével állítanak elő.
A kulcs neve a hozzá tartozó érték elérésére szolgál.
Ez nagyon felgyorsítja az értlkek keresését a hash táblában,
függetlenül a hash táblában lévő elemek számától.
Hash funkciók
Például, ha az alkalmazottak nyilvántartásait szeretnénk tárolni,
és minden alkalmazott egyedileg azonosítható egy alkalmazotti szám segítségével.
Kulcsként használhatjuk az alkalmazotti számot,
értékként a munkavállalói adatokat rendelhetjük hozzá.
A hash függvény megoldja a fenti problémát azáltal, hogy lekéri az alkalmazottu számot,
és ennek segítségével generál egy hash egész értéket,
rögzített számjegyeket, és optimalizálja a tárhelyet.
A hash függvény célja egy kulcs létrehozása, amely a tárolni kívánt értékre hivatkozik.
A függvény elfogadja a mentendő értéket, majd egy algoritmus segítségével kiszámítja a kulcs értékét.