Lista adatszerkezet A lista adatszerkezet jellemzői 1 Különböző problémák számítógépes megoldása során gyakran van szükség olyan adatszerkezetre, amely nagyszámú, azonos típusú elem tárolására alkalmas, és nem jelent problémát a közvetlen elérés hiánya. Azonban gyakran van szükség az adatszerkezet olyan szinten történő megváltoztatására, hogy bizonyos elemeit kitöröljük, illetve a már sorozatbeli elemek közé adott helyre újat vegyünk fel, lehetőleg kevés adatmozgatás elvégzésével. Ez utóbbi feltételezi, hogy nem feltétlenül ismert előre a sorozat elemszáma. A lista adatszerkezet A lista elemek egymásutániságát jelenti. Fajtái: statikus, dinamikus lista. Statikus lista reprezentációja esetén egy táblázatot használunk, amiben érték, index párokat helyezünk el. Az indexek jelentik a rákövetkezőségeket, tehát ez fogja a lista elemei közötti logikai sorrendet kialakítani. (A táblázatban elfoglalt pozíció és rákövetkezőség nem azonos a listában elfoglalt pozícióval és rákövetkezőséggel.) A dinamikus lista mérete az igényeknek megfelelően változik. Megvalósítása láncolt listával történik. A láncolt lista egyike a számítógép-programozásban használatos legegyszerűbb adatszerkezeteknek. Olyan csomópontok, cellák sorozatából épül fel, amelyek tetszőleges számú és fajtájú adatmezőt, és egy vagy két hivatkozást tárolnak. A hivatkozás(ok) a lista következő (és előző) elemére mutat(nak). 1 Forrás: http://tudasbazis.sulinet.hu/hu/informatika/informatika/informatika-9-12-evfolyam/informatikaiprogramozasi-alapfogalmak/linearis-listak-szekvencialis-es-lancolt-helyfoglalas
A listaelem szerkezete A listaelem feladata kettős. Egyrészt helyet kell biztosítania a sokaság egy eleme számára, másrészt biztosítania kell a következő elem elérését, hiszen a memória tetszőleges területén lehet. Ennek megfelelően a listaelem funkcionálisan két részből áll: a tárolandó sorozat egy eleme és mutató a következő elem eléréséhez. Láncolt lista adatok szétszórt tárolása Tárolási módok: A listaelem szerkezete egyirányú láncolt lista, cirkuláris láncolt lista, kétirányú láncolt lista, multilista. Egy irányban láncolt lista A láncolt lista olyan homogén, dinamikus, szekvenciális elérésű adatszerkezet, amelynek minden eleme - a tárolandó adatokon kívül - azt az információt is tárolja, hogy a következő elemet hol tárolja a rendszer a számítógép memóriájában.
A lánc első elemének a címét a lista feje tartalmazza. A listafej nem tartalmaz információs részt, azaz tényleges listabeli adatot. A lánc végét az jelzi, hogy az utolsó elemben a rákövetkező elem mutatója üres (NULL). Megjegyzés: A lista első elemének eléréséhez csupán egy mutató is elegendő. Ennek ismerete a teljes lista ismeretét jelenti, mert így hozzáférhetünk az elemben tárolt minden adathoz, tehát azt az információt is ki tudjuk olvasni, hogy hol található a következő elem. A láncolt szerkezet lehetővé teszi listaelemek törlését és beszúrását a lista tetszőleges pontjára konstans (azaz a konkrét helytől független) időben, ugyanakkor egy véletlenszerűen kiválasztott elem előkeresése a lista hosszával arányos időt igényel. A láncolt listákat gyakran alkalmazzák összetettebb adatstruktúrák, mint például verem vagy sor építésekor. A cellák adatmezői tetszőleges adatot tárolhatnak, így akár hivatkozást is egy másik láncolt listára. Ezzel a trükkel már nem csak lineáris adatszerkezeteket tudunk építeni, hanem tetszőleges elágazó struktúrát, mint például fákat, gráfokat stb. Láncolt lista
Új elem felvitele Új elem felvitelét elvégezhetjük a lista elejére, végére, és adott elem után. A lista végre történő elem hozzáadásának lépései: a tárolandó adat bekérése vagy előállítása, új listaelem létrehozása; érték beállítása; a következő elem mutatójának nullázása, az új elem hozzáfűzése a lista végére, az utolsó elem mutatójának ráállítása az új elemre. Lista kiírása, feldolgozása A lista elemein egyesével végig kell menni, és kiírni vagy feldolgozni a tárolt adatot. Az elemek eléréséhez egy segéd mutatót használunk, amelyet kezdetben az első elemre állítunk. Első, utolsó elem törlése A lista első elemének törlésénél a fej mutatót állítjuk a második elemre, majd felszabadítjuk az első elem által lefoglalt memóriát. A Java nyelv esetén automatikus memória felszabadítás van. Azokat a memória területeket, amelyekre nem történik hivatkozás a rendszer Garbage Collection mechanizmusa felszabadítja. Szokták automatikus szemétgyűjtésnek is nevezni.
Tartalmazás vizsgálat Azt akarjuk kideríteni, hogy egy megadott érték szerepel-e a listában. Szintén az fejtől indulunk, és minden elem adattagját megvizsgáljuk, hogy az-e a keresett. Függvénnyel megvalósítva egy logikai igen-nem értékkel jelezzük a találatot. Láncolt lista megvalósítása Java nyelven /* * Láncolt lista adatszerkezet megvalósítása * ---------------------------------------- */ package lancoltlista; public class LancoltLista { //listaelem megvalósítása belső osztállyal class ListaElem{ //adattagok public int adat; public ListaElem kovetkezo; // listaelem konstruktora public ListaElem(int adat, ListaElem kovetkezo){ this.adat = adat; this.kovetkezo = kovetkezo; //láncolt lista adattagja a kezdő és az utolsó elem referenciája (mutatója) private ListaElem fej; private ListaElem utolso; //Láncolt lista konstruktora public LancoltLista(){ fej = null; utolso = null; üres //annak lekérdezése, hogy a lista üres -- empty = public boolean isempty(){ return fej == null; public static void main(string[] args) { // TODO code application logic here
Új elem felvitele a lista végére. //új elem felvitele a lista végére public void ujelem(int adat){ //létrehozunk egy önálló listaelemet ListaElem elem = new ListaElem(adat, null); //az elem felfűzése a listába if(fej == null){ //ha a lista üres fej = elem; //a fej mutasson az elemre else{ //egyébként utolso.kovetkezo = elem;//láncolunk utolso = elem; //a segédreferenciát is ráállítjuk Első elem törlése. //első elem törlése a listából public void torolelso(){ //ha a lista nem üres if(fej!= null) fej = fej.kovetkezo; Utolsó elem törlése //utolsó elem törlése public void torolutolso(){ //ha a lista nem üres if(utolso!= null){ ListaElem seged = fej; //megkeressük az utolsó előtti elemet while(seged.kovetkezo!= utolso){ seged = seged.kovetkezo; //töröljük az utolsót utolso = seged;
seged.kovetkezo = null; Adott értékű elem keresése //adott értékű elem keresése public boolean bennevan(int keresettadat){ ListaElem seged = fej; //amíg meg nem találjuk a keresett értéket, lépkedünk while((seged.adat!= keresettadat) && (seged.kovetkezo!= null)) seged = seged.kovetkezo; //megtaláltuk, ha úgy lépünk ki ciklusból, hogy nem értük el a lista végét return seged.adat == keresettadat; A lista elemeinek kiírása //lista kiírása public void kiirlista(){ if(!this.isempty()){ ListaElem seged = fej; while(seged!= null){ System.out.print(seged.adat+", "); seged = seged.kovetkezo; System.out.println(""); else{ System.out.println("A lista üres, nincs mit kiírni."); A lista tesztelése //főprogram public static void main(string[] args) { Random rnd = new Random();
//lista készítése LancoltLista ll = new LancoltLista(); //lista feltöltése 10 elemmel int adat; for(int i = 0; i < 10; i++){ adat = rnd.nextint(101); //új elem hozzáadása ll.ujelem(adat); //a lista kiírása System.out.println("A lista elemei:"); ll.kiirlista(); //első elem törlése, majd a lista kiírása System.out.println("Első elem törlése, majd a lista kiírása:"); ll.torolelso(); ll.kiirlista(); //utolsó elem törlése, majd a lista kiírása System.out.println("Utolsó elem törlése, majd a lista kiírása"); ll.torolutolso(); ll.kiirlista(); //adott értékű elem keresése System.out.println("10 érték keresése:"); System.out.println(ll.benneVan(10)?"benne van":"nincs benne"); A futás eredménye run: A lista elemei: 51, 37, 25, 18, 76, 49, 33, 61, 10, 76, Első elem törlése, majd a lista kiírása: 37, 25, 18, 76, 49, 33, 61, 10, 76, Utolsó elem törlése, majd a lista kiírása 37, 25, 18, 76, 49, 33, 61, 10, 10 érték keresése: benne van BUILD SUCCESSFUL (total time: 0 seconds)
Ciklikusan láncolt lista Hasonló az egy irányban láncolt listához, ám itt egyik listaelem mutatórésze sem tartalmazhatja a NIL értéket: az utolsó listaelem mutatórészébe az első listaelem címe kerül. A cirkuláris lista első elemének tárbeli címét most is egy mutató, a fejmutató tárolja. Amennyiben a fejmutató a NIL értéket tartalmazza, akkor a cirkuláris lista üres. Ciklikusan láncolt lista
Két irányban láncolt lista Hasonló az egy irányban láncolt listához, ám itt minden listaelem mutatórésze két részből áll: az egyik mutató az adott listaelemet megelőző, a másik az adott listaelemet követő listaelemre mutat. Ha üres a lista, a listát azonosító mutatók értéke végjel. Két lánc alakul ki, két fejmutatóval. A fejmutatók a két irányban láncolt lista első és utolsó elemére mutatnak. Ha mindkét fejmutató értéke NIL, akkor a két irányban láncolt listának nincs egyetlen eleme sem, azaz üres. Két irányban láncolt lista
Szabad helyek kezelése A lista-adatszerkezetek szervezéséből adódóan a listaelemek a memória különböző területein, szétszórtan helyezkedhetnek el (különösen kellő számú új elemmel való bővítés és feleslegessé vált elem listából való elhagyása után). Ez természetesen nem okoz gondot, mert az egyes listaelemek elérését az őket megelőző elemek mutatói biztosítják. A listaelemekkel végezhető műveletek (lista bővítése egy elemmel, feleslegessé vált elem elhagyása a listából) azt feltételezik, hogy a listából törölt elemek is szétszórtan helyezkednek el a memóriában. Az így felszabadult elemekre a későbbiekben egy újabb bővítés alkalmával még szükség lehet, hiszen a lista dinamikus adatszerkezet. Meg kell tehát oldani a szabad helyek kezelését. Ennek legkézenfekvőbb megvalósítása, hogy a szabaddá vált listaelemeket egyszerűen egy listába fűzve tároljuk. Szabad helyek kezelése