This shows you the differences between two versions of the page.
|
poo:laboratoare:07 [2019/11/06 08:01] mihai.nan [Problema 1] |
poo:laboratoare:07 [2025/11/20 08:01] (current) george.tudor1906 [Problema 4] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ===== Laboratorul 07. ===== | ===== Laboratorul 07. ===== | ||
| - | Arhiva laborator: {{:poo:laboratoare:arhiva7.zip| Arhiva}} | + | Arhiva laborator: {{:poo:laboratoare:arhiva_lab7.zip| Arhiva}} |
| ==== Problema 1 ==== | ==== Problema 1 ==== | ||
| - | Să se scrie un program pentru afișarea cuvintelor distincte dintr-un fișier text folosind clasa **//TreeSet//**. Fișierul va conține și cuvinte repetate (identice). | + | Se cere realizarea unui program care citește un fișier text și afișează cuvintele distincte. |
| - | Elementele mulțimii se vor afișa în ordine crescătoare (metoda **//printWords//**) și în ordine descrescătoare (metoda **//printWordsComparator//** ), fără a apela o funcție de sortare, folosind două obiecte **//TreeSet//** construite diferit (cu și fără argument de tip **//Comparator//**). | + | |
| - | Se vor implementa cele 2 metode ce vor fi apelate din metoda **//main//**: | + | |
| - | * ''public TreeSet printWords (String)'' - va primi, ca argument, numele fișierului din care se citește și va folosi un obiect de tip **//TreeSet//**, instanțiat folosind constructorul fără argument de tip **//Comparator//**; | + | |
| - | * ''public TreeSet printWordsComparator(TreeSet)'' - va primi ca argument obiectul de tip **//TreeSet//**, returnat de metoda anterioară, și va construi si returna un alt obiect de tip **//TreeSet//**, stocând informațiile în ordine descrescătoare. | + | |
| - | În cazul instanțierii obiectului ce va fi returnat, folosiți constructorul cu argument de tip **//Comparator//**! | + | |
| - | Se poate folosi ca fisier de intrare fisierul test01.txt din arhiva! | + | În această problemă, prin "cuvânt" înțelegem o secvență de caractere obținută prin separare atât după spații, cât și după semnele uzuale de punctuație. Tokenizarea se va face exclusiv cu **StringTokenizer**, folosind o listă de delimitatori care include cel puțin: spațiul ' ', tabul '\t', virgula ,, punctul ., punct și virgulă ;, două puncte :, semnele !?, ghilimele "', paranteze ()[]{}, cratime, etc. Se vor ignora tokenurile vide (dacă apar). Compararea cuvintelor este case-sensitive („Ana” și „ana” sunt diferite). |
| + | Afișarea se face **fără a apela nicio funcție de sortare sau de inversare a ordinii din afara colecției** și se face în două etape: mai întâi se construiește un **TreeSet<String> cu ordonare naturală** (crescătoare), folosind constructorul fără argument și care este populat cu toate cuvintele distincte extrase din fișier. Apoi, **plecând strict de la setul obținut la pasul anterior**, construiți al doilea TreeSet<String> - creați o instanță nouă inițializată cu un comparator descrescător și adăugați în ea toate elementele din primul set, fără a reciti fișierul. Al doilea set trebuie să rezulte exclusiv prin această reconstrucție - nu se folosesc sortări sau inversări externe precum **Collections.sort**, //List.sort//, //descendingSet()//, etc.. | ||
| - | <hidden>==== Problema 2 ==== | + | Se vor implementa două metode, apelate din main: |
| - | Pornind de la codul de mai jos, asigurați faptul că se va apela codul aferent tipului dinamic al parametrului, definind clasele **//Hero//**, **//Warrior//**, **//Ninja//**, **//Rogue//** și **//StormFire//**, în mod minimal! | + | * <code java>public TreeSet<String> printWords(String fileName) throws IOException</code> - citește fișierul și întoarce setul crescător, instanțiat fără comparator și populat prin separare strictă la spații si semne punctuație. |
| + | * <code java>public TreeSet<String> printWordsComparator(TreeSet<String> asc)</code> - primește **exact setul obținut anterior** și construiește, **fără a reciti fișierul**, un nou TreeSet<String> cu ordonare **descrescătoare** (instanțiat cu un comparator), în care sunt copiate toate elementele din primul set. | ||
| - | <code java> | + | În main se apelează pe rând cele două metode și se afișează cuvintele, câte un cuvânt pe linie: mai întâi în ordine crescătoare, apoi o linie separatoare ---, urmată de ordinea descrescătoare. |
| - | public class Binding{ | + | |
| - | public static void main(String args[]) { | + | |
| - | Hero h1 = new Warrior(), h2 = new Ninja(); | + | |
| - | Hero h3 = new Rogue(); | + | |
| - | BadLuck bl = new StormFire(); | + | |
| - | bl.execute(h1); | + | |
| - | bl.execute(h2); | + | |
| - | bl.execute(h3); | + | |
| - | } | + | |
| - | } | + | |
| - | abstract class BadLuck { | + | Se poate folosi ca fișier de intrare fișierul test01.txt din arhivă! |
| - | abstract void execute(Hero h); | + | |
| - | abstract void execute(Warrior w); | + | |
| - | abstract void execute(Ninja n); | + | |
| - | abstract void execute(Rogue r); | + | |
| - | } | + | |
| - | </code> | + | |
| - | + | ||
| - | <note warning>Clasele **//Hero//** și **//BadLuck//** sunt clase abstracte!</note> | + | |
| - | </hidden> | + | |
| ==== Problema 2 ==== | ==== Problema 2 ==== | ||
| - | Să se definească o clasă **//LinkedSet//** pentru o mulțime realizată ca listă înlănțuită de elemente distincte. Clasa va extinde clasa **//LinkedList//** și va implementa interfața **//Set//**. | + | Definiți o clasă LinkedSet care modelează o mulțime de elemente **distincte**, implementată peste o listă înlănțuită. Clasa va **extinde** LinkedList și va **implementa** Set, iar elementele vor fi de tip **Object**. Scopul este ca structura să se comporte ca un Set - **să nu accepte duplicate**, dar **să păstreze ordinea de inserare specifică listei**. |
| - | Se vor redefini cele două metode de adăugare și metoda de setare a unui obiect: | + | Vor fi supradefinite cele trei metode indicate mai jos, astfel încât să respecte unicitatea: |
| + | * <code java>boolean add(Object obj)</code> - adaugă elementul doar dacă nu există deja în colecție (după equals). Metoda întoarce true dacă a inserat și false dacă elementul era deja prezent. | ||
| + | * <code java>void add(int index, Object obj)</code> - menține prioritatea regulii de mulțime. Operația la un index anume este permisă numai dacă elementul nu există în colecție; în caz contrar, nu efectuează nicio modificare (nu se inserează un duplicat). | ||
| + | * <code java>Object set(int index, Object obj)</code> - înlocuiește elementul de la poziția indicată doar dacă această înlocuire nu introduce un duplicat în altă poziție. Dacă obj se găsește deja în colecție pe un alt index, se va arunca o excepție de tip //IllegalArgumentException//. Dacă nu se creează duplicat, se face înlocuirea și se returnează elementul vechi. | ||
| - | <note tip><code java>boolean add(Object obj); | + | Pentru verificarea egalității se folosește metoda equals a obiectelor introduse. |
| - | void add (int i, Object obj); | + | |
| - | Object set (int i , Object obj);</code></note> | + | Pentru testare puteți folosi clasa existentă în Test2.java. |
| - | Să se testeze clasa prin folosirea metodelor definite și afișare! Se poate folosi Test2.java din arhiva! | + | |
| ==== Problema 3 ==== | ==== Problema 3 ==== | ||
| - | Să se definească o clasă **//SListSet//** pentru o mulțime ordonată de obiecte, care extinde clasa **//LinkedList//** si implementează interfața **//SortedSet//**. Clasa va conține un obiect de tip **//Comparator//** și metodele: | + | Se cere realizarea unei clase **SListSet** care modelează o mulțime ordonată de obiecte peste o listă înlănțuită. Clasa **extinde LinkedList** și **implementează SortedSet** (fără generics; elementele sunt de tip Object). Ordinea elementelor este dată de un Comparator furnizat la creare sau, dacă acesta este null, de ordinea naturală a elementelor. Două elemente sunt considerate **duplicate** atunci când comparația lor dă zero (compare(a, b) == 0), iar mulțimea nu trebuie să conțină două astfel de elemente. **Nu se acceptă valori null**. Dacă parametrul Comparator este null, toate elementele introduse trebuie să fie //Comparable// - în caz contrar se aruncă o excepție clară (de exemplu //ClassCastException// / //IllegalArgumentException//). |
| <note tip> | <note tip> | ||
| <code java> | <code java> | ||
| - | Comparator comparator () ; //comparator folosit (null pentru comparatia naturala) | + | Comparator comparator(); //comparator folosit (null pentru comparatia naturală) |
| - | boolean add(Object o); //adauga un elemnt in multime daca nu exista deja si sorteaza multimea | + | boolean add(Object o); //adaugă un elemnt în mulțime dacă nu există deja și sortează mulțimea |
| - | Object first(); //primul obiect din multime | + | Object first(); //primul obiect din mulțime |
| - | Object last(); // ultimul obiect din multime | + | Object last(); // ultimul obiect din mulțime |
| - | SortedSet subSet(Object from, Object to); // o submultime ordonata | + | SortedSet subSet(Object from, Object to); // copie ordonată a intervalului [from, to) |
| - | SortedSet headSet(Object to); // o submultime cu primele obiecte | + | SortedSet headSet(Object to); // copie ordonată a intervalului (primul_element, to) |
| - | SortedSet tailSet(Object from); //o submultime cu ultimele obiecte | + | SortedSet tailSet(Object from); copie ordonată a intervalului [from, ultimul_element) |
| + | SListSet reversed(); // întoarce o copie a mulțimii ordonată descrescător, construită pe baza comparatorului curent (dacă există) sau a ordinii naturale; populați exclusiv din elementele setului curent, fără recitirea fișierului și fără sortări/inversări externe. | ||
| </code> | </code> | ||
| </note> | </note> | ||
| - | Se vor defini cel puțin doi constructori: fără argumente (sortare conform ordinii naturale) și cu un argument de tip **//Comparator//**. | ||
| - | Să se folosească un obiect de tip **//SListSet//** pentru afișarea cuvintelor distincte dintr-un text citit dintr-un fișier text (//test01.txt//), în ordine crescătoare sau descrescătoare (în locul clasei **//TreeSet//** din problema 1). | ||
| - | ==== Problema 4 ==== | + | Se vor defini **doi constructori**: |
| - | Program pentru afișarea numerelor liniilor dintr-un fișier text în care apare fiecare cuvânt distinct. Se va folosi un dicționar cu liste de valori asociate fiecărei chei. Dicționarul va fi de tip **//TreeMap//**, iar listele vor fi de tip **//LinkedList//**. | + | * **SListSet()** - comparator == null, deci ordine naturală (necesită elemente Comparable); |
| + | * **SListSet(Comparator cmp**) - ordine definită de cmp. | ||
| - | Pentru afisare se va folosi un Iterator pe multimea intrarilor din dictionar. La afișare, fiecare cuvânt va începe pe o linie nouă și va fi urmat, pe liniile următoare, de lista numerelor liniilor în care apare. Pentru fiecare cuvânt în parte se va afișa la sfârșit numărul de apariții al acestuia. | + | Programul va folosi SListSet pentru a afișa cuvintele distincte dintr-un fișier text (//test1.txt//), în ordine crescătoare și în ordine descrescătoare, fără a apela sortări din afara colecției. Delimitarea cuvintelor este identică cu Problema 1. |
| - | Se poate folosi ca fisier de intrare tot fisierul test01.in din arhiva! | + | ==== Problema 4 ==== |
| + | Realizați un program care citește un fișier text și afișează, pentru **fiecare cuvânt distinct**, numerele liniilor în care apare și, la final, numărul total de apariții ale acelui cuvânt. Se va utiliza un **dicționar ordonat alfabetic** după cuvânt, implementat ca **TreeMap<String, LinkedList<Integer> >**: cheia este cuvântul, iar valoarea este lista numerelor de linie pentru **fiecare apariție** (dacă același cuvânt apare de mai multe ori pe aceeași linie, numărul liniei se repetă în listă). | ||
| - | <note tip> | + | Pentru afișare se va itera cu un **Iterator** peste mulțimea intrărilor dicționarului obținută prin **Map.entrySet()**. Pentru fiecare intrare, se va tipări **cuvântul** pe o linie separată urmat, pe liniile următoare, de lista numerelor de linie (în ordinea colectării), iar la final "Total: N", unde N este dimensiunea listei aferente cuvântului. Fiecare cuvânt începe pe o linie nouă. |
| - | Map - //**entrySet()**// | + | |
| + | Fișierul de intrare recomandat: test4.txt din arhivă. | ||
| - | Set - //**iterator()**// | ||
| - | </note> | ||
| ==== Problema 5 ==== | ==== Problema 5 ==== | ||
| - | Program pentru crearea și afișarea unui dicționar cu numele fișierelor dintr-un director împreună cu dimensiunea lor exprimată în kiloocteți (ca număr întreg). Numele reprezintă cheia, iar dimensiunea este valoarea asociată cheii. | + | Realizați un program care, pentru un director dat, construiește și afișează un dicționar cu **numele fișierelor** (cheia) și **dimensiunea lor** exprimată în kiloocteți (KiB) ca număr întreg (valoarea). Dicționarul se va construi **inițial** folosind HashMap<String, Integer>, apoi se va **reorganiza** într-un TreeMap<String, Integer> pentru afișarea alfabetică a numelor. Dimensiunea în KiB se calculează prin rotunjire în sus: KiB = (bytes + 1023) / 1024. |
| - | Programul va folosi succesiv clasele **//HashMap//** și **//TreeMap//**. | + | |
| - | Afișarea se va face atât în ordinea alfabetică a numelor cât și în ordinea dimensiunii fișierelor (două afișări). | + | Programul va produce două afișări separate: |
| + | * **în ordine alfabetică după nume** - folosind TreeMap (ordonarea naturală a cheilor String). | ||
| + | * î**n ordine descrescătoare după dimensiune** - obținută prin transformarea mulțimii de intrări (entrySet()) într-o listă și sortarea ei cu Collections.sort / List.sort după dimensiune (descrescător). | ||
| + | |||
| + | |||
| + | Pentru fiecare afișare, fiecare linie va conține numele fișierului urmat de dimensiunea în KiB (de ex.: readme.txt - 5 KiB). Programul primește calea directorului ca argument; dacă lipsește, se poate folosi directorul curent. | ||
| <note tip> | <note tip> | ||
| - | ''entrySet'' din ''Map'' transformă colecția în ''Set'' de intrari; | + | ''entrySet'' din ''Map'' transformă colecția în ''Set'' de intrări; |
| ''Collections.sort'' sortează o colectie după un criteriu definit. | ''Collections.sort'' sortează o colectie după un criteriu definit. | ||
| </note> | </note> | ||
| + | |||
| + | |||
| + | |||
| + | ==== Problema 6 ==== | ||
| + | Se cere realizarea unui program care implementează o **memorie cache cu capacitate fixă** și politică **LRU**: la depășirea capacității este eliminată intrarea folosită cel mai demult. "Folosire" înseamnă acces prin get (citire) sau put (inserare/actualizare). Implementarea se va baza exclusiv pe colecțiile standard Java. | ||
| + | |||
| + | Cache-ul va fi realizat ca o clasă **LruCache** care **extinde** **LinkedHashMap** în regim de //access-order// (ordonare după ultimul acces), prin apelarea constructorului potrivit și suprascrierea metodei removeEldestEntry. Eliminarea celui mai vechi element din punct de vedere al accesului trebuie să se producă automat imediat după o operație care ar face cache-ul să depășească capacitatea. | ||
| + | |||
| + | Programul citește dintr-un fișier text o **succesiune** de operații asupra cache-ului și afișează atât **rezultatul operațiilor de tip GET**, cât și **starea finală a cache-ului în ordinea LRU**. Fișierul conține câte o instrucțiune pe linie, în formatul: | ||
| + | * //PUT <cheie><valoare>// - inserează sau actualizează intrarea; la actualizare intrarea devine "cea mai recent folosită". | ||
| + | * //GET <cheie>// - afișează valoarea asociată sau NULL dacă lipsește; la acces reușit, intrarea devine "cea mai recent folosită". | ||
| + | * Liniile goale sau cele care încep cu # sunt ignorate. Cheile și valorile se tratează ca șiruri simple (fără spații în interior). | ||
| + | |||
| + | **Ordinea de afișare a cache-ului**: se iterează în ordinea //access-order// a LinkedHashMap (de la cea mai veche la cea mai recentă). Se tipărește câte o intrare pe linie, în forma //<cheie>=<valoare>//. Între rezultatele GET și listarea finală se afișează o linie separatoare //---//. | ||
| + | |||
| + | Programul primește două argumente din linia de comandă: **capacitatea** cache-ului (număr întreg strict pozitiv) și **calea fișierului de operații**. | ||
| + | |||
| + | Programul va conține următoarele elemente **obligatorii**: | ||
| + | * <code java> | ||
| + | // O clasă fără generics: | ||
| + | |||
| + | class LruCache extends LinkedHashMap { | ||
| + | public LruCache(int capacity) { ...} // seteaza access-order = true | ||
| + | protected boolean removeEldestEntry(Map.Entry eldest) { ... } // eliminare cand size() > capacity | ||
| + | } | ||
| + | |||
| + | // Cheile null sunt interzise (verificate în put). | ||
| + | |||
| + | // Capacity se memorează în obiect și este strict pozitiv. | ||
| + | </code> | ||
| + | |||
| + | |||
| + | * <code java> | ||
| + | // O metodă statică ce execută operațiile citite din fișier și returnează cache-ul: | ||
| + | |||
| + | public static LruCache runOps(String opsFile, int capacity) throws IOException {...} | ||
| + | |||
| + | // Citește fișierul, interpretează liniile în ordine, pentru GET afișează imediat rezultatul (valoare sau NULL). | ||
| + | |||
| + | // Ignoră liniile invalide (nu oprește programul). | ||
| + | </code> | ||
| + | |||
| + | |||
| + | * <code java> | ||
| + | // O metodă statică pentru afișarea stării curente a cache-ului în ordinea LRU: | ||
| + | |||
| + | public static void printCache(LruCache cache){...} | ||
| + | |||
| + | // Parcurge intrările cache.entrySet() și tipărește <cheie>=<valoare> pe linie. | ||
| + | </code> | ||
| + | |||
| + | |||
| + | În metoda main se validează argumentele, se apelează runOps(...), se afișează linia ---, apoi printCache(...). | ||
| + | |||
| + | <note tip> | ||
| + | Pentru fișierul de intrare din arhivă (capacitate 3, loadfactor 0.75), output-ul trebuie să fie: | ||
| + | |||
| + | <code java> | ||
| + | 1 | ||
| + | NULL | ||
| + | 3 | ||
| + | NULL | ||
| + | 30 | ||
| + | NULL | ||
| + | 5 | ||
| + | 6 | ||
| + | --- | ||
| + | C=30 | ||
| + | E=5 | ||
| + | F=6 | ||
| + | </code> | ||
| + | |||
| + | Explicația se găsește la fiecare pas în fișierul de intrare. | ||
| + | </note> | ||
| + | |||