Sunteți pe pagina 1din 16

Ministerul Educaţiei al Republicii Moldova

Universitatea Tehnică a Moldovei

Specialitatea: Tehnologii Informaționale

RAPORT
Lucrare de laborator Nr.2
la Analiza şi proiectarea algoritmilor
Tema: Metoda divide et impera

A efectuat: st. gr. TI-171


Trili Diana

A verificat: Catruc Mariana

Chişinău 2019
▪ Tema: Metoda divide et impera

▪ Scopul lucrării:

1. Analiza empirică a algoritmilor.


2. Analiza teoretică a algoritmilor.
3. Determinarea complexităţii temporale şi asimptotice a algoritmilor

▪ Sarcina:
1. Studiaţi noţiunile teoretice despre metoda divide et impera.
2. Implementaţi algoritmii Mergesort şi Quicksort.
3. Efectuaţi analiza empirică a algoritmilor Mergesort şi Quicksort.
4. Faceţi o concluzie asupra lucrării efectuate.

▪ Listingul programului :
#include<iostream>
#include <array>
#include <time.h>
#include <string.h>
#include <ctime>

using namespace std;

class Sort{
private:

double sec = 0,sec2 = 0,sec3 = 0;


int swapCount,compCount;

public :
Sort() {
compCount = 0;
swapCount = 0;
}

//fuziunea
void merge(int a[], int low, int mid, int high, int dim){

int b[dim];
int i = low, j = mid + 1, k = 0;

while (i <= mid && j <= high)


compCount++;
if (a[i] <= a[j]){
b[k++] = a[i++];{
//dacă val i<j(a tab temp), plasăm val în tab permanent
swapCount++;
} else{
b[k++] = a[j++];
swapCount++;
}

}
while (i <= mid){
b[k++] = a[i++];
swapCount++;
}

while (j <= high){


b[k++] = a[j++];
swapCount++;
}

k--;
while (k >= 0) {
a[low + k] = b[k];
swapCount++;
k--;
}
}

void mergeSort(int a[], int low, int high,int dim){


if (low < high){
int m = (high + low)/2;
mergeSort(a, low, m,dim);
mergeSort(a, m + 1, high,dim);
merge(a, low, m, high,dim);//fuziunea
}
}

int partition(int a[],int low,int high){


int pivot = a[low];
swapCount++;

do{
while(low < high && a[high] >= pivot){
high--;
compCount++;
}
if(low < high){
a[low] = a[high];
swapCount++;
while(low < high && a[low] <= pivot){
low++;
compCount++;
}
if(low < high) {
a[high] = a[low];
swapCount++;
}
}
} while(low < high);

a[low] = pivot;
swapCount++;

return low;
}

void quickSort(int a[],int low,int high){


if(low < high){
int mid = partition(a,low,high);
quickSort(a,low,mid-1);
quickSort(a,mid+1,high);
}
}
void swap(int list[], int index1, int index2){

int temp = list[index1];

list[index1] = list[index2];

list[index2] = temp;
}

void superSort(int a[],int size) {

bool isSorted;

for (int i=0; i<size-1; i++) {


isSorted = true;
for (int j=0; j<size-i-1; j++) {
compCount++;
if (a[j+1] < a[j]) {
swap(a,j,j+1);
swapCount++;
isSorted = false;

}
}

if (isSorted) {
break;
}
}

void generateRandom(int a[],int size){


for (int i = 0; i< size; i++) {
a[i] = rand()%200;
}
}

void printArray(int A[], int size){


int i;
for (i=0; i < size; i++)
printf("%d ", A[i]);
printf("\n");

void invers(int a[],int size){


int temp;
for (int i = 0; i < size; ++i){
for (int j = i + 1; j < size; ++j){
if (a[i] < a[j]){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
void sortElementsArb(int *a,int size){

clock_t start, end;


a = new int[size];
int *b = new int[size];
int *c = new int[size];
generateRandom(a,size);
memcpy(b,a,sizeof(int)*size);
memcpy(c,a,sizeof(int)*size);
start = clock();
compCount = 0;
swapCount = 0;
mergeSort(a,0,size-1,size);
end = clock();
sec = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<size<<" items sorted"<<endl;
cout<<"MergeSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec<<endl<<endl;

start = clock();
compCount = 0;
swapCount = 0;
quickSort(b,0,size-1);
end = clock();
sec2 = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<"QuickSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec2<<endl<<endl;

start = clock();
compCount = 0;
swapCount = 0;
superSort(c,size);
end = clock();
sec3 = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<"SuperSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec3<<endl<<endl;

void sortElementsSort(int *a,int size){


clock_t start, end;
a = new int[size];
int *b = new int[size];
int *c = new int[size];
generateRandom(a,size);
invers(a,size);
quickSort(a,0,size-1);
compCount = 0;
swapCount = 0;
memcpy(b,a,sizeof(int)*size);
memcpy(c,a,sizeof(int)*size);
start = clock();
compCount = 0;
swapCount = 0;
mergeSort(a,0,size-1,size);
end = clock();
sec = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<size<<" items sorted"<<endl;
cout<<"MergeSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec<<endl<<endl;

start = clock();
compCount = 0;
swapCount = 0;
quickSort(b,0,size-1);
end = clock();
sec2 = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<"QuickSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec2<<endl<<endl;

start = clock();
compCount = 0;
swapCount = 0;
superSort(c,size);
end = clock();
sec3 = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<"SuperSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec3<<endl<<endl;

void sortElementsInv(int *a,int size){


clock_t start, end;
a = new int[size];
int *b = new int[size];
int *c = new int[size];
generateRandom(a,size);
invers(a,size);

memcpy(b,a,sizeof(int)*size);
memcpy(c,a,sizeof(int)*size);
start = clock();
compCount = 0;
swapCount = 0;
mergeSort(a,0,size-1,size);
end = clock();
sec = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<size<<" items sorted"<<endl;
cout<<"MergeSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec<<endl<<endl;

start = clock();
compCount = 0;
swapCount = 0;
quickSort(b,0,size-1);
end = clock();
sec2 = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<"QuickSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec2<<endl<<endl;
start = clock();
compCount = 0;
swapCount = 0;
superSort(c,size);
end = clock();
sec3 = (float)(end-start)/(CLOCKS_PER_SEC/1000);
cout<<"SuperSort: "<<endl;
cout<<"Number of comparisons: "<<compCount<<endl;;
cout<<"Number of swaps: "<<swapCount<<endl;
cout<<"Running time: "<<sec3<<endl<<endl;
}

};

int main(){

Sort sort;

int *tab;

cout<<" Tablou arbitrar:"<<endl;


sort.sortElementsArb(tab,10);
sort.sortElementsArb(tab,50);
sort.sortElementsArb(tab,100);
sort.sortElementsArb(tab,1000);
sort.sortElementsArb(tab,10000);
sort.sortElementsArb(tab,150000);

cout<<" Tablou sortat crescator:"<<endl;


sort.sortElementsArb(tab,10);
sort.sortElementsArb(tab,50);
sort.sortElementsArb(tab,100);
sort.sortElementsArb(tab,1000);
sort.sortElementsArb(tab,10000);
sort.sortElementsArb(tab,150000);

cout<<" Tablou sortat invers:"<<endl;


sort.sortElementsArb(tab,10);
sort.sortElementsArb(tab,50);
sort.sortElementsArb(tab,100);
sort.sortElementsArb(tab,1000);
sort.sortElementsArb(tab,10000);
sort.sortElementsArb(tab,150000);

return 0;
}

▪ Analiza rezultatelor:
1. Tabloul arbitrar:

2. Tabloul sortat crescător:


3. Tabloul sortat invers (descrescător):
▪ Analiza aprofundată a algoritmilor:

În cazul sortării prin interclasare(MergeSort) vectorii care se interclasează sunt două secvențe
ordonate din același vector. Sortarea prin interclasare utilizează metoda Divide et Impera:
- se împarte vectorul în secvențe din ce în ce mai mici., astfel încît fiecare secventă să fie
ordonată la un moment dat și interclasată cu o altă secventă din vector corespunzătoare.
- practic interclasarea va începe cînd se ajunge la o secvență formată din două elemente.
Aceasta odată ordonată se va interclasa cu o alta corespunzătoare. Cele două secvențe vor alcătui
în subșir ordonat din vector mai mare care la rîndul lui se va interclasa cu subșirul corespunzător.

Cazul mediu: O(N log N)


Cazul defavorabil: O(N log N)
Memorie folosita: O(N)
Stabil: DA
Sortare descrescatoare: b[i] >= a[j]
Sortare crescatoare: b[i] <= a[j]

Avantajele algoritmului:
− Aplicarea algoritmului asupra listelor înlănțuite;
− Perfect pentru sortarea datelor care sunt accesate secvențial;
− Poate fi aplicat asupra fișierelor de orice dimensiune.

Dezavantajele algoritmului:
− În majoritatea implementărilor, dacă lista are dimensiunea N, atunci necesită 2N memorie
pentru a manevra cu sortarea;
− Dacă este folosită recursia, atunci se utilizează de două ori mai multă memorie, în
comparație cu QuickSort.

Quick Sort este unul dintre cei mai rapizi și mai utilizați algoritmi de sortare pînă în acest
moment, bazîndu-se pe tehnica Divide et Impera. Deși cazul cel mai nefavorabil este O(N2), în
practică, QuickSort oferă rezultate mai bune decît restul algoritmilor de sortare din clasa
O(N log N).

Cazul mediu: O(N log N)


Cazul cel mai nefavorabil: O(N2)
Memorie folosită: O(log N)
Stabil: DA
Sortare descrescatoare: while(vector[min] > mijl) min++;
while(vector[max] < mijl) max--;
Sortare crescatoare: while(vector[min] < mijl) min++;
while(vector[max] > mijl) max--;

Avantajele algoritmului:
− Unul dintre cei mai eficienți algoritmi;
− Nu necesită memorie adițională(sortarea are loc în tablou).

Dezavantajele algoritmului:
− Cazul nefavorabil - O(N2).

Concluzie

În urma efectuării lucrării de laborator la tema: ”Metoda divide et impera”, am însușit


necesitatea utilizării și aplicării acestei metode, cît și eficiența algoritmilor incluși în metodă.
La fel am analizat mai profund algoritmii de sortare MergeSort și Quick Sort, în dependență de
timp, număr de comparații și de permutări. Din punct de vedere teoretic, ambii algoritmi au
complexitatea O(N log N), iar timpul utilizat pentru sortarea elementelor rămîne același.
Cu toate acestea, QuickSort este mai eficient decît MergeSort în ceea ce ține de spațiu.
QuickSort este algoritmul de sortare în tablou, astfel nu folosește memorie adițională pentru
sortare. La MergeSort, este utilizat un tablou temporar, astfel nu se observă aceeași metodă de
sortare ca în QuickSort.
Cu toate acestea eficiența timpului a QuickSort depinde de alegerea elementului pivot, adică cel
din mijloc.
Conform rezultatelor obținute și graficelor întocmite, conchidem că metoda mai eficientă de
sortare este QuickSort, deoarece timpul de execuție al algoritmului nu crește atît de rapid la
mărirea dimensiunii tabloului arbitrar, ceea ce nu putem spune despre MergeSort. La un număr
de 10000 de elemente MergeSort afișează un rezultat de 2.42 s, în timp ce QuickSort doar
1.917s.
Aceeași situație o putem urmări și în cazul tabloului sortat crescător, la un număr de 10000 de
elemente MergeSort afișează un rezultat de 2.107 s, în timp ce QuickSort doar 1.692s.
Iar în cazul tabloului sortat descrescător, la un număr de 10000 de elemente MergeSort afișează
un rezultat de 2.108 s, în timp ce QuickSort doar 1.722s.

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