Diferență între revizuiri ale paginii „SDA Lucrarea 2 Backup”

De la WikiLabs
Jump to navigationJump to search
m (Radu Hobincu a redenumit pagina SDA Lucrarea 2 în SDA Lucrarea 2 Backup fără a lăsa o redirecționare în loc)
 
(Nu s-au afișat 21 de versiuni intermediare efectuate de același utilizator)
Linia 1: Linia 1:
== Calcularea unui interval de timp ==
+
În acest laborator veți relua și recapitula noțiunile legate funcții recursive și citire și scriere din fișiere.
  
În Visual Studio 2013, următoarea funcție permite obținerea numărului de milisecunde care a trecut de la pornirea sistemului:
+
= Utilizarea fișierelor in C =
  
<syntaxhighlight lang="c">
+
Pentru a recapitula modurile de scriere și citire din fișiere în limbajul C, puteți recapitula [[PC Laborator 13]].
#include <windows.h>
 
  
unsigned long GetTickCount();
+
= Funcțiile recursive - Clasa de algoritmi ''Divide-et-impera'' =
</syntaxhighlight>
+
 
 +
Definirea și utilizarea funcțiilor recursive se pot recapitula citind [[PC Laborator 10]].
 +
 
 +
== Divide-et-impera ==
 +
 
 +
Clasa de algoritmi ''divide-et-impera'' se referă la algoritmii în care problema inițială se împarte în două probleme de același fel, în care datele de intrare nu se suprapun. Se rezolvă aceste două sub-probleme obținând două rezultate parțiale care apoi se combină pentru a obține rezultatul final.
 +
 
 +
Pașii de rezolvare a unei probleme folosind ''Divide-et-impera'':
 +
# Dacă problema este elementară, se întoarce direct rezultatul.
 +
# Se împarte problema inițială '''P''' (adică datele de intrare) în două probleme de același fel, '''P<sub>a</sub>''' și '''P<sub>b</sub>'''. În mod optim această împărțire se face exact la jumătate.
 +
# Se rezolvă problemele '''P<sub>a</sub>''' și '''P<sub>b</sub>''' (folosind eventual același algoritm) și se obțin două rezultate parțiale '''R<sub>a</sub>''' și '''R<sub>b</sub>'''.
 +
# '''R<sub>a</sub>''' și '''R<sub>b</sub>''' se combină într-un mod care ține de aplicație și se obține rezultatul final '''R'''.
 +
 
 +
De cele mai multe ori, algoritmii de tip ''divide-et-impera'' se implementează cu ajutorul funcțiilor recursive.
 +
 
 +
== Exemplu de algoritm și implementare ==
 +
 
 +
=== Cerință ===
 +
 
 +
Se cere să se scrie un algoritm divide-et-impera care să calculeze maximul unui vector de valori în virgulă mobilă.
 +
 
 +
=== Rezolvare ===
  
Pentru a calcula, de exemplu, cât durează apelul unei funcții ”test”, putem scrie următorul cod:
+
# Dacă vectorul are un singur element, se întoarce elementul respectiv.
 +
# Se împarte vectorul în două jumătăți egale (sau cel mult cu diferență de un element, dacă lungimea este impară).
 +
# Se calculează maximul fiecărei jumătăți folosind același algoritm.
 +
# Se calculează maximul global din maximul fiecărei jumătăți.
  
<syntaxhighlight lang="c">
+
Implementarea în C:
#include <windows.h>
+
<syntaxhighlight lang="C">
 +
#include <stdio.h>
 +
#include <stdlib.h>
  
void test();
+
float getMaximum (float * array, unsigned start, unsigned stop) {
 +
    if (start == stop) return array[start];
  
int main(){
+
    float max1 = getMaximum(array, start, (start + stop) / 2);
    unsigned long start;
+
     float max2 = getMaximum(array, (start + stop) / 2 + 1, stop);
    unsigned long finish;
 
   
 
    start = GetTickCount();
 
    test();
 
     finish = GetTickCount();
 
  
    printf("Functia test a rulat in %ld milisecunde.\n", finish - start);
+
     return max1 > max2 ? max1 : max2;
     return 0;
 
 
}
 
}
</syntaxhighlight>
 
  
== Exercițiul 1 ==
+
int main(){
 +
    unsigned size;
 +
    printf("size = ");
 +
    scanf("%u", &size);
 +
 
 +
    float *array = (float*)malloc(size * sizeof(float));
 +
    unsigned i;
 +
    for(i=0; i<size; i++) {
 +
        printf("array[%u] = ", i);
 +
        scanf("%f", &array[i]);
 +
    }
  
Scrieți o funcție care să citească un fișier text ce conține un număr '''n''', întreg, pozitiv, apoi '''n''' numere în virgulă mobilă. Funcția va sorta șirul de numere folosind algoritmul bubble-sort. Testați această funcție apelând-o în '''main'''.
+
    float max = getMaximum(array, 0, size - 1);
  
== Exercițiul 2 ==
+
    free(array);
  
Scrieți o funcție care are ca argument un singur număr întreg pozitiv '''n'''. Această funcție trebuie să genereze un fișier text ce va conține numărul '''n''' pe prima poziție, apoi '''n''' numere aleatoare în virgulă mobilă. Această funcție va apela apoi funcția de la exercițiul 1 și va contoriza timpul de execuție. La sfârșit se va afișa pe ecran timpul de rulare și numărul '''n'''.
+
    printf("Max is = %f\n", max);
 +
    return 0;
 +
}
 +
</syntaxhighlight>
  
== Exercițiul 3 ==
+
= Exerciții =
  
Realizați un program care să apeleze funcția de la exercițiul 2 cu numere întregi de la 1000 la 10000, din 1000 în 1000 (adică 1000, 2000, 3000,... 10000). Folosind timpul măsurat de execuție pentru fiecare dimensiune de vector de intrare, se va calcula complexitatea în timp a algoritmului.
+
* Grupa 1
 +
*# Definiți și implementați un algoritm ''divide-et-impera'' care să calculeze suma unui vector de elemente de tip întreg pe 16 biți citite din următoarele fișiere (prima valoare din fișier reprezintă numărul de valori) - atenție, rezultatul poate fi pe un număr foarte mare de biți:
 +
*#* [[Fișier:sda_lab2_ex1_1.txt]] - rezultatul corect este <code>55</code>
 +
*#* [[Fișier:sda_lab2_ex1_2.txt]] - rezultatul corect este <code>-63041</code>
 +
*#* [[Fișier:sda_lab2_ex1_3.txt]] - rezultatul corect este <code>-999712</code>
 +
*# Definiți și implementați un algoritm ''divide-et-impera'' care să calculeze produsul scalar între doi vectori de tip întreg pe 16 biți citite din următoarele fișiere (prima valoare din fișier reprezintă numărul de valori) - atenție, rezultatul poate fi pe un număr foarte mare de biți:
 +
*#* [[Fișier:sda_lab2_ex2_1.txt]] - rezultatul corect este <code>130</code>
 +
*#* [[Fișier:sda_lab2_ex2_2.txt]] - rezultatul corect este <code>-177671557</code>
 +
*#* [[Fișier:sda_lab2_ex2_3.txt]] - rezultatul corect este <code>732104297</code>
 +
*# Definiți și implementați un algoritm ''divide-et-impera'' care să calculeze media valorilor dintr-un vector de tip întreg pe 16 biți citite din următoarele fișiere (prima valoare din fișier reprezintă numărul de valori) - media se va reprezenta ca virgulă mobilă cu simplă precizie. Atenție și la vectorii cu dimensiune impară, unde media acestuia depinde de dimensiunile exacte ale jumătăților.
 +
*#* [[Fișier:sda_lab2_ex1_1.txt]] - rezultatul corect este <code>5.5</code>
 +
*#* [[Fișier:sda_lab2_ex1_2.txt]] - rezultatul corect este <code>-630.41</code>
 +
*#* [[Fișier:sda_lab2_ex1_3.txt]] - rezultatul corect este <code>-99.97</code>
 +
* Grupa 2
 +
*# Să se scrie un program care să afișeze cea mai mare diferența dintre elementele a doi vectori de valori întregi pe 64 de biți folosind un algoritm de tip <i>divide-et-impera</i>. Datele se vor citi din fișier. <br> <div> De exemplu pentru: <br> A = [0,1,2,3] <br>B = [5,6,9,10] <br> A[0] - B[0] = 0-5 = -5 <br> A[1] - B[1] = 1-6 = -5 <br> A[2] - B[2] = 2-9 = -7 <br> A[3] - B[3] = 3-10 = -7 <br><br> să afișeze -7 </div>
 +
* Grupa 3
 +
*# Să se scrie o funcție care să precalculeze într-un vector <code>bitCount</code> de întregi pe 8 biți fără semn, numărul de biți 1 din fiecare byte de la 0 la 255. <br> 0<sub>(10)</sub> = 00000000<sub>(2)</sub>, bitCount[0] = 0 <br> 1<sub>(10)</sub> = 00000001<sub>(2)</sub>, bitCount[1] = 1 <br> 2<sub>(10)</sub> = 00000010<sub>(2)</sub>, bitCount[2] = 1 <br> 3<sub>(10)</sub> = 00000011<sub>(2)</sub>, bitCount[3] = 2 <br>...<br> 255<sub>(10)</sub> = 11111111<sub>(2)</sub>, bitCount[255] = 8
 +
*# Să se scrie un program de tip ''Divide-et-impera'' care să citească un fișier oarecare și să calculeze numărul de biți 1 din acel fișier.
 +
* Grupa 4
 +
*# Folosind metoda ''Divide-et-impera'', scrieți o funcție care să determine dacă un vector cu elemente întregi pe 16 de biți fără semn este ordonat crescător.

Versiunea curentă din 8 martie 2017 11:58

În acest laborator veți relua și recapitula noțiunile legate funcții recursive și citire și scriere din fișiere.

Utilizarea fișierelor in C

Pentru a recapitula modurile de scriere și citire din fișiere în limbajul C, puteți recapitula PC Laborator 13.

Funcțiile recursive - Clasa de algoritmi Divide-et-impera

Definirea și utilizarea funcțiilor recursive se pot recapitula citind PC Laborator 10.

Divide-et-impera

Clasa de algoritmi divide-et-impera se referă la algoritmii în care problema inițială se împarte în două probleme de același fel, în care datele de intrare nu se suprapun. Se rezolvă aceste două sub-probleme obținând două rezultate parțiale care apoi se combină pentru a obține rezultatul final.

Pașii de rezolvare a unei probleme folosind Divide-et-impera:

  1. Dacă problema este elementară, se întoarce direct rezultatul.
  2. Se împarte problema inițială P (adică datele de intrare) în două probleme de același fel, Pa și Pb. În mod optim această împărțire se face exact la jumătate.
  3. Se rezolvă problemele Pa și Pb (folosind eventual același algoritm) și se obțin două rezultate parțiale Ra și Rb.
  4. Ra și Rb se combină într-un mod care ține de aplicație și se obține rezultatul final R.

De cele mai multe ori, algoritmii de tip divide-et-impera se implementează cu ajutorul funcțiilor recursive.

Exemplu de algoritm și implementare

Cerință

Se cere să se scrie un algoritm divide-et-impera care să calculeze maximul unui vector de valori în virgulă mobilă. 

Rezolvare

  1. Dacă vectorul are un singur element, se întoarce elementul respectiv.
  2. Se împarte vectorul în două jumătăți egale (sau cel mult cu diferență de un element, dacă lungimea este impară).
  3. Se calculează maximul fiecărei jumătăți folosind același algoritm.
  4. Se calculează maximul global din maximul fiecărei jumătăți.

Implementarea în C:

#include <stdio.h>
#include <stdlib.h>

float getMaximum (float * array, unsigned start, unsigned stop) {
    if (start == stop) return array[start];

    float max1 = getMaximum(array, start, (start + stop) / 2);
    float max2 = getMaximum(array, (start + stop) / 2 + 1, stop);

    return max1 > max2 ? max1 : max2;
}

int main(){
    unsigned size;
    printf("size = ");
    scanf("%u", &size);

    float *array = (float*)malloc(size * sizeof(float));
    unsigned i;
    for(i=0; i<size; i++) {
        printf("array[%u] = ", i);
        scanf("%f", &array[i]);
    }

    float max = getMaximum(array, 0, size - 1);

    free(array);

    printf("Max is = %f\n", max);
    return 0;
}

Exerciții

  • Grupa 1
    1. Definiți și implementați un algoritm divide-et-impera care să calculeze suma unui vector de elemente de tip întreg pe 16 biți citite din următoarele fișiere (prima valoare din fișier reprezintă numărul de valori) - atenție, rezultatul poate fi pe un număr foarte mare de biți:
    2. Definiți și implementați un algoritm divide-et-impera care să calculeze produsul scalar între doi vectori de tip întreg pe 16 biți citite din următoarele fișiere (prima valoare din fișier reprezintă numărul de valori) - atenție, rezultatul poate fi pe un număr foarte mare de biți:
    3. Definiți și implementați un algoritm divide-et-impera care să calculeze media valorilor dintr-un vector de tip întreg pe 16 biți citite din următoarele fișiere (prima valoare din fișier reprezintă numărul de valori) - media se va reprezenta ca virgulă mobilă cu simplă precizie. Atenție și la vectorii cu dimensiune impară, unde media acestuia depinde de dimensiunile exacte ale jumătăților.
  • Grupa 2
    1. Să se scrie un program care să afișeze cea mai mare diferența dintre elementele a doi vectori de valori întregi pe 64 de biți folosind un algoritm de tip divide-et-impera. Datele se vor citi din fișier.
      De exemplu pentru:
      A = [0,1,2,3]
      B = [5,6,9,10]
      A[0] - B[0] = 0-5 = -5
      A[1] - B[1] = 1-6 = -5
      A[2] - B[2] = 2-9 = -7
      A[3] - B[3] = 3-10 = -7

      să afișeze -7
  • Grupa 3
    1. Să se scrie o funcție care să precalculeze într-un vector bitCount de întregi pe 8 biți fără semn, numărul de biți 1 din fiecare byte de la 0 la 255.
      0(10) = 00000000(2), bitCount[0] = 0
      1(10) = 00000001(2), bitCount[1] = 1
      2(10) = 00000010(2), bitCount[2] = 1
      3(10) = 00000011(2), bitCount[3] = 2
      ...
      255(10) = 11111111(2), bitCount[255] = 8
    2. Să se scrie un program de tip Divide-et-impera care să citească un fișier oarecare și să calculeze numărul de biți 1 din acel fișier.
  • Grupa 4
    1. Folosind metoda Divide-et-impera, scrieți o funcție care să determine dacă un vector cu elemente întregi pe 16 de biți fără semn este ordonat crescător.