Sunteți pe pagina 1din 17

Universitatea Tehnica a Moldovei

Catedra Automatica si Tehnologii Informationale

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

A efectuat :

st. gr. TI-

A verificat:
Bagrin Veronica

Chisinau 2012
Scopul lucrrii:
1

1 Studierea metodei divide et impera.


2 Analiza i implementarea algoritmilor bazai pe metoda divide et impera.
Indicaii teoretice:
Divide et impera se bazeaz pe principiul descompunerii problemei n dou sau mai multe subprobleme (mai u oare),
care se rezolv, iar soluia pentru problema ini ial se ob ine combinnd solu iile subproblemelor. De multe ori,
subproblemele sunt de acelai tip i pentru fiecare din ele se poate aplica aceea i tactic a descompunerii n (alte)
subprobleme, pn cnd (n urma descompunerilor repetate) se ajunge la probleme care admit rezolvare imediat.
Nu toate problemele pot fi rezolvate prin utilizarea acestei tehnici. Se poate afirma c numrul celor rezolvabile prin
"divide et impera" este relativ mic, tocmai datorit cerinei ca problema s admit o descompunere repetat.
Divide et impera este o tehnic ce admite o implementare recursiva. Principiul general prin care se elaboreaz
algoritmi recursivi este: "ce se ntmpl la un nivel, se ntmpl la orice nivel" (avnd grij s asigurm condi iile de
terminare). Aadar, un algoritm prin divide et impera se elaboreaz astfel: la un anumit nivel avem dou posibilit i:
1. s-a ajuns la o problem care admite o rezolvare imediat (condi ia de terminare), caz n care se rezolv i se
revine din apel;
2. nu s-a ajuns n situaia de la punctul 1, caz n care problema curent este descompus n (dou sau mai multe)
subprobleme, pentru fiecare din ele urmeaz un apel recursiv al func iei, dup care combinarea rezultatelor
are loc fie pentru fiecare subproblem, fie la final, naintea revenirii din apel.
Metoda mergesort
Aceasta metoda de ordonare are la baza interclasarea a doi vectori: fiind dati doi vectori ordonati se obtine un al treilea
vector ordonat care va contine elementele din cei doi vectori.
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. Cele doua secvente vor alcatui in subsir ordonat din vector mai mare care la
randul lui se va interclasa cu subsirul corespunzator samd.
Fie vectorul:
8

17

17

16

Se imparte in doua secvente:


8

In continuare pt prima secvente se procedeaza la fel:


8

Dupa o noua impartire se obtine:


8

Se incepe interclasarea. Se considera ca avem doi vectori de lungime 1 care se interclaseaza:


2

16

8
Rezulta:

La fel si pentru secventa :


9

Se considera ca avem iar doi vectori de lungime 1 care se interclaseaza:


9

Rezulta:
3

Ceea ce inseamna ca cele doua secvente determina obtinerea urmatorului subsir din vector:
7

Pentru care se interclaseaza cele doua zone. Rezulta:


3

La fel se procedeaza si cu secventa:


6

17

16

Se obtine:
6
4
Care se interclaseaza si se obtine:
4

La fel pentru:
17
16
Se obtine:
16
17
Se obtine o noua secventa:
4

16

17

Care prin interclasarea celor doua zone conduce la:


4
6
16
17
Cele doua secvente initiale din vector au devenit:
3

16

17

16

17

Care se interclaseaza obtinand:


3

Analiza algoritmului MERGESORT


In sortarea cu n obiecte , merge sort are o performata medie si cel mai rau caz (n*log(n)). Daca timpul de executie
pentru sortarea merge sort cu lungimea de n elemente este T(n), atunci repetarea T(n) = 2T(n/2) + n, rezulta din
definitia de algoritm (se aplica algoritmul doua liste de dimensiunea jumate din lista intitiala si adauga n pasi pentru
imbinarea rezultatului a doua liste).
T(n) = 2T(n/2) + n
n=2^k;
t(2^k)=2T(2^(k-1))+2^k
tk=2t(k-1)+2^k
tk-2t(k-1)=2^k
(x-2)(x-2)=0
R1,2=2
Tk=C1*2^k+C2*2^k*k
K=log(n)
tn=C1*2log(n)+C2*log(n)*log(n)
tn=C1*n+C2*n*log(n)
T(n)=O(n*log(n)
In cel mai rau caz algoritmul de sortarea merge sort efectueaza cu aproximatic 39% comparatii mai putin decit
algoritmul de sortare quick sort in cazul mediu. Merge sort mereu efectueaza comparatii mai putine decit quick
sort cu exceptii foarte rare atunci cind merge sort are cazul cel mai nefavorabil si quick sort cel mai favorabil
caz.
In termeni de miscari merge sort are complexitatea O(n*log (n)), fiind la fel ca complexitatea quick sort in cel
mai bun caz. In cel mai bun caz algoritmul merge sort efectueaza de 2 ori mai putine iteratii decit in cel mai rau caz.
QUICKSORT(sortarea rapida)
Sortarea rapida este un algoritm de sortare care, pentru un sir de n elemente, are un timp de executie O(n^2), in cazul
cel mai defavorabil. In ciuda acestei comportari proaste, in cazul cel mai defavorabil, algoritmul de sortare rapida este
deseori cea mai buna solutie practica, deoarece are o comportare medie remarcabila: timpul sau mediu de executie este
O(n log2 n), si constanta ascunsa in formula O(n log2 n) este destul de mica. Algoritmul are avantajul ca sorteaza pe
loc (in spatiul alocat sirului de intrare) si lucreaza foarte bine chiar si intr-un mediu de memorie virtuala.
Algoritmul contine si un subalgoritm important, folosit de sortarea rapida pentru partitionare.
Algoritmul de sortare rapida, ca de altfel si algoritmul de sortare prin interclasare, se bazeaza pe paradigma divide si
stapaneste
Descrierea algoritmului este urmtoarea:

Mai jos este prezentat cum lucreaza algoritmul:

Analiza algoritmului QUICKSORT


Timpul de execuie al algoritmului de sortare rapid depinde de faptul c partiionarea este echilibrata sau nu, iar
acesta din urm de elementele alese ca pivot pentru partiionare. Daca partiionarea este echilibrata, algoritmul este
la fel de rapid ca sortarea prin interclasare. n cazul n care partiionarea nu este echilibrat, algoritmul se executa la
fel de ncet ca sortarea prin inserare. n aceasta seciune vom investiga, fr rigoare matematica, performana
algoritmului de sortare rapid n cazul partiionrii echilibrate.
Partitionarea in cazul cel mai defavorabil.
Comportarea cea mai defavorabil a algoritmului de sortare rapid apare n situaia n care procedura de partiionare
produce un vector de n-1 elemente i unul de 1 element.

Arborele de recursivitate pentru Quicksort cnd procedura Partiie pune ntotdeauna ntr-o parte a vectorului numai un
singur element (cazul cel mai defavorabil). Timpul de execuie n acest caz este O(n^2).
Partitionarea in cazul cel mai favorabil.
Daca algoritmul de partiionare produce doi vectori de n/2 elemente, algoritmul de sortare rapid lucreaz mult mai
repede.

Arborele de recuren pentru Quicksort cnd procedura Partiie produce ntotdeauna pari egale (cazul cel mai
favorabil). Timpul de execuie rezultat este O(n log2 n).
Costul total al algoritmului de sortare rapid este deci O(n log2 n). Ca urmare, cu o partiionare n proporie de 9 la 1
la fiecare nivel al partiionrii (care intuitiv pare a fi total dezechilibrata), algoritmul de sortare rapid are un timp de
execuie de O(n log2 n) asimptotic acelai ca n cazul partiionrii n dou pari egale. De fapt, timpul de execuie va
fi O(n log2 n) i n cazul partiionrii ntr-o proporie de 99 la 1. La orice partiionare ntr-o proporie constanta,
adncimea arborelui de recursivitate este O(log2 n) i costul, la fiecare nivel, este O(n). Deci timpul de execuie este
O(n log2 n) la orice partiionare ntr-o proporie constant.

Bubble-Sort
Considerm tabloul A cu 5 elemente numere reale: 0.0, 1.1, 1.0, 1.2 i 0.08. Prima parcurgere a tabloului (ok este
iniializat cu adevrat):

a1 = 0.0
a2 = 1.1

0.0

0.0

1.0

1.0

a3 = 1.0

a4 = 1.2

a5 = 0.08

ok

1.1

1.2

0.08

fals

1.2

fals

1.1

0.08

Valorile 0.0 < 1.1, rmn neschimbate, 1.1 > 1.0, le interschimbm. Deoarece 1.1 < 1.2, avansm i constatm
c 1.2 > 0.0.8, deci din nou avem interschimbare. n consecin, la ieire din structura
pentru ok este fals. Observm c 1.2 a ajuns pe locul lui definitiv. Urmeaz a doua parcurgere a tabloului
(ok primete din nou valoarea adevrat).

a1 = 0.0
a2 = 1.0

0.0

1.0

a3 = 1.1

0.08

a4 = 0.08

a5 = 1.2

ok

1.1

1.2

fals

Am avut interschimbare i de data aceasta, deci ieim cu ok = fals. La acest pas 1.1 a ajuns pe locul su definitiv.
A treia parcurgere a tabloului ncepe cu reiniializarea lui ok cu valoarea adevrat.

a1 = 0.0
a2 = 1.0

0.0

a3 = 0.08

a4 = 1.1

a5 = 1.2

ok

1.0

1.1

1.2

fals

0.08

Am interschimbat 0.08 cu 1.0, cel din urm astfel a ajuns pe locul su n irul ordonat. A patra parcurgere a
tabloului se finalizeaz cu valoarea ok = adevrat, deoarece nu am efectuat nici o interschimbare, ceea ce
nseamn c procesul de ordonare s-a ncheiat.

a1 = 0.0
a2 = 0.08

a3 = 1.0

a4 = 1.1

a5 = 1.2

ok

0.08

1.0

1.1

1.2

adevrat

0.0

Mergesort:
Listingul programului
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int * sort(int stinga[], int dreapta[], int lS, int lD);
int * Imparte(int a[], int lungime);
void MergeSort(int * a, int nrElemente);
int contor = 0;
int main()
{
srand(time(0));
int * a, nrE;
clock_t start, sfirsit;
cout << "Introduceti nr de elemente: ";
cin >> nrE;
a = new int[nrE];
for (int i = 0; i < nrE; i++)
{
a[i] = 0 + rand() % ((15000 + 1) - 0);
}
cout<<endl<<"Marimea tabelului este:"<<endl;
for (int i=0;i<nrE;i++)
{
cout<<a[i]<<" ";
}
start = clock();
MergeSort(a, nrE);
sfirsit = clock();
cout<<endl<<"Tabelul sortat este: \n"<<endl;
for (int i=0;i<nrE;i++)
{
cout << a[i]<<" ";
7

}
cout << "\nTimpul de executie: " << (sfirsit - start) / CLOCKS_PER_SEC << " sec." << endl;
cout << "Nr de iteratii: " << contor << endl;
delete [] a;
cin.get();
cin.get();
return 0;
}
void MergeSort(int * a, int nrElemente)
{
int * x = Imparte(a, nrElemente);
for (int i = 0; i < nrElemente; i++)
{
a[i] = x[i];
}
delete [] x;
}
int * Imparte(int a[], int lungime)
{
if (lungime <= 1)
{
return a;
}
int * stinga, * dreapta;
int jumatate = lungime / 2;
stinga = new int[jumatate];
dreapta = new int[lungime - jumatate];
for (int i = 0; i < jumatate; i++)
{
stinga[i] = a[i];
}
for (int i = jumatate; i < lungime; i++)
{
dreapta[i - jumatate] = a[i];
}
stinga = Imparte(stinga, jumatate);
dreapta = Imparte(dreapta, lungime - jumatate);
int * x = sort(stinga, dreapta, jumatate, lungime - jumatate);
delete [] stinga;
delete [] dreapta;
return x;
}
int * sort(int stinga[], int dreapta[], int lS, int lD)
{
int * rezultat = new int[lS + lD];
int indS = 0, indD = 0, indR = 0;
while(lS > 0 || lD > 0)
{
if (lS > 0 && lD > 0)
{
if (stinga[indS] <= dreapta[indD])
{
contor++;
rezultat[indR++] = stinga[indS++];
lS--;
8

}
else
{
rezultat[indR++] = dreapta[indD++];
lD--;
}
}
else if (lS > 0)
{
contor++;
rezultat[indR++] = stinga[indS++];
lS--;
}
else if (lD > 0)
{
contor++;
rezultat[indR++] = dreapta[indD++];
lD--;
}
}
return rezultat;
}

Rezultatul executiei:

QUICKSORT:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include<time.h>
using namespace std;
int contor=0;
void sort_rapida(int tablou[], int prim, int ultim)
{
int temp, min, max, separator_lista;
min=prim;
max=ultim;
separator_lista=tablou[(prim+ultim)/2];
do
{
while(tablou[min] < separator_lista)
{
min++;
}
while(tablou[max] > separator_lista)
{
contor++;
max--;
}
if(min<=max)
{
10

contor++;
temp=tablou[min];
tablou[min++]=tablou[max];
tablou[max--]=temp;
}
}while(min<=max);
if(prim<max)
{
contor++;
sort_rapida(tablou, prim, max);
}
if(min<ultim)
{
contor++;
sort_rapida(tablou, min, ultim);
}
}
int main()
{
time_t start,end;
double dif;
int val[19000], i=0, n=0;
cout<<"Introduceti numarul de elemente: ";
cin>>n;
cout<<endl<<"Marimea tabloului este: "<<endl;
for(i=0; i<n; i++)
{
val[i]=rand()%100;
cout<<val[i]<<' ';
}
time (&start);
cout<<endl;
sort_rapida(val, 0, n);
time (&end);
dif = difftime (end,start);
cout<<endl<<"Tabloul sortat: "<<endl;
for(i=1; i<=n; i++)
{
cout<<val[i]<<' ';
}
cout<<endl;
printf("timp de executie: %.2lf secunde\n\n",dif);
cout<<endl<<"Numarul de iteratii este: "<<contor<<endl;
getch();
return 0;
}

11

Rezultatul executiei:

12

Bubble-Sort:
#include <iostream>
#include<stdlib.h>
#include<time.h>
using namespace std;
int contor=0;
int main()
{
time_t start,end;
double dif;
int v[100000],i,n,gasit,aux;
cout<<"Introduceti numarul n= ";cin>>n;
for(i=1;i<=n;i++)
{
v[i]=rand()%100;
cout<<v[i]<<" ";
}
time (&start);
do
{
gasit=0;
for(i=1;i<=n;i++)
if(v[i]>v[i+1])
{
contor++;
aux=v[i];
v[i]=v[i+1];
v[i+1]=aux;
gasit=1;
}
time (&end);
dif = difftime (end,start);
}
while(gasit==1);
cout<<"\nVectorul sortat este: \n";
for(i=1;i<=n;i++)
cout<<v[i]<<" ";
cout<<endl;
printf("timp de executie: %.2lf secunde\n\n",dif);
cout<<endl<<"Numarul de iteratii este:"<<contor<<endl;
return 0;}

13

14

Mergesort
10

QuickSort
22

Bubble-Sort
36

27

100

394

493

2708

1000

5656

7443

249579

100000

72322

80283

24945162

Mergesort
80000

72322

70000
60000
50000
40000
30000
20000
10000

22

394

0
10

100

5656
1000
Column1

15

10000

QuickSort
90000

80283

80000
70000
60000
50000
40000
30000
20000
7443

10000

36

493

01
10

2
100

3
1000

4
10000

Column1

Bubble-Sort
30000000

24945162
25000000
20000000
15000000
10000000
5000000

27

2708

249579

01
10

2
100

3
1000

4
10000

Iteratii

Concluzie
In urma analizei algoritmelor propuse se poate de spus ca algoritmul Mergesort este mai universal ,
avnd rezultate mai performante n mai multe cazuri ncercate fapt care rezulta din datele care li-am introdus
observind ca la numerge mici numarul de iterati nu variaza pe intervale foarte mari din cauza ca este simplu
de facut injumatatirea si la Mergesort timpul execuiei fiind mult mai mic dect la Quicksort . dar n schimb
Quicksort se comporta mai performant n cazuri generale , pentru numrul de valori mari date aleatoriu .La
fel si algoritumul Bubble-Sort observ ca pentru numerele mici care i le dau obtin un numar mic de
iteratii,obtinind chiar cel mai bun rezultat cind ii dau valoarea 5 dar algoritmul se incepe a schimba odata ce
incepe a creste valoarea numerica incepe a creste brusc si numarul de iteratii.Deci algoritmul mergesort este
mai static din punct de vedere a diferitor variante ,metoda lui fiind simpl njumtire , pe cind quicksort
16

este mai variabil pentru cazuri diferite , avind o metoda dependenta de aranjarea iniiala a
variabilelor.Bubble-Sort se comporta si el aproximatic ca Quicksort in dependenta de cum sunt aranjate
initial variabilele de asta depinde si inteschimbare dintre numere .
In general cea mi eficienta metoda este Mergesort prin care simpla injumatatire ne faciliteaza
sortarea.Aceasta metoda nu este dependenta de aranjarea initiala a variabilelor fapt care o face sa domine
metoda Quicksort si Bubble-Sort pentru ca la inregistrarea unor numere random nu se stie ce pozitie vor lua
numerele.

17

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