This shows you the differences between two versions of the page.
sd-ca:laboratoare:lab-03 [2020/03/12 14:43] serban_ioan.ciofu |
sd-ca:laboratoare:lab-03 [2025/03/18 16:23] (current) andrei.pirlea [Exerciții] |
||
---|---|---|---|
Line 3: | Line 3: | ||
Responsabili | Responsabili | ||
- | * [[mailto:amirea99@gmail.com|Adrian Mirea]] | + | * [[mailto:dragos.o.dragan@gmail.com|Dragos Dragan]] |
- | * [[mailto:alexcosmin.mihai@gmail.com|Alexandru Mihai]] | + | * [[mailto:marina@oprea.eu|Marina Oprea]] |
Line 15: | Line 15: | ||
===== LinkedList (conținut din laboratorul precedent) ===== | ===== LinkedList (conținut din laboratorul precedent) ===== | ||
- | O listă înlănțuită (LinkedList) reprezintă o structură de date liniară și omogenă. Spre deosebire de vector, lista înlănțuită nu își are elementele într-o zonă contiguă de memorie, ci fiecare element (nod al listei) va conține, pe langă informația utilă, și legătură către nodul următor (listă simplu înlănțuită), sau legături către nodurile vecine (listă dublu înlănțuită). Alocând dinamic nodurile pe măsură ce este nevoie de ele, practic se pot obține liste de lungime limitată doar de cantitatea de memorie accesibilă programului. | + | O listă înlănțuită (LinkedList) reprezintă o structură de date **liniară** și **omogenă**. Spre deosebire de vector, lista înlănțuită nu își are elementele într-o zonă contiguă de memorie, ci fiecare element (nod al listei) va conține, pe langă informația utilă, și legătură către nodul următor (listă simplu înlănțuită), sau legături către nodurile vecine (listă dublu înlănțuită). Alocând dinamic nodurile pe măsură ce este nevoie de ele, practic se pot obține liste de lungime limitată doar de cantitatea de memorie accesibilă programului. |
<note important> | <note important> | ||
Line 40: | Line 40: | ||
Asupra unei liste înlănțuite ar trebui să putem executa urmatoarele operații: | Asupra unei liste înlănțuite ar trebui să putem executa urmatoarele operații: | ||
- | * ''<nowiki>void add_nth_node(struct LinkedList* list, int n, void* new_data);</nowiki>'' adaugă pe poziția n în listă elementul ''new_data''. Adăugarea presupune modificarea câmpului ''next'' al nodului în urma căruia se va adăuga noul nod, cât și a câmpului ''next'' al nodului adăugat pentru a face legăturile necesare ca lista sa funcționeze corect. Dacă nodul este adăugat pe prima poziție, atunci el va deveni ''head''-ul listei, iar dacă este adăugat pe ultima poziție, el va deveni ''tail''-ul listei. //Complexitate: ''O(n)''. Dacă se adaugă elementul în capul sau coada listei, se obține o complexitate mai buna: ''O(1)''.// | + | * ''<nowiki>void add_nth_node(struct LinkedList* list, int n, void* new_data);</nowiki>'' - adaugă pe poziția n în listă elementul ''new_data''. |
+ | Adăugarea presupune: | ||
- | * ''<nowiki>struct Node* remove_nth_node(struct LinkedList* list, int n);</nowiki>'' șterge și întoarce al ''n''-lea element al listei. Operația presupune modificarea listei astfel încât între nodurile vecine celui eliminat să se refacă legaturile pentru a permite listei sa funcționeze în continuare. Daca nu există un nod următor, ''head'' va deveni NULL, iar lista va fi goală. Dacă nodul eliminat era ''head-ul'' listei, atunci succesorul său îi va lua locul. Analog pentru ultimul nod, însă în această situație, nodul precedent devine ''tail''. //Complexitate: ''O(n)''. Dacă se șterge primul nod, se obține o complexitate mai buna: ''O(1)''. Aceeași complexitate se obține și dacă lista este dublu înlănțuită și se șterge ultimul nod.// | + | 1) modificarea câmpului ''next'' al nodului în urma căruia se va adăuga noul nod |
- | * ''<nowiki>int get_size(struct LinkedList* list);</nowiki>'' întoarce numărul curent de elemente stocate în listă. //Complexitate: ''O(1)''// | + | 2) campul ''next'' al nodului adăugat pentru a face legăturile necesare ca lista sa funcționeze corect. |
+ | |||
+ | 3) Dacă nodul este adăugat pe prima poziție, atunci el va deveni ''head''-ul listei | ||
+ | |||
+ | 4) Dacă este adăugat pe ultima poziție, el va deveni ''tail''-ul listei. | ||
+ | |||
+ | //Complexitate: ''O(n)''. Dacă se adaugă elementul în capul sau coada listei, se obține o complexitate mai buna: ''O(1)''.// | ||
+ | |||
+ | * ''<nowiki>struct Node* remove_nth_node(struct LinkedList* list, int n);</nowiki>'' - șterge și întoarce al ''n''-lea element al listei. | ||
+ | |||
+ | Operația presupune: | ||
+ | |||
+ | 1) modificarea listei astfel încât între nodurile vecine celui eliminat să se refacă legaturile pentru a permite listei sa funcționeze în continuare | ||
+ | |||
+ | 2) Daca nu există un nod următor, ''head'' va deveni NULL, iar lista va fi goală. | ||
+ | |||
+ | 3) Dacă nodul eliminat era ''head-ul'' listei, atunci succesorul său îi va lua locul. Analog pentru ultimul nod, însă în această situație, nodul precedent devine ''tail''. | ||
+ | |||
+ | //Complexitate: ''O(n)''. Dacă se șterge primul nod, se obține o complexitate mai buna: ''O(1)''. Aceeași complexitate se obține și dacă lista este dublu înlănțuită și se șterge ultimul nod.// | ||
+ | |||
+ | * ''<nowiki>int get_size(struct LinkedList* list);</nowiki>'' - întoarce numărul curent de elemente stocate în listă. | ||
+ | |||
+ | //Complexitate: ''O(1)'' - DACA LISTA CONTINE CAMPUL SIZE IN STRUCTURA// | ||
+ | |||
+ | //Complexitate: ''O(n)'' - trebuie parcursa toata lista pentru a afla numarul de noduri // | ||
<note important> | <note important> | ||
Line 60: | Line 85: | ||
=== Listă liniară simplu înlănțuită === | === Listă liniară simplu înlănțuită === | ||
- | Prezentată în laboratorul precedent. | + | {{:sd-ca:playground:nod_lista_simplu_inlantuita.png?direct|}} |
=== Listă liniară dublu înlănțuită === | === Listă liniară dublu înlănțuită === | ||
Line 97: | Line 122: | ||
</code> | </code> | ||
- | Îmbinând informațiile despre listele circulare și particularitățile listei circulare simplu înlănțuite, putem reprezenta grafic o listă simplu înlănțuită astfel: | + | Îmbinând informațiile despre listele circulare și particularitățile listei circulare simplu înlănțuite, putem reprezenta grafic o listă circulară simplu înlănțuită astfel: |
{{:sd-ca:playground:lista_circulara_simplu.png?600|}} | {{:sd-ca:playground:lista_circulara_simplu.png?600|}} | ||
Line 113: | Line 138: | ||
</code> | </code> | ||
- | Îmbinând informațiile despre listele circulare și particularitățile listei circulare dublu înlănțuite, putem reprezenta grafic o listă simplu înlănțuită astfel: | + | Îmbinând informațiile despre listele circulare și particularitățile listei circulare dublu înlănțuite, putem reprezenta grafic o listă circulară dublu înlănțuită astfel: |
{{:sd-ca:playground:lista_circulara_dublu.png?600|}} | {{:sd-ca:playground:lista_circulara_dublu.png?600|}} | ||
===== Schelet ===== | ===== Schelet ===== | ||
- | {{:sd-ca:laboratoare:schelet_laborator03_circulardoublylinkedlist.zip|}} | + | <note important>Daca folositi **Github Classroom**, va rugam sa va actualizati scheletul cu cel de mai jos. Cel din repo-ul clonat initial nu este la cea mai recenta versiune.</note> |
+ | {{:sd-ca:laboratoare:sd-lab-03V2.zip|Scheletul de laborator}} | ||
===== Exerciții ===== | ===== Exerciții ===== | ||
+ | |||
<note> | <note> | ||
- | Fiecare laborator va avea unul sau doua exerciții publice și un pool de subiecte ascunse, din care asistentul poate alege cum se formeaza celelalte puncte ale laboratorului. | + | Trebuie să vă creați cont de [[https://beta.lambdachecker.io/ | Devmind]], dacă nu v-ați creat deja, pe care îl veți folosi la SD pe toată durata semestrului. Aveti grija sa selectati contestul corect la submit, si anume **[[https://beta.lambdachecker.io/contest/69/problems?page=1 | Laborator 3]]** |
</note> | </note> | ||
- | [**7p**] Implementaţi, plecând de la scheletul de cod, lista circulară dublu înlănțuită. | + | [**5p**] Implementaţi, plecând de la scheletul de cod, lista circulară dublu înlănțuită. (problema **Circular Doubly LinkedList** pe Devmind) |
- | + | ||
- | <hidden> | + | |
- | **311CAa** | + | |
- | + | ||
- | [**2p**] Implementați o funcție care primește ca parametru un pointer la începutul unei liste dublu înlănțuite sortată crescător și elimină nodurile cu valori duplicate (păstrând un singur nod din fiecare grup de duplicate). | + | |
- | + | ||
- | //Exemplu//: pentru lista //1 ⇔ 2 ⇔ 2 ⇔ 3 ⇔ 5 ⇔ 5 ⇔ 5 ⇔ 9// rezultă lista //1 ⇔ 2 ⇔ 3 ⇔ 5 ⇔ 9//. | + | |
- | </hidden> | + | |
- | + | ||
- | **311CAb** | + | |
- | + | ||
- | [**2p**] Implementați o funcție care primește ca parametru un pointer la începutul unei liste dublu înlănțuite și inversează ordinea nodurilor din listă (fără alocare de memorie auxiliară pentru o nouă listă). | + | |
- | + | ||
- | //Exemplu//: pentru lista //1 ⇔ 2 ⇔ 3// rezultă lista //3 ⇔ 2 ⇔ 1//. | + | |
- | + | ||
- | + | ||
- | <hidden> | + | |
- | **312CAa** | + | |
- | + | ||
- | [**2p**] Se dau două liste dublu înlănțuite, A și B, ale căror noduri stochează în ordine inversă cifrele câte unui număr natural reprezentat în baza 10 (primul nod al unei liste stochează cea mai puțin semnificativă cifră). Creați o nouă listă dublu înlănțuită, C, care stochează suma celor două numere. Lista C trebuie construită în timp ce se parcurg listele A și B! | + | |
- | + | ||
- | //Exemplu//: pentru listele //A: 4 ⇔ 3 ⇔ 2 ⇔ 9// și //B: 6 ⇔ 6 ⇔ 7//, va rezulta lista //C: 0 ⇔ 0 ⇔ 0 ⇔ 0 ⇔ 1//. | + | |
- | </hidden> | + | |
- | + | ||
- | **312CAb** | + | |
- | + | ||
- | [**2p**] Fiind date două liste dublu înlănţuite, A şi B, ale căror noduri stochează valori integer, construiţi o nouă listă dublu înlănţuită, C, pentru care fiecare nod i este suma nodurilor asociate din A şi B. Mai exact, nodul i din C reţine suma dintre valoarea nodului i din A şi valoarea nodului i din B. Dacă una dintre listele primite este mai lungă decât cealaltă, se consideră că nodurile asociate lipsă din cealaltă listă conţin valoarea 0, adică se păstrează valorile din lista mai lungă. | + | |
- | + | ||
- | //Exemplu//: pentru listele //A: 3 ⇔ 7 ⇔ 29 ⇔ 4// și //B: 2 ⇔ 4 ⇔ 3//, va rezulta lista //C: 5 ⇔ 11 ⇔ 32 ⇔ 4//. | + | |
- | + | ||
- | + | ||
- | **313CAa** | + | |
- | + | ||
- | [**2p**] Implementați o funcție care primește ca parametri doi pointeri la începuturile a două liste dublu înlănțuite sortate și întoarce o listă dublu înlănțuită sortată ce conține toate elementele din cele două liste. | + | |
- | + | ||
- | //Exemplu//: pentru listele //1 ⇔ 2 ⇔ 5 ⇔ 9// și //2 ⇔ 3 ⇔ 7 ⇔ 8 ⇔ 10// rezultă lista //1 ⇔ 2 ⇔ 2 ⇔ 3 ⇔ 5 ⇔ 7 ⇔ 8 ⇔ 9 ⇔ 10//. | + | |
- | + | ||
- | <hidden> | + | |
- | **313CAb** | + | |
- | + | ||
- | [**2p**] Se dă o listă dublu înlănţuită ale cărei noduri reţin valori de tip int şi, se dă de asemenea, un integer X. Reordonaţi nodurile din listă astfel încât toate nodurile cu valori mai mici sau egale decât X să apară înaintea nodurilor cu valori mai mari decât X. Nu alocaţi noduri noi! | + | |
- | + | ||
- | //Exemplu//: pentru lista //3 ⇔ 6 ⇔ 5 ⇔ 4 ⇔ 2// şi integer-ul //3//, o posibilă listă rezultat este //2 ⇔ 3 ⇔ 4 ⇔ 6 ⇔ 5//. | + | |
- | </hidden> | + | |
- | + | ||
- | <hidden> | + | |
- | **314CAa** | + | |
- | + | ||
- | [**2p**] Se dă o listă dublu înlănțuită ale cărei noduri stochează câte un caracter. Verificați dacă șirul de caractere stocat de lista dublu înlănțuită reprezintă un palindrom. Nu puteți să rețineți șirul în afara unei liste (de ex. nu aveți voie să parcurgeți lista și să stocați șirul la o adresă la care pointeză un char*). | + | |
- | + | ||
- | //Exemplu//: pentru lista //l ⇔ u ⇔ p ⇔ u ⇔ l//, rezultă ca este palindrom. | + | |
- | </hidden> | + | |
- | + | ||
- | **314CAb** | + | |
- | + | ||
- | [**2p**] Implementați o funcție care primește ca parametri un pointer la începutul unei liste dublu înlănțuite și șterge elementul aflat în mijlocul listei. Ștergerea trebuie să se facă printr-o singură parcurgere a listei. | + | |
- | + | ||
- | //Exemple//: | + | |
- | * pentru lista //vidă//, rezultă lista //vidă//; | + | |
- | * pentru lista //1//, rezultă lista //vidă//; | + | |
- | * pentru lista //1 ⇔ 2//, rezultă lista //2//; | + | |
- | * pentru lista //1 ⇔ 2 ⇔ 3//, rezultă lista //1 ⇔ 3//; | + | |
- | * pentru lista //1 ⇔ 2 ⇔ 3 ⇔ 4//, rezultă lista //1 ⇔ 3 ⇔ 4//; | + | |
- | * pentru lista //1 ⇔ 2 ⇔ 3 ⇔ 4 ⇔ 5//, rezultă lista //1 ⇔ 2 ⇔ 4 ⇔ 5//. | + | |
- | + | ||
- | **315CAa** | + | |
- | + | ||
- | [**2p**] Implementați o funcție care primește ca parametri un pointer la începutul unei liste dublu înlănțuite și un element și adaugă elementul în mijlocul listei. Adăugarea trebuie să se facă printr-o singură parcurgere a listei. | + | |
- | + | ||
- | //Exemple// (elementul adăugat este X): | + | |
- | * pentru lista //vidă//, rezultă lista //X//; | + | |
- | * pentru lista //1//, rezultă lista //X ⇔ 1//; | + | |
- | * pentru lista //1 ⇔ 2//, rezultă lista //1 ⇔ X ⇔ 2//; | + | |
- | * pentru lista //1 ⇔ 2 ⇔ 3//, rezultă lista //1 ⇔ X ⇔ 2 ⇔ 3//; | + | |
- | * pentru lista //1 ⇔ 2 ⇔ 3 ⇔ 4//, rezultă lista //1 ⇔ 2 ⇔ X ⇔ 3 ⇔ 4// | + | |
- | * pentru lista //1 ⇔ 2 ⇔ 3 ⇔ 4 ⇔ 5//, rezultă lista //1 ⇔ 2 ⇔ X ⇔ 3 ⇔ 4 ⇔ 5//. | + | |
- | + | ||
- | + | ||
- | **315CAb** | + | |
- | + | ||
- | [**2p**] Implementați o funcție care primește ca parametru un pointer la începutul unei liste dublu înlănțuite și întoarce o listă dublu înlănțuită obținută prin următoarea procesare a listei inițiale: între fiecare nod și succesorul său (din lista inițială) se introduce un nou nod, având ca valoare suma valorilor celor două noduri învecinate. | + | |
- | //Exemplu//: pentru lista //1 ⇔ 2 ⇔ 5 ⇔ 6 ⇔ 7 ⇔ 9// rezultă lista //1 ⇔ 3 ⇔ 2 ⇔ 7 ⇔ 5 ⇔ 11 ⇔ 6 ⇔ 13 ⇔ 7 ⇔ 16 ⇔ 9//. | + | [**2p**] Rezolvati problema desemnata grupei voastre. O veti gasi pe Devmind sub forma **SD-CA-LAB-03-GR-31XCA**. |
+ | <note important>**Important!** Problemele folosesc liste dublu inlantuite **liniare**, nu circulare!</note> | ||
Line 215: | Line 162: | ||
Această secțiune nu este punctată și încearcă să vă facă o oarecare idee a tipurilor de întrebări pe care le puteți întâlni la un job interview (internship, part-time, full-time, etc.) din materia prezentată în cadrul laboratorului. | Această secțiune nu este punctată și încearcă să vă facă o oarecare idee a tipurilor de întrebări pe care le puteți întâlni la un job interview (internship, part-time, full-time, etc.) din materia prezentată în cadrul laboratorului. | ||
- | - Implementați o funcție de ștergere a duplicatelor dintr-o listă dublu înlănțuită sortată. | ||
- Implementați o funcție de detectare (+ înlăturare) a unui ciclu într-o listă dublu înlănțuită. | - Implementați o funcție de detectare (+ înlăturare) a unui ciclu într-o listă dublu înlănțuită. | ||
+ | - Implementați o funcție care returneaza al k-lea element de la finalul listei, cu o singura parcurgere si fara sa stiti in prealabil dimensiunea listei. | ||
Și multe altele... | Și multe altele... | ||
Line 224: | Line 171: | ||
- [[https://visualgo.net/en/list | Linked list visualization]] | - [[https://visualgo.net/en/list | Linked list visualization]] | ||
- CLRS - //Introduction to Algorithms, 3rd edition//, capitol 10.2 - Linked lists | - CLRS - //Introduction to Algorithms, 3rd edition//, capitol 10.2 - Linked lists | ||
+ | - Cracking The Coding Interview - Chapter 2, Linked Lists |