Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
pp:lheap [2019/04/01 12:38]
dmihai [Exerciții]
pp:lheap [2019/04/18 14:23] (current)
georgem [Exerciții]
Line 1: Line 1:
-====== ​TODO ======+====== ​Structuri funcționale de date ======
  
 Scopul laboratorului:​ Scopul laboratorului:​
   * recapitularea conceptelor învățate   * recapitularea conceptelor învățate
-  * programarea cu o structură funcțională+  * programarea cu o structură ​de date funcțională
   * înțelegerea conceptului de "​leftist heap"   * înțelegerea conceptului de "​leftist heap"
  
Line 17: Line 17:
   * ''​top''​ - returnează elementul cu prioritatea maximă   * ''​top''​ - returnează elementul cu prioritatea maximă
   * ''​delete''​ - scoate elementul cu prioritatea maximă din coadă   * ''​delete''​ - scoate elementul cu prioritatea maximă din coadă
 +
 +O altă operație utilă (și necesară în unele implementări) este ''​merge'',​ care primește două liste de priorități și le combină într-una singură.
  
 Coada de priorități este o structură abstractă, ce poate avea diverse implementări care diferă prin complexitatea diverselor operații (e.g. ''​insert'',​ ''​delete''​). Coada de priorități este o structură abstractă, ce poate avea diverse implementări care diferă prin complexitatea diverselor operații (e.g. ''​insert'',​ ''​delete''​).
Line 22: Line 24:
 Un exemplu naiv este implementarea unei cozi de priorități folosind o listă. Avem două posibilități:​ să introducem complexitatea determinării priorității în funcția ''​top'',​ sau în ''​insert''​. Un exemplu naiv este implementarea unei cozi de priorități folosind o listă. Avem două posibilități:​ să introducem complexitatea determinării priorității în funcția ''​top'',​ sau în ''​insert''​.
  
-Putem pune mereu un element la începutul listei (astfel ''​insert''​ e echivalent cu '':''​). Atunci când avem nevoie de cel cu prioritatea cea mai mare, pornim o căutare liniară prin elementele listei. Similar pentru ștergere. Avem astfel complexitățile:​+Putem pune mereu un element la începutul listei (astfel ''​insert''​ e echivalent cu '':''​). Atunci când avem nevoie de cel cu prioritatea cea mai mare, pornim o căutare liniară prin elementele listei. Similar pentru ștergere. Pentru operația de ''​merge''​ putem folosi append din Haskell (''​%%+%%%%+%%''​). Avem astfel complexitățile:​
  
 | Funcție | Complexitate | | Funcție | Complexitate |
Line 29: Line 31:
 | ''​top''​ | ''​O(n)''​ | | ''​top''​ | ''​O(n)''​ |
 | ''​delete''​ | ''​O(n)''​ | | ''​delete''​ | ''​O(n)''​ |
 +| ''​merge''​ | ''​O(n)''​ |
 +
 +<​note>​
 +''​n''​ este lungimea listei care stă la baza cozii. Pentru ''​merge'',​ ''​n''​ este lungimea listei din stânga.
 +</​note>​
  
-Alternativ, simplificând funcția ''​top'',​ ne asigurăm că elementele sunt mereu //​ordonate//​ în listă (astfel, ''​top''​ este echivalent cu ''​head''​). Inserarea unui element într-o listă ordonată se face în timp liniar. Avem astfel complexitățile:​+Alternativ, simplificând funcția ''​top'',​ ne asigurăm că elementele sunt mereu //​ordonate//​ în listă (astfel, ''​top''​ este echivalent cu ''​head''​). Inserarea unui element într-o listă ordonată se face în timp liniar ​(amintiți-vă de //insert sort//). Combinarea a două liste ordonate se face, deasemena în timp liniar (amintiți-vă de //merge sort//). Avem astfel complexitățile:​
  
 | Funcție | Complexitate | | Funcție | Complexitate |
Line 37: Line 44:
 | ''​top''​ | ''​O(1)''​ | | ''​top''​ | ''​O(1)''​ |
 | ''​delete''​ | ''​O(1)''​ | | ''​delete''​ | ''​O(1)''​ |
 +| ''​merge''​ | ''​O(n+m)''​ |
 +
 +<​note>​
 +Pentru ''​merge'',​ considerăm două liste cu dimensiunile ''​n'',​ respectiv ''​m''​.
 +</​note>​
  
 Implementarea cu liste nu este ideală și putem obține performanțe mai bune. Implementarea cu liste nu este ideală și putem obține performanțe mai bune.
 +
 ==== Binary Heap ==== ==== Binary Heap ====
  
 Un [[https://​en.wikipedia.org/​wiki/​Binary_heap|binary heap]] este un arbore binar cu următoarele două proprietăți:​ Un [[https://​en.wikipedia.org/​wiki/​Binary_heap|binary heap]] este un arbore binar cu următoarele două proprietăți:​
  
-  * pentru orice nod, valoarea asociată este **mai mare sau egală** cu valorile ​copiiilor +  * pentru orice nod, valoarea asociată ​acestuia ​este fie mai mare sau egală, fie mai mica sau egală ​cu valorile ​copiilor 
-  * arborele este [[https://​en.wikipedia.org/​wiki/​Binary_tree#​Types_of_binary_trees|complet]]:​ fiecare nivel este plin, cu excepția ultimului, pe care nodurile sunt cât mai la stânga+  * arborele este [[https://​en.wikipedia.org/​wiki/​Binary_tree#​Types_of_binary_trees|complet]]:​ fiecare nivel este plin, cu excepția ultimului, pe care nodurile sunt cât mai la stânga ​- acest lucru permite ca arborele să fie ținut într-un array. 
 + 
 +Pentru inserare se va introduce noul element la finalul array-ului. Noua valoare introdusă poate schimba locul cu părintele, în cazul în care prioritățile nu corespund (nu respectă ordinea impusă de noi). 
 + 
 +Această operație poartă diverse denumiri: ''​sift-up'',​ ''​percolate-up'',​ ''​cascade-up'',​ ... 
 + 
 +Pentru ștergere se va elimina primul element, se mută ultimul element din array ca nou "​varf"​ al arborelui, după care se va face swap între acesta și copilul cel mai mare/mic (în funcție de ordine). 
 + 
 +Acestă operație se numește: ''​sift-down'',​ ''​percolate-down'',​ ''​cascade-down'',​ ... 
 + 
 +Se poate observa că aceste operații ar fi greu de implementat într-un stil funcțional.
  
 ==== Leftist Heap === ==== Leftist Heap ===
  
-Un [[https://​en.wikipedia.org/​wiki/​Leftist_tree|leftist heap]] este +Un [[https://​en.wikipedia.org/​wiki/​Leftist_tree|leftist heap]] este o structură de date pur funcțională. 
 +În acest tip de heap se mai menține o informație și anume un rank. Acesta reprezintă distanța la cea mai apropiată frunză. 
 +Leftist heap-ul are următoarea proprietate:​ 
 +  * rank-ul oricărui subarbore stâng este cel puțin la fel de mare ca cel al subarborelui drept. ​
  
 +Leftist heap-ul utilizeză o operație generală de ''​merge''​ pentru a-și defini operațiile de ''​insert''​ și ''​delete''​.
 +
 +Astfel, un ''​insert''​ înseamnă crearea unui nou nod și apelarea funcției de ''​merge''​ pe ''​root''​ și pe acesta.
 +
 +Un ''​delete''​ se implementează prin eliminarea ''​root-ului''​ și apelarea funcției de ''​merge''​ pe copilul stâng și cel drept.
 +
 +[[https://​courses.cs.washington.edu/​courses/​cse326/​08sp/​lectures/​markup/​05-leftist-heaps-markup.pdf | Leftist heap - more info ]]
 +
 +Obținem complexitățile:​
 +
 +| Funcție | Complexitate |
 +| ''​isEmpty''​ | ''​O(1)''​ |
 +| ''​insert''​ | ''​O(log(n))''​ |
 +| ''​top''​ | ''​O(1)''​ |
 +| ''​delete''​ | ''​O(log(n))''​ |
 +| ''​merge''​ | ''​O(log(n))''​ |
  
 ===== newtype ===== ===== newtype =====
Line 143: Line 185:
   - Folosiți arbori binari pentru a implementa un leftist heap   - Folosiți arbori binari pentru a implementa un leftist heap
  
-<note tip> +{{:​pp:​laborator_6_-_schelet.zip|Lab 6 - Schelet}}\\ 
-Clasa ''​PQueue''​ conține unele funcții cu implementări default. Considerați înlocuirea acestora cu implementări particularizate+
-</​note>​+
 ===== Recommended Reading ===== ===== Recommended Reading =====