Table of Contents

Tema 3 - Biblioteca

Responsabili:

Deadline soft: 28 aprilie, ora 23:55

Depunctare întârziere după depășirea deadline-ului soft: -10p/zi

Deadline hard: 1 mai, ora 23:55

Changelist:

Introducere

Fiind aproape de terminarea anului I de facultate, dornici sa ne afirmam si sa ne testam cunostintele acumulate pana acum, acceptam sa participam intr-un proiect de modernizare a unei biblioteci.

In prima faza a proiectului, cea de documentare si intelegere a cerintelor clientului, aflam de la directorul institutiei urmatoarele:

  1. se doreste o metoda de indexare a fiecarei carti intr-un format electronic, astfel incat operatiile de gestiune a volumelor sa fie simple, rapide, moderne, sigure etc. (operatia PUT)
  2. majoritatea cautarilor in baza de date a bibliotecii nu se realizeaza dupa numele cartilor ci dupa continut astfel incat este nevoie de o metoda rapida de cautare, tinand cont de volumul mare de carti. Practic, date niste cuvinte cheie (ce se afla in continutul cartilor) trebuie sa se gaseasca numele cartilor ce le contin. (operatia GET)
  3. multi clienti organizeaza competitii unu-la-unu pe baza cartilor citite astfel: primul alege numele cartii, iar oponentul sau scrie o lista de cuvinte continute in acea carte. In cazul in care nu a gresit niciun cuvant (toate cuvintele mentionate se gasesc in carte), acesta acumuleaza un punctaj egal cu numarul de cuvinte scrise, si 0p altfel. Dupa un numar prestabilit de runde, se desemneaza castigatorul: persoana cu cele mai multe puncte acumulate! Deoarece partea de verificare a cuvintelor este foarte costisitoare manual, se doreste implementarea in aplicatia electronica si a acestei functionalitati. Formal, dat un nume de carte si o lista de cuvinte, sa se determine daca toate cuvintele se afla in acea carte. (operatia PLAY)

Detalii implementare

Dându-se ca input o serie de comenzi, fiecare comanda specifica aplicatiei: PUT, GET sau PLAY, se doreste generarea unui output cu raspunsurile corespunzatoare. Atat fomatele comenzilor cat si a raspunsurilor sunt detaliate in continuare.

Input

Input-ul constă dintr-o insiruire de comenzi, fiecare pe cate o linie. Citirea se realizeaza pana la intalnirea caracterului de sfarsit de fisier EOF.

comanda1
comanda2
...

Tipurile de comenzi (detaliate ulterior):

Comanda PUT

Sintaxa comenzii PUT este:

      PUT titlu_carte  cuv1 cuv2 .. cuvN

Rolul acestei comenzi este de a indexa conținutul cărții titlu_carte si anume: cuv1 cuv2 .. cuvN, astfel încât la orice căutare ulterioara de cuvinte apartinand cartii, aceasta să fie printre rezultatele găsite.

Această comandă se poate reprezenta în două moduri:

În tema voastră, va trebui să implementați cea de-a doua tehnică de reținere a informațiilor, cea în care într-un hashtable se rețin asocieri de tipul cuvânt - listă de carti.

Astfel dacă se dau la input următoarele 3 comenzi:

PUT titlu_carte1 cand rasare soarele
PUT titlu_carte2 afara este soarele
PUT titlu_carte3 cand mergem afara

Hashtable-ul după aceste 3 comenzi va arăta în felul următor:

Observații comandă PUT:

Comanda GET

Sintaxa comenzii GET este:

    GET cuv1_interogare cuv2_interogare .. cuvN_interogare

Această comandă va întoarce toate cărțile în care apar toți termenii interogării. De exemplu, pentru următoarele interogări:

Observații comandă GET:

Intrucât va trebui să afisați toate cărțile care conțin toți termenii interogării, va trebui să găsiți o metodă de intersecție rapidă (eficienta).

Comanda PLAY

Sintaxa comenzii PLAY este:

   PLAY titlu_carte cuv1_concurent cuv2_concurent .. cuvN_concurent
   

Această comandă verifică dacă toți termenii din interogarea: cuv1_concurent cuv2_concurent .. cuvN_concurent există în cartea titlu_carte. Dacă toți termenii există în carte, atunci se va afișa YOU_WIN, iar dacă nu, se va afișa YOU_LOSE.

Exemplu: INPUT:

PLAY titlu_carte1 soarele cand
PLAY titlu_carte3 mergem bal

OUTPUT:

YOU_WIN
YOU_LOSE

Observații generale INPUT

Observații generale timpi

Hashtable

Pentru implementarea eventualelor structuri de date de tip hashtable din temă, puteți pleca de la implementarea din Laboratorul 6, bazată pe vector de liste înlănțuite. Evident, elementele din dictionar sunt de tipul (cheie, valoare). In cazul temei, valoare va fi reprezentat sub forma unui vector std::vector<std::string> in care veti mentine lista cartilor in care se gaseste cuvantul din cheie. Pentru a optimiza cautarea in acest vector va trebui sa mentineti acest vector sortat lexicografic si sa optimizati cautarea in vector folosind un algoritm specific acestei proprietati (de sortare).

Pentru a putea efectua tema, trebuie să țineți cont de următoarele observații:

In cadrul temei este obligatorie setarea dimensiunii initiale a dictionarului la valoarea 16 si setarea factorului de incarcare la valoarea 0.7, pentru ca toate implementarile voastre sa faca acelasi numar de redimensionari.

Următorul exemplu vă va ajuta să înțelegeți cum se redimensionează un hashtable:

Înainte:

După redimensionare:

Explicații:

Schelet de Cod

Aveti la dispoziție un schelet de cod, care realizează citirea și parsarea comenzilor. Acesta va scuteste de efortul de a implementa partea nefunctionla a temei. Scheletul de cod se gaseste aici: 3-biblioteca_schelet

Nu este obligatorie folosirea acestui schelet de cod.

Exemple

Input Output
PUT titlu_carte1 cand rasare soarele
PUT titlu_carte3 cand mergem
GET mergem titlu_carte3
PLAY titlu_carte1 cand rasare YOU_WIN
PLAY titlu_carte1 ana are YOU_LOSE
PLAY titlu_carte3 mergem YOU_WIN
PUT titlu_carte3 afara soarele
GET cand soarele titlu_carte1 titlu_carte3
PUT titlu_carte2 afara este soarele
GET afara titlu_carte2 titlu_carte3
GET afara titlu_carte2 titlu_carte3
GET cand mergem titlu_carte3
GET temaSD BOOK_NOT_FOUND

Așa cum observați, pentru claritate răspunsul comenzilor GET/PLAY a fost pus pe rândul corespunzător din tabel, lăsând câte o linie goală pentru fiecare comandă PUT, dar voi NU trebuie să lăsați nicio linie goală. Pentru mai multe detalii, consultați checkerul disponibil.

Așa cum am amintit și în secțiunea corespunzătoare comenzii GET, cărțile sunt afișate în ordine alfabetică.

Bonus

Bucurosi ca am finalizat cu succes cea de-a doua faza a proiectului, anume implementarea corecta a bibliotecii virtuale, dorim sa aflam cum functioneaza aplicatia, “in mediul real”. Contactandu-l pe director, acesta ne spune ca lucrurile stau mult mai bine acum: gestiunea cartilor este mult usurata, clientii s-au obisnuit cu folosirea aplicatiei si a crescut numarul de competitii datorita simplificarii verificarilor. Insa, exista si o mica problema recenta, neprevazuta la inceputul proiectului: din cauza numarului mare de carti, si a numarului mare de interogari: GET/PLAY, aplicatia este destul de lenta. Deoarece momentan nu exista fonduri suficiente pentru achizitionarea unor echipamente hardware dedicate si nici de upgrade-uri la cele existente, acesta ne propune o prima pentru optimizarea (software) a aplicatiei.

Cerinta bonus

Optimizati aplicatia din punct de vedere a timpului de rulare, pastrand implemetarea si algoritmul folosit in tema, astfel incat sa respecte timeout-urile noi (setate in checker, la sectiunea bonus). Pentru indeplinirea cerintei, este obligatoriu sa pastrati algoritmul si structura descrisa in cerinta temei. Scopul bonusului este scrierea corecta si eficienta a codului. Cateva sfaturi in acest sens ar fi:

std::vector<T> a, b;
//fill a with many elements
b = a; //realizeaza o copiere (duplicare a tuturor elementelor din a)
std::vector<int> intVect;
for (int i = 0; i < 10000; ++i)
    intVect.push_back(i);
// In acest caz, in vector se aloca un element nou, pentru fiecare apel push_back. 
// Apelul de alocare este unul costisitor.
// Chiar mai ineficient este cazul cand, din lipsa posibilitatii alocarii
// unui element nou in continuarea elementelor vectorului, se copiaza toate elementele
// intr-un spatiu continuu suficient de mare. Acest proces poate sa apara, in cel mai
// defavorabil caz, la fiecare alocare.

    
// Solutie:
std::vector<int> intVect;
intVect.reserve(10000);
for (int i = 0; i < 10000; ++i)
    intVect.push_back(i);
// In acest caz se va face o alocare de 10000 elemente o singura data (la inceput)
// dupa care nu va mai fi nevoie de nicio realocare.

Trimitere și punctare

Temele vor trebui trimise pe vmchecker. Atenție! Temele trebuie trimise în secțiunea Structuri de Date (CA).

Arhiva trebuie să conțină:

Punctare:

Timpul de rulare/test: Există un timp de rulare specific pentru fiecare test, astfel încât să fie verificat că implementați bine operațiile hashtable si ca respectati optimizarile precizate in cerinta. Acesti timpi sunt specifici rularii temei pe vmchecker si nu rularii temei local, unde este posibil sa obtineti timpi diferiti (mai buni). Timpul de rulare/test considerat va fi numai cel de pe vmchecker.

Pentru alte detalii legate de punctare citiți Regulamentul General de Trimitere a Temelor.

Checker

Puteți descărca checker-ul, cu testele publice aferente, de aici: 3-biblioteca_checker_v2

Link-uri extra

* Un post scurt despre interted index @google + video

FAQ

Q: Se poate folosi STL?

R: Puteți folosi clasele std::vector, std::list și std::string pentru a reține cuvintele, titlurile cartilor etc. De asemenea, in general este recomandat sa folositi iteratorii nativi structurii, precum std::vector<T>::iterator in C++, acestia fiind mai eficienti in parcurgerea structurilor (iterabile). Vedeti exemple de utilizare in scheletul de cod.