Sunteți pe pagina 1din 12

Ministerul Educației, Culturii și Cercetării Republicii Moldova

Universitatea Tehnică a Moldovei

Departamentul Ingierie Software și Automatică

Raport
Disciplina Analiza și Proiectarea Algoritmilor
Tema: Metoda Divide et Impera

A îndeplinit: st.gr. TI-182 Damaschin Andrian

Chișinău-2019
Cuprins:

1. Scopul și sarcina lucrării………………………….………………………………3

2. Descrierea algoritmilor………………………………….………………………..4

3. Analiza empirică a rezultatelor……………………………………….…………..5

4. Concluzie…………………………………………………………………………7

Anexa A…………………………………………………………………………..8

Anexa B…………………………………………………………………………..14
1. Scopul și sarcina lucrării

1. Studierea metodelor divide et impera.


2. Analiza şi implementarea algoritmilor bazaţi pe metoda divide et impera.
Descrierea algoritmilor

1. Merge Sort:

Algoritmul de sortare implică trei etape:

şirul este împărţit până la jumătate în două subşiruri de lungimi egale (sau care diferă cu cel mult o unitate),
apoi prin recursivitate, cu subşirurile obţinute se procedează la fel, până ce subşirurile au lungime 1 sau cel
mult 2 elemente;
cele două subşiruri corespunzătoare ultimului apel recursiv sunt sortate;
subşirurile sortate se interclasează, prin revenirea din recursivitate reconstruindu-se treptat tot vectorul
iniţial sortat;
Dacă timpul de fuzionare de sortare pentru o listă cu lungimea n este T (n), atunci repetarea T (n) = 2T
(n / 2)+n.

Rezultă că în sortarea a n obiecte, Merge Sort are o performanță medie și cel mai rău caz de O (n log
n).

2. Quick Sort:
Pașii algoritmului:
1. Se alege un element al listei, denumit pivot
2. Se reordonează lista astfel încât toate elementele mai mici decât pivotul să fie plasate înaintea
pivotului şi toate elementele mai mari să fie după pivot. După această partiţionare, pivotul se află în
poziţia sa finală.
3. Se sortează recursiv sublista de elemente mai mici decât pivotul şi sublista de elemente mai mari
decât pivotul.

Algoritmul Quick Sort-ului ia complxitatea O (nlog(n)).


Analiza empirică a rezultatelor

Algoritmii Merge Sort și Quick Sort au fost analizați la introducerea a 100, 1000, 10000 și 100000
numere. Au fost prelucrate 3 cazuri: cazul favorabil (când toate numerele sunt aranjate în ordine
crescătoare), mediu (când numerele sunt ordonate random) și defavorabil (când numerele sunt aranjate în
ordine descrescătoare). În calitate de criteriu de comparare a fost ales timpul de execuție al algoritmilor.
Timpul a fost măsurat în microsecunde.

100 1000 10000

(Caz favorabil) Merge Sort 6594 522452 50292232


Ω
Quick Sort 5049 500499 49985005
Bubble Sort 5151 501501 50015001
(Caz mediu) Merge Sort 1443 20951 277231
Θ
Quick Sort 633 11752 172436

Bubble Sort 5151 501501 50015001

(Caz defavorabil) Merge Sort 6594 522452 50292232


O
Quick Sort 5049 500499 49945031

Bubble Sort 5151 501501 50015001

Caz favorabil
60000000

50000000

40000000

30000000

20000000

10000000

0
100 1000 10000

MergeSort QuickSort BubbleSort


Cazul mediu
60000000

50000000

40000000

30000000

20000000

10000000

0
100 1000 10000

MergeSort QuickSort BubbleSort

Cazul defavorabil
60000000

50000000

40000000

30000000

20000000

10000000

0
100 1000 10000

MergeSort QuickSort BubbleSort


Anexa A
Listingul programului

#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <time.h>
#include <chrono>
using namespace std::chrono;
using namespace std;

int itNr_m = 0;
int itNr_q = 0;

int a[100000], b[100000], c[100000];

int initData(int nr)


{

int v;
cout << "1. Caz favorabil" << endl;
cout << "2. Caz nefavorabil" << endl;
cout << "3. Random" << endl;
cin >> v;
if (v == 1) {
for (int i = 1; i <= nr; i++) {
a[i] = i;
}
}
else if (v == 2) {
nr = nr + 1;
for (int i = 1; i <= nr; i++) {
a[i] = nr - i;
}
}
else if (v == 3) {
for (int i = 1; i <= nr; i++) {
a[i] = rand() % nr + 1; ;
}
}
for (int i = 1; i <= nr; i++)
b[i] = a[i];
for (int i = 0; i <= nr; i++)
c[i] = a[i + 1];
}

int printArray(int arr[], int size)


{
int i;
for (i = 0; i < size; i++)
{
cout << a[i] << " " ;
}
}

void merge(int a[], int l, int m, int r)


{
int i, j, k, o;
int n1 = m - l + 1;
int n2 = r - m;

/* create temp arrays */


int b[n1], c[n2];

/* Copy data to temp arrays L[] and R[] */


for (i = 0; i < n1; i++)
b[i] = a[l + i];
for (j = 0; j < n2; j++)
c[j] = a[m + 1+ j];

/* Merge the temp arrays back into arr[l..r]*/


i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2)
{
if (b[i] <= c[j])
{
a[k] = b[i];
i++;

}
else
{
a[k] = c[j];
j++;
}
k++;
}

/* Copy the remaining elements of L[], if there


are any */
while (i < n1)
{
a[k] = b[i];
i++;
k++;

/* Copy the remaining elements of R[], if there


are any */
while (j < n2)
{
a[k] = c[j];
j++;
k++;

}
}

/* l is for left index and r is right index of the


sub-array of arr to be sorted */
void mergeSort(int a[], int l, int r)
{

if (l < r)
{
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m = l+(r-l)/2;

itNr_m++;
// Sort first and second halves
mergeSort(a, l, m);
mergeSort(a, m+1, r);
merge(a, l, m, r);
}

void swap(int* s, int* j)


{
itNr_q+=2;
int t = *s;
*s = *j;
*j = t;
}

/* This function takes last element as pivot, places


the pivot element at its correct position in sorted
array, and places all smaller (smaller than pivot)
to left of pivot and all greater elements to right
of pivot */
int partition (int a[], int low, int high)
{
int pivot = a[high]; // pivot
int i = (low - 1); // Index of smaller element

for (int j = low; j <= high- 1; j++)


{
// If current element is smaller than or
// equal to pivot
if (a[j] <= pivot)
{
i++; // increment index of smaller element
swap(&a[i], &a[j]);
}

}
itNr_q++;
swap(&a[i + 1], &a[high]);
return (i + 1);
}

/* The main function that implements QuickSort


arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(int a[], int low, int high)
{
if (low < high)
{
/* pi is partitioning index, arr[p] is now
at right place */
int pi = partition(a, low, high);
// Separately sort elements before
// partition and after partition
itNr_q++;
quickSort(a, low, pi - 1);
quickSort(a, pi + 1, high);

}
}

/*meniu function*/

void meniuPr()
{
int f, k, nr;
//chrono::time_point<std::chrono::system_clock> start, end;

cout << endl << endl << " Meniu " << endl;
cout << " 1. MergeSort" << endl;
cout << " 2. QuickSort" << endl;
cout << " 0. Exit " << endl;

cin >> f;

if (f == 1)
{
system("cls");
itNr_m = 0;
cout << "Enter the number of values you want to sort: " << endl;
cout << "1. 100" << endl << "2. 1000" << endl << "3. 10000" << endl << "4. 100000" <<
endl;
cin >> k;
if (k == 1)
{nr = 100;}
else if ( k == 2 )
{nr = 1000;}
else if (k == 3)
{nr = 10000;}
else if (k == 4)
{nr = 100000;}

system("cls");

cout << "Initial array: " << endl;


initData(nr);
//printArray(a, nr);
auto start = high_resolution_clock::now(); /*start measuring time*/
mergeSort(a , 0, nr - 1);
auto stop = high_resolution_clock::now();

auto duration = duration_cast<microseconds>(stop - start);


cout << endl << endl << "Sorted array with MergeSort: " << endl;
printArray (a, nr);
cout << endl << endl << "Nr of interations: " << itNr_m;
cout << endl << "Execution time: " << duration.count() << " milisec." << endl;
meniuPr();

return;
}
if (f == 2)
{
system("cls");
itNr_q = 0;
cout << "Enter the number of values you want to sort: " << endl;
cout << "1. 100" << endl << "2. 1000" << endl << "3. 10000" << endl << "4. 100000" <<
endl;
cin >> k;
system("cls");

if (k == 1)
{nr = 100;}
else if ( k == 2 )
{nr = 1000;}
else if (k == 3)
{nr = 10000;}
else if (k == 4)
{nr = 100000;}
//int size = 0;
initData(nr);
cout << "Initial array: " << endl;
//printArray(a, nr);
cout << endl << endl << "Sorted array with QuickSort: " << endl;
auto start = high_resolution_clock::now();
quickSort(a, 0, nr - 1);
auto stop = high_resolution_clock::now();
printArray (a, nr);
auto duration = duration_cast<microseconds>(stop - start);
cout << endl << endl << "Nr of interations: " << itNr_q;
cout << endl << "Execution time: " << duration.count() << " milisec." << endl;
meniuPr();
return;
}
if (f == 0)
{
system("cls");
cout << "You exited the program.";
return;
}
else
{ system("cls");
cout << "No such option. Try another one.";
meniuPr();
}

int main()
{

meniuPr();
}
Anexa B

Figura 1. Rezultatul execuției programului.

Concluzie

În cadrul lucrării de laborator nr. 2 au fost analizată tehnica de programare Divide et Impera pe exemplul
algoritmilor de sortare Merge Sort și Quick Sort.
Acești algoritmi au la bază tehnica Divide et Impera, adică ambii împart problema propusă în mai multe
subprobleme, le rezolvă și apoi le concatenează, astfel primind în rezultat problema inițial propusă
rezolvată. Pentru aceasta a fost creat un program care sortează șiruri de numere de diferite dimensiuni
(100, 1000, 10000, 100000) aranjate crescător, descrescător și random. În urma analei empirice a
algoritmilor, s-a determinat că mai efectiv în raport de timp este Merge Sort. Acesta sortează în
toate cazurile tablourile unidimensiionale de elemente într-un timp mai scurt decât Quick Sort.
Efectuînd lucrarea dată am implementat algoritmi de sortare, quicksort , mergesort si bubblesort, bazaţi
pe analizind timpul de executie al algoritmilor daţi.

S-ar putea să vă placă și