PR2ET12: Ahelloend

Labori materjal

Laboriülesanded

Selles laboris on üks laboriülesanne, mida laiendab 2 edasijõudnute ülesannet

Laboriülesanne: Ahelloend

Baasülesandes tuleb sul luua rakendus, mis koostab ahelloendi, väljastab selle ning võimaldab loendist otsinguid teostada.

Lae alla aluskood: https://blue.pri.ee/ttu/files/iax0584/aluskoodid/12_ll_basecode.zip

Nõuded
  • Loo menüüprogramm, mis kasutab ühesuunalist ahelloendit
  • Lisatavad elemendid tuleb paigutada loendi algusesse.
  • Iga elemendi sees on täisarv (id) ja sõne (nimi)
    • id on automaatselt genereeritud, unikaalne, järjestikuline täisarv, mis algab nullist.
    • Nimi on sõne, mille sisestab kasutaja uue elemendi loomise käigus
    • Nime jaoks rakenda dünaamilist mälujaotust vastavalt nime sisestatava pikkusele.
  • Ülesande lahendamise käigus tuleb sul luua minimaalselt järgnevad funktsioonid: PrintNode() , CreateNode() , InsertNode() , FindNodeByID() , FindNodeByName()  ja Unload()  .
  • Lahendus tuleb luua etteantud aluskoodi peale.
  • Lahendust luues järgi samm-sammult järgnevat juhendit. Loo funktsioonid vastavalt seal kirjeldatud nõuetele.
Samm-sammuline juhend

NB! Märka, et struktuuri deklareerides on loodud andmetüübile kaks erinevat nime –  struct node  ja list . Mõlemad tähendavad sama asja – st on aliased (nimekaimud) tänu tüübidefinitsioonile. Kasutuse poole pealt on funktsioonid koostatud sedasi, et struct node  viitab ühele elemendile, samal ajal kui list  viitab loendile kui tervikule.


Esimene funktsioon, mis tuleb luua, on ühe ahelloendi elemendi kõigi liikmete väljastamiseks (st id, nimi ja viit järgnevale elemendile). Funktsiooni prototüüp on juba päisefailis olemas. Sinul tuleb luua funktsiooni keha ja paigutada see koodifaili.

PrintNode()  funktsiooni peaksid kasutama iga kord, kui tuleb väljastada ühe elemendi sisu. Sedasi kui loendis olevad liikmed peaksid muutuma tuleb muudatus väljastuseks teha vaid ühes kohas. Ülesande lõpupoole on sul seda funktsiooni vaja ka nt otsingufunktsioonide tulemuste väljastamiseks.

Kontrolli, et funktsiooni poleks edastatud NULL-viita. NULL-viida puhul väljasta veateade, kehtiva viida puhul väljasta elemendi sisu.

Kommenteeri sisse testimise esimene osa (stage 1) ja jooksuta oma programmi!

NB! Testjuhtudes on sõned kirjutatud UTF-8 vormingus, mis töötab väga kenasti Linuxis, kuid võib tekitada veidi lahkhelisid Windowsi keskkonnas. Probleemide korral muuda sõnesid.

Kliki mind, et näha väljundit

NB! See funktsioon on juba sinu eest valmis tehtud. Pööra tähelepanu funktsioonis oleva tsükli ülesehitusele! Sul on seda vaja loendi läbikäiguks  järgnevate funktsioonide lahendamisel.

Selle funktsiooni eesmärgiks on väljastada kõigi ahelloendis olevate elementide sisu. Funktsioonile PrintList()  edastatakse ahelloendi esimese liikme mäluaadress ning tsükli käigus liigutakse läbi ahelloendi kuni jõutakse loendi lõppu, mida tähistab NULL -viit.

Funktsioonile võib edastada ka   NULL -viida. See juhtub tavaliselt siis, kui loend mida väljastatakse osutub tühjaks.

Funktsioon ise väljastust ei teosta, vaid kasutab selle jaoks eelmises etapis loodud  PrintNode()  funktsiooni.

Kommenteeri sisse testimise teine osa (stage 2) ja jooksuta oma programmi!

Kliki mind, et näha väljundit

Seda funktsiooni kasutame uue elemendi loomiseks ja väärtustamiseks. Funktsioon tagastab vastloodud uue elemendi aadressi. Väärtused elemendile antakse kaasa parameetritena.

  1. Loo ja anna mälu uuele elemendile
  2. Määra ära ID väärtus (järjestikuline suurenev täisarv, kasuta  static  märksõna)
  3. Küsi mälu ja kopeeri struktuuri nimi
  4. Väärtusta  pNext  viit
  5. Tagasta struktuur

NB! Siin funktsioonis on kahel korral vaja mälu anda. Mõlemat tagastust tuleb kontrollida! Vea korral tagasta NULL-viit! Programm peab vea korral jätkama töötamist.

Kommenteeri sisse testimise kolmas osa (stage 3) ja jooksuta oma programmi! Ainukesed visuaalselt nähtavad erinevused on aadressiruumi muutus elementidel (läksime funktsioonide pinust kuhja). Valgrindiga käivitades näed mälu küsimiste arvu suurenemist!

Kliki mind, et näha väljundit

Selle funktsiooni eesmärgiks on lisada eelmise funktsiooni poolt loodud uus element  pNode  ahelloendisse, millele viitab ppHead . Topeltviit on vajalik, et lisada uus element loendi algusesse.

Baasülesandes lisame uue elemendi loendi algusesse. Selleks on vaja ainult 2 omistuslauset kirjutada!

NB! Enne lisamist kontrolli, et  pNode  poleks NULL -viit!

Kommenteeri sisse testimise neljas osa (stage 4) ja jooksuta oma programmi! Visuaalselt väljundis midagi ei muutu võrreldes eelmise korraga.

Kliki mind, et näha väljundit

Seda funktsiooni kutsutakse hävitajaks (destructor), mille eesmärk on andmestruktuur mälust vabastada. Vabastamise käigus vabastatakse ka struktuuri liikmed, mis on dünaamiliselt loodud – meie puhul on selleks nimi.

Ahelloendi vabastamiseks on vaja tsüklis käia läbi kogu loend.  Läbikäigu ideega tutvu  PrintList()  funktsiooniss.

Loendi vabastamise juures on oluline pöörata tähelepanu praeguse elemendi vabastamisele. Nimelt pärast praeguse elemendi vabastamist ei ole meil enam ligipääsu selle pNext  viidale. Sellest tingitult on meil vaja vabastamiseks täiendavat abiviita praegusele elemendile, mis teeb selle protseduuri natuke keerukamaks.

Tsüklis on 3 olulist sammu. Kõige elegantsema tsükli saad kasutades while()  tüüpi tsüklit!

  1. Praeguse elemendi aadressist koopia tegemine (seda koopiat kasutame vabastamiseks)
  2. Järgmise elemendi juurde liikumine ( pCurrent = pCurrent->pNext )
  3. Praeguse elemendi ja selle liikmete vabastamine.

Kommenteeri sisse testimise viies osa (stage 5).  Jooksuta programmi kasutades valgrindi! Peaksid nägema, et rakendus on 6 korda mälu küsinud ning vabastanud.

Kliki mind, et näha väljundit

Selles osas loome kaks otsingufunktsiooni, millest üks otsib nime ja teine ID väärtuse järgi. Kui otsing annab tulemust (st loendis on selline element), tagastatakse viit leitud elemendile. Kui elementi loendis ei ole, tagastatakse NULL-viit.

Kasuta  PrintNode()  funktsiooni leitud elemendi väljastamiseks.

Kommenteeri sisse testimise viiesosa (kuues 6) ja jooksuta oma programmi! Märka, et näidisväljundis on veateade väljastatud PrintNode() poolt ja ei ole seotud otsinguga!

Kliki mind, et näha väljundit

Palju õnne! Kõik baasfunktsionaalsuseks vajaminevad funktsioonid on nüüd valmis! Nüüd lisa abifunktsioonid ja koodilaused, et rakendus oleks kasutatav läbi menüü. Testimiseks mõeldud koodi võid soovi korral oma rakendusest kustutada.

Lisada tuleks näiteks nime küsimine uue kirje loomisel või otsitava sisestused otsingufunktsioonide kasutamiseks ning vajadusel tagastuste töötlemiseks. Kui valmis, anna märku tunnitöö esitamiseks!

Testimine

Siin on näha täielikult valmis programmi väljund.

Kliki mind, et näha väljundit

Edasijõudnute ülesanne 1: Tähestikulises järjestikus sorteeritud loend

Selle ülesandega muudame oma elementide lisamise funktsiooni selliseks, et loend oleks alati sorteeritud tähestikulises järjekorras

Nõuded
  • Uuenda InsertNode()  funktsiooni sedasi, et uus element paigutataks olemasolevate vahele sedasi, et loend oleks tähestikulises järjekorras
    • Selleks pead toetama elemendi lisamist loendi algusesse, lõppu või keskele
  • Uuenda   FindNodeByName()  funktsiooni, et see lõikaks kasu tähestikulisest järjekorrast.
  • Kui oled varasemalt lahendanud edasijõudnute ülesande 2, siis uuenda ka eemaldamise funktsiooni, et ka see lõikaks kasu tähestikulisest järjekorrast.
Märkused
  • Vastavalt loendi asukohale kuhu element lisatakse viitasid käidelda erinevalt.
  • Veendu asukohas enne lisamise alustamist!

Edasijõudnute ülesanne 2: Elementide eemaldamine

Loo kaks funktsiooni elementide eemaldamiseks loendist vastavalt nime või ID alusel.

Nõuded
  • Realiseeri  RemoveNodeByName()  funktisoon, mis eemaldab elemendi nimelise vaste korral.
  • Realiseeri RemoveNodeByID()  funktsioon, mis eemaldab elemendi ID vaste korra.
  • Võimalusel kasuta ära omadust, et loend on juba sorteeritud tähestikulises järjekorras (edasijõudnute ülesanne 1)
  • Veendu loendi terviklikkuses pärast elemendi eemaldamist. Testi loendi keskelt, algusest ja lõpust!
Märkused
  • Esmalt leia kas element üldsegi eksisteerib mida peaksid eemaldama
  • Eemaldamisel ühesuunalisest loendist on sul vaja meeles pidada eelmise elemendi asukohta! Seetõttu ei saa sa korduvkasutada  FindNodeBy()  funktsioone! (Saaksid, kui see oleks kahesuunaline ahelloend).
  • Algusest, keskelt ja lõpust eemaldamine on erinev! Kontrolli positsiooni enne eemaldamise alustamist, seejärel vali sobilik eemaldamise meetod.
  • Ära unusta mälu vabastada!
  • Topeltviit on vajalik loendi algusest eemaldamiseks.

Pärast seda tundi peaksid

Täiendav materjal