Documente Academic
Documente Profesional
Documente Cultură
I. Descrierea metodei.
Metoda “Divide et impera” (desparte şi stăpâneşte) este o metodă generală de elaborare a algoritmilor. Ea constă
în împărţirea repetată a unei probleme de dimensiune mare în două sau mai multe subprobleme de acelaşi tip, urmată de
combinarea soluţiilor subproblemelor rezolvate pentru a obţine soluţia problemei iniţiale.
Utilizând aceasta tehnica dorim să rezolvam următoarea problema:
Fiind dat un vector a = ( a1 , a 2 ,..., a n ) cu elementele in ordine oarecare, să se ordoneze elementele vectorului a in
ordine crescătoare (descrescătoare).
Vom face mai intai o generalizare a problemei a.i. vom obtine urmatoarea problema: fiind data o secventa de sir
a =( a p , a p +1 ,..., a q ) cu elementele in ordine oarecare, se cere sa se ordoneze aceasta secventa in ordine crescatoare
(descrescatoare).
Mai mult, presupunem că pentru orice p, q numere naturale cu 1 ≤ p ≤ q ≤ n există k astfel încât p ≤ k < q
{
şi prelucrarea secvenţei a p ,..., a q} se poate face prelucrând secvenţele {a ,..., a } şi {a
p k k +1 ,..., a q } şi apoi
combinând rezultatele pentru a obţine prelucrarea dorită a întregii secvenţe {a ,..., a } .
p q
Algoritmul recursiv, general divide et impera de prelucrare a secventei a[p…q] este următorul:
DIV_IMP( p, q; r) unde:
- p – indică începutul secvenţei ce trebuie prelucrată;
- q – indică sfârşitul secvenţei ce trebuie prelucrată;
- r – indică rezultatul prelucrării.
Algoritmul se va apela prin DIV_IMP(1, n; r).
DIV_IMP(p, q; r)
daca q – p+1 ≤ EPS atunci
// q – p +1 numărul de elemente al secvenţei a[p…q]
// EPS este dimensiunea la care problema se poate rezolva prin
// calcule elementare
SORT(p, q; r)
altfel
DIV(p, q; k)
DIV_IMP(p, k; r1 )
DIV_IMP(k+1, q; r2 )
COMB( r1 , r2 ; r )
sf. daca
sf algoritm
Observaţie:
In cazul algoritmilor de tip divide et impera se urmareste atingerea unuia dintre urmatoarele obiective:
I. Realizarea prin operatii foarte simple a divizarii problemei ceea ce duce la algoritmi mai complecsi de combinare
a solutiilor subproblemelor
o Ex:
p +q
In cazul algoritmului de sortare prin interclasare algoritmul de divizare era m =
2
Pentru combinarea solutiilor se folosea functia de interclasare – ceva mai complexa
II. Sau, realizarea prin operatii mai complexe a divizarii problemei in subprobleme, in schimb, combinarea solutiilor
fiind foarte simpla
Gasirea pozitiei k de partitionare a secventei a[p..q] se face prin interschimbari repetate care mentin invariante
proprietati asemanatoare celei de mai sus.
Se considera doua variabile de tip indice: i cu care se parcurge sirul a[p..q] de la stanga la dreapta si j cu care se
parcurge sirul a[p..q] de la dreapta spre stanga.
Initial: i = p+1
j=q
Operatiile de mai sus sunt repetate cat timp i<j, adica, cat timp subsirul a[i..j] mai contine elemente ce inca nu au
fost pozitionate relativ la elementul pivot x.
Considerand k = i-1 si interschimband a[i] cu a[p]=x vom obtine partitionarea dorita a vectorului a[p..q].
Dupa pozitionarea lui a[p] pe pozitia sa finala k astfel incat toate numerele mai mici sunt plasate in stanga sa si
toate numerele mai mari in dreapta sa rezulta ca pentru a sorta intreg sirul a[p..q], mai ramane sa sortam recursiv
subsirurile a[p..k-1] si a[k+1..q] apoi prin combinarea solutiilor (a[p..k-1] sortat) @ a[k] @ (a[k+1..q] sortat) vom obtine
sirul initial sortat.
Se observa ca nu mai este necesara combinarea solutiilor deoarece dupa rezolvarea problemelor a[p..k-1] si
a[k+1..q] avem:
Observatie:
• Daca sirul a[p..q]contine un singur element i.e. p=q, atunci nu mai este necesara o partitionare a problemei sirul
fiind gata sortat
• Daca sirul a[p..q] contine doua elemente, atunci unul dintre ele va fi ales pivot iar cel de al doilea trebuie
pozitinat relativ la elementul pivot apoi trebuie sortat sirul format din elementul ce nu este pivot
• In concluzie, EPS va avea valoarea 1 i.e. q=p
•
deci, algoritmul de sortare prin divide et impera poate fi rescris astfel:
qsort(p, q; r)
//daca p=q sirul este sortat deci nu mai avem ce sorta
daca p q atunci
// secventa a[p…q] contine cel putin doua elemente
//alegem a[p] ca pivot
x = a[p]
//determina poziţia k, pentru divizarea secvenţei a[p…q]
//in secvenţele a[p…k-1] si a[k+1…q] cu proprietatea:
•
•
•
i = p+1
j=q
cat timp i j executa
daca a[i] x atunci i++
daca x a[j] atunci j—
daca i<j si a[i]>x si a[j]<x atunci
a[i] a[j]
i++
j—
sf. daca
sf. cat timp
k=i-1
a[k] a[p]
Exemplu
Programul C/C++
#include <iostream.h>
i = p+1;
j = q;
while (i<=j){
if (a[i] <= x) i++;
if (x <= a[j] ) j--;
if (i<j && a[i]>x && x>a[j]){
//interschimba a[i] cu a[j]
aux = a[i];
a[i] = a[j];
a[j] = aux;
i++;
j--;
}
}
k = i-1;
//interschimba a[k] cu a[p]
aux = a[k];
a[k] = a[p];
a[p] = aux;
qsort(a, p, k-1);
qsort(a, k+1, q);
}
}
void main()
{
int n, i;
int a[100]
//citire sir
cout<<endl<<"n=";
cin>>n;
//afisam sirul a
cout<<"\nSirul nesortat: ";
afisareSir(a, n);
qsort(a, 1, n);
cout<<"\nSirul sortat: ";
afisareSir(a, n);
}//main
Algoritmul qsort prezentat mai sus este optim peste clasa algoritmilor de sortare bazati pe comparatii. De aceea,
in bibliotecile limbajului C/C++ exista o functie cu numele qsort care implementeaza algoritmul de sortare rapida quick
sort.
Ea se gaseste in <stdlib.h> si are urmatorul prototip:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void
*elem2 ) );
unde:
• base este adresa vectorului ce va fi sortat
• num este numarul de elemente ale vectorului
• witdh este numarul de octeti ocupat de un element al vectorului
• compare este adresa functiei prin care se realizeaza compararea a doua elemente ale vectorului. Ea returneaza:
o 1 daca elem1 > elem2
o 0 daca elem1 = elem2
o -1 daca elem1 < elem2
Exemplu de utilizare:
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
int v1 = *(int*)e1;
int v2 = *(int*)e2;
void main()
{
int i;
int n=12;
int x[100] = {1, 4, -2, -8, 7, 3, 5, 365, 346,46, 46, 4};
//sirul sortat
for( i = 0; i < n; i++ )
cout<<x[i]<<" ";
}