Differences

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

Link to this comparison view

sda-aa:laboratoare:02 [2021/02/28 23:31]
127.0.0.1 external edit
sda-aa:laboratoare:02 [2021/03/09 18:11] (current)
cristian.rusu [4. Exercitii]
Line 1: Line 1:
-===== Laboratorul 1: Alocare dinamica, structuri ​=====+===== Laboratorul 1: Algoritmi de sortare ​=====
  
-==== Obiective ===== 
-În urma parcurgerii acestui laborator studentul va fi capabil: 
-  * să aloce dinamic o zonă de memorie; 
-  * să elibereze o zonă de memorie; 
-  * să lucreze cu vectori și matrice alocate dinamic. 
  
-Structura ​laboratorului ​se gaseste in **[[http://​gooogle.com|acest link.]]**+==== 1. Obiectivele ​laboratorului ​==== 
 +  ​Calculul complexitatii algoritmilor 
 +  ​Implementarea unor algoritmi de sortare
  
-===== 1. Alocare dinamică ===== 
  
-Funcțiile standard de alocare și eliberare a memoriei sunt declarate în biblioteca //<​stdlib.h>//:  +==== 2Calculul complexitatii algoritmilor ====
-  * void* malloc(size_t ); +
-  * void* calloc(size_t , size_t ); +
-  * void* realloc(void *, size_t ); +
-  * void free(void*)+
  
-**Alocarea memoriei**+=== A. Introducere ===
  
-Funcția **malloc** ​are drept rezultat adresa zonei de memorie alocate (de tipul void) și ca argument, dimensiunea zonei de memorie ​alocate, exprimate în octețiDacă există suficient spatiu liber in HEAP, atunci un bloc de memorie continuu de dimensiunea specificată va fi marcat ca ocupat, iar funcția malloc va returna un pointer ce conține adresa deînceput a acelui bloc. Dacă nu există spațiu pentru a se face alocarea, funcția malloc întoarce NULL. Accesarea blocului alocat se realizează printr-un pointer către adresa de început a blocului+Analiza complexitatii unui algoritm ​are ca scop estimarea volumului ​de resurse ​de calcul necesare pentru executia algoritmului. Prin resurse se intelege: 
 +   Spatiul ​de memorie ​necesar pentru stocarea datelor pe care le prelucreaza algoritmul. 
 +   * Timpul necesar pentru executia tuturor prelucrarilor specificate ​in algoritm.
  
-**Exemplu ​malloc** +Aceasta analiza este utila pentru a stabili daca un algoritm utilizeaza un volum acceptabil de resurse pentru rezolvarea unei probleme. In acest fel timpul de executie va fi exprimat prin numarul de operatii elementare executate. Sunt considerate operatii elementare cele aritmetice (adunare, scadere, inmultire, impartire), comparatiile si cele logice (negatie, conjuncte si disjunctie). 
-<code > + 
-char *str malloc(10);            // Aloca memorie pentru ​10 de caractere +Este asadar suficient sa se contorizeze doar anumite tipuri de operatii elementare, numite operatii de baza. Timpul de executie al intregului algoritm se obtine insumand timpii de executie ai prelucrarilor componente. 
-int *a = malloc(sizeof(int)); // Aloca memorie pentru ​numere intregi+ 
 + 
 +**Exemplul 1 Suma a n numere** 
 + 
 + 
 +Consideram problema calculului sumei. Dimensiunea acestei probleme poate fi considerata n. Algoritmul si tabelul cu costurile corespunzatoare prelucrarilor sunt prezentate in Tabel. Insumand timpii de executie ai prelucrarilor elementare se obtine: $T(n)=n(c_3 + c_4 + c_5) + c_1 + c_2 + c_3$ deci $T(n)=k_1n + k_2$, adica timpul de executie depinde liniar de dimensiunea problemei. Costurile operatiilor elementare influenteaza doar constantele ce intervin in functia $T(n)$. 
 + 
 +{{:​sda-ab:​laboratoare:​complexitati1.png?​600|}} 
 + 
 +**Exemplul 2 - inmultirea a 2 matrici** 
 + 
 +Consideram problema determinarii produsului a doua matrici: A de dimensiune $m \times n$ si B de dimensiune $n \times p$. In acest caz dimensiunea problemei este determinata de trei valori: $(m, n, p)$. 
 + 
 +In practica nu este necesara o analiza atat de detaliata ci este suficient sa se identifice operatia dominanta si sa se estimeze numarul de repetari ale acesteia. Prin operatie dominanta se intelege operatia care contribuie cel mai mult la timpul de executie a algoritmului si de regula este operatia ce apare in ciclul cel mai interior. in exemplul ar putea fi considerata ca operatie dominanta, operatia de inmultire. In acest caz costul executiei algoritmului ar fi $T(m, n, p)=mnp$. 
 + 
 +{{:​sda-ab:​laboratoare:​complexitati2.png?​600|}} 
 + 
 + 
 + 
 +=== B. Caracterizarea unui algoritm === 
 + 
 +Numim sortare orice asezare(sau - mai clar - reasezarea unor elemente date in asa fel incat, dupa asezare, sa existe o ordine completa in functie de un atribut(numit cheie) al elementelor. 
 + 
 +Pentru a exista o ordine completa, trebuie sa alegem o relatie pe care vrem sa o impunem. Daca relatia este valabila intre oricare doua elemente pentru care primul element este asezat la stanga celui de-al doilea, atunci avem o ordine completa. 
 + 
 +Exemplu: daca alegem drept cheie un atribut numar intreg si relatia mai mic sau egal, obtinem ordinea crescatoare. 
 + 
 +Vom descrie un algoritm de sortare prin: 
 +   * timp mediu - timpul de executie la care ne asteptam, in medie, pentru sortare 
 +   * timp la limita- timpul de executie pentru cel mai rau caz posibil 
 +   ​* ​memorie ​- memoria maxima de care are nevoie algoritmul ​pentru ​sortare(excludem memoria deja alocata inainte ​de algoritm → vectorul efectiv ce va fi sortat) 
 +   ​stabilitate - un algoritm stabil pastreaza ordinea in care apar doua elemente cu aceeasi cheie(atributul dupa care sortam) 
 + 
 +Folosim notatia O(n) pentru ​indica: 
 +   * un numar de operatii de ordinul lui n. in acest caz, spunem ca avem „complexitate de timp de ordinul lui n“ 
 +   * o dimensiune de ordinul lui n pentru memoria alocata. in acest caz, spunem ca avem „complexitate de spatiu de ordinul lui n“ 
 + 
 + 
 + 
 +==== 3. Implementarea unor algoritmi de sortare ==== 
 + 
 +In acest curs ati vazut deja algoritmi de sortare precum 
 +   * Bubble sort - interschimbare 
 +   * Selection sort - selectie 
 +   * Insertion sort - inserare 
 +   * Merge sort - interclasare 
 +   * Quick sort - partitionare 
 + 
 +=== A. Bubble sort === 
 + 
 +Caracteristici:​ 
 +   * timp mediu: O(N^2) 
 +   timp la limita: O(N^2) 
 +   * memorie: O(1) 
 +   * Stabil: DA 
 + 
 +**Descriere:​** 
 +Sortarea prin metoda bulelor se considera drept una din cele mai putin efective metode de sortare, dar cu un algoritm mai simplu. 
 + 
 +Ideea de baza a sortarii prin metoda bulelor este in a parcurge tabloul, de la stanga spre dreapta, fiind comparate elementele alaturate a[i] si a[i+1]. Daca vor fi gasite 2 elemente neordonate, valorile lor vor fi interschimbate. 
 +Parcurgerea tabloului de la stanga spre dreapta se va repeta atat timp cat vor fi intalnite elemente neordonate. 
 + 
 +{{:​sda-aa:​laboratoare:​bubble-sort-example-300px.gif?​300|}} 
 + 
 + 
 +**Implementarea:​** 
 +<code C> 
 +//sortare descrescatoare 
 +void bubble(int a[],int n) 
 +
 +    int i,​schimbat,​aux; 
 +    do { 
 +        schimbat = 0; 
 +        ​// parcurgem vectorul 
 +        for(i = 0; i < n-1; i++) { 
 +     // daca valoarea i din vectorul a este mai mica decat cea de pe pozitia i+1 
 +            if (a[i] < a[i+1]) {  
 +                // interschimbare 
 +         aux = a[i]; 
 + a[i] = a[i+1]; 
 + a[i+1] = aux; 
 + schimbat = 1; 
 +     } 
 +        } 
 +    } while(schimbat);​ 
 +}
 </​code>​ </​code>​
  
  
-Funcția **free** are drept argument o adresă (un pointer) și eliberează zona de la adresa respectivă 
  
-Funcția **calloc**; dacă există suficient spațiu liber în HEAP, atunci un bloc de memorie continuu va fi marcat ca ocupat, iar funcția calloc va returna un pointer ce conține adresa de început a acelui bloc+=== B. Selection sort ===
  
-**Exemplu ​calloc** +Caracteristici:​ 
-<code > +   timp mediu: O(N^2) 
-int *v;    +   timp la limita: O(N^2) 
-int n=3+   * memorie: O(1) 
-v=(int*)calloc(n,sizeof(int)); // Aloca spațiu pentru n=3 întregi șîi inițializez cu 0+   * Stabil: DA 
 + 
 +**Descriere:​** 
 +Acest algoritm selecteaza, la fiecare pas i, cel mai mic element din vectorul nesortat(de la pozitia i pana la n). Valoarea minima gasita la pasul i este pusa in vector la pozitia i, facandu-se intereschimbarea cu pozitia actuala a minimului. Nu este un algoritm indicat pentru vectorii mari, in majoritatea cazurilor oferind rezultate mai slabe decat insertion sort si bubble sort. 
 + 
 +{{:​sda-aa:​laboratoare:​selection-sort.gif?​300|}} 
 + 
 + 
 +**Implementarea:​** 
 +<​code ​C
 +void selectionSort(int a[],int n) 
 +{ 
 + int i,​j,​aux,​min,​minPoz;​ 
 + for(i = 0; i < - 1;i++) 
 +
 + minPoz ​i
 + min a[i]; 
 + for(j = i + 1;j < n;j++//selectam minimul 
 + //din vectorul ramasde la i+1 la n
 +
 + if(min > a[j]//sortare crescatoare 
 +
 + minPoz = j; //pozitia elementului minim 
 + min ​a[j]; 
 +
 +
 + aux = a[i] ; 
 + a[i] = a[minPoz]; //​interschimbare 
 + a[minPoz] = aux; 
 +
 +}
 </​code>​ </​code>​
  
-Funcția **realloc** ​ void * realloc( void *p, int dim ); dacă există suficient spațiu în HEAP, atunci un bloc de memorie continuu cu dimensiunea dim specificată va fi marcat ca ocupat. AStfel, funcția realloc returnează un pointer ce conține adresa de început a acelui bloc. Se copiază la noua locație conținutul blocului inițial și se eliberează memoria de la vechea adresă. ​ 
  
-<note important>​Dacă nu există suficient spațiu liber, realloc întoarce NULL, iar pointerul inițial rămâne nemodificat.</​note>​ 
  
 +=== C. Insertion sort ===
 +
 +Caracteristici:​
 +   * timp mediu: O(N^2)
 +   * timp la limita: O(N^2)
 +   * memorie: O(1)
 +   * Stabil: DA
 +
 +**Descriere:​**
 +Spre deosebire de alti algoritmi de sortare, sortarea prin insertie este folosita destul de des pentru sortarea tablourilor cu numar mic de elemente. De exemplu, poate fi folosit pentru a imbunatati rutina de sortare rapida.
 +
 +   * Sortarea prin insertie seamana oarecum cu sortarea prin selectie. Tabloul este impartit imaginar in doua parti - o parte sortata si o parte nesortata. La inceput, partea sortata contine primul element al tabloului si partea nesortata contine restul tabloului.
 +   * La fiecare pas, algoritmul ia primul element din partea nesortata si il insereaza in locul potrivit al partii sortate.
 +   * Cand partea nesortata nu mai are nici un element, algoritmul se opreste.
 +
 +{{:​sda-aa:​laboratoare:​insertion-sort-example-300px.gif?​300|}}
 +
 +
 +**Implementarea:​**
 +<code C>
 +void insertionSort(int a[], int n)
 +{
 +    int i, j, aux;
 +    for (i = 1; i < n; i++)
 +    {
 +        j = i;
 +        while (j > 0 && a[j - 1] > a[j])
 +        { //cautam pozitia pe care sa mutam a[i]
 +            aux = a[j]; //​interschimbare
 +            a[j] = a[j - 1];
 +            a[--j] = aux;
 +        }
 +    }
 +}
 +</​code>​
 +
 +
 +
 +=== D. Merge sort ===
 +
 +Caracteristici:​
 +   * timp mediu: O(N log N)
 +   * timp la limita: O(N log N)
 +   * memorie: O(N)
 +   * Stabil: DA
 +
 +**Descriere:​**
 +in cazul sortarii prin interclasare,​ vectorii care se interclaseaza sunt doua secvente ordonate din acelasi vector. Sortarea prin interclasare utilizeaza metoda Divide et Impera:
 +   * se imparte vectorul in secvente din ce in ce mai mici, astfel incat fiecare secventa sa fie ordonata la un moment dat si interclasata cu o alta secventa din vector corespunzatoare.
 +   ​* ​
 +   * practic, interclasarea va incepe cand se ajunge la o secventa formata din doua elemente. Aceasta, odata ordonata, se va interclasa cu o alta 
 +corespunzatoare(cu 2 elemente). Cele doua secvente vor alcatui un subsir ordonat din vector mai mare(cu 4 elemente) care, la randul lui, se va interclasa cu un subsir corespunzator(cu 4 elemente) s.a.m.d.
 +
 +{{:​sda-aa:​laboratoare:​merge-sort-example-300px.gif?​300|}}
 +
 +
 +
 +=== E. Quick sort ===
  
 +Caracteristici:​
 +   * timp mediu: O(N log N)
 +   * timp la limita: O(N^2)
 +   * memorie: O(log N)
 +   * Stabil: NU
  
 +**Descriere:​**
 +Quick Sort este unul dintre cei mai rapizi si mai utilizati algoritmi de sortare pana in acest moment,​bazandu-se pe tehnica „Divide et impera“. Desi cazul cel mai nefavorabil este O(N^2), in practica, QuickSort ofera rezultate mai bune decat restul algoritmilor de sortare din clasa „O(N log N)“.
  
 +Algoritmul se bazeaza pe urmatorii pasi:
 +   * alegerea unui element pe post de pivot
 +   * parcurgerea vectorului din doua parti(de la stanga la pivot, de la dreapta la pivot, ambele in acelasi timp)
 +   * interschimbarea elementelor care se afla pe „partea gresita“ a pivotului(mutam la dreapta pivotului elementele mai mari, la stanga pivotului elementel mai mici)
 +   * divizarea algoritmului:​ dupa ce mutam elementele pe „partea corecta“ a pivotului, avem 2 subsiruri de sortat, iar pivotul se afla pe pozitia buna.
  
  
  
-===== 2Structuri de date =====+==== 4Exercitii ​====
  
-O structură de date reprezintă ​un mod de a organiza și stoca o colecție de date; pentru ​a facilita manipularea elementelor din colecție este recomandată sortarea colecțieiÎn funcție ​de modul în care sunt organizate elementele, se pot identifica: +  - Alegeti ​un algoritm A (dintre Bubble, Insertion si Selection) si un algoritm B (dintre Merge si Quick). Introduceti niste variabile globale cu care sa contorizati numarul ​de comparatii ​pentru ​algoritmii A si BComparati rezultatele pentru un vector ​de intregi de lungime n = 20. 
-  - Structuri ​de date **liniare**: ​   +  - Implementati un algoritm (dintre Bubble, Insertion si Selection) pentru sortarea unui vector cu n cuvinte ​de maxim 4 litere fiecare. 
-                        * **Tablouri** ​elemente stocate în locații succesive de memorie la care se știe adresa primului element +  Implementati un algoritm ​(dintre Merge si Quickpentru sortarea unui vector ​de structuri, unde fiecare structura reprezinta un moment de timp(int ora, min, sec). 
-                        * **Liste** - elemente stocate în locații nesuccesive de memorie +  - Se da un vector ​de n intregi, iar toate valorile din vector sunt intre 0 si 1000. Sortati vectorul in timp O(n).
-                        * **Stive** - elemente stocate în locații nesuccesive de memorie la care se aplică principiul LIFO (Last In First Out- ultimul element adăugat este primul procesat +
-                        * **Cozi** - elemente stocate în locații nesuccesive ​de memorie la care se aplică principiul FIFO (First In First Out- primul element adăugat este primul procesat +
-  - Structuri ​de date **neliniare**:​ +
-                        * **Arbori** - favorizează păstrarea unor colecții de elemente sub formă ierarhică în stare sortată +
-                        * **Grafuri** - favorizează conexiunile dintre elemente ​+
  
-<​hidden>​Aici vom insera codul sursa cu linkul de pe Github. Ruben a venit cu propunerea sa lasam aici link catre GitHub care sa fie activ doar pe saptamana ​in care trebuie sa incarce ei laboratorul</​hidden>​+**Nota:** Implementati toti algoritmii ​in fisiere separate (.c si .h) si apoi apelati-le din main.c
sda-aa/laboratoare/02.1614547919.txt.gz · Last modified: 2021/03/01 15:19 (external edit)
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0