Sortarea prin interclasare MergeSort
Informaţii generale:
Definim interclasarea a două liste sortate ca fiind operaţia prin care obţinem o listă sortată ce conţine toate elementele listelor de intrare.
Sortarea prin interclasare utilizeaza metoda Divide et Impera:
-se împarte vectorul în secvenţe din ce în ce mai mici, astfel încât fiecare secvenţă să fie uşor ordonată la un moment dat, apoi interclasată cu o altă secvenţă din vector, de asemenea ordonată.
-practic, interclasarea va începe când se ajunge la o secvenţă formată din doua elemente. Cele doua secvente se vor interclasa şi vor alcătui un subşir ordonat din vector, mai mare, care, la rândul lui se va interclasa cu subşirul corespunzator obţinut în acelaşi mod, ş.a.m.d.
Prezentarea algoritmului:
Ideea este de a utiliza interclasarea în etapa de asamblare a soluţiilor: în urma rezolvării recursive a subproblemelor obţinute prin aplicarea tehnicii de programare “Divide et Impera” rezultă liste ordonate şi prin interclasarea lor obţinem lista iniţială sortată.
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;
Problema interclasării a doi vectori sortaţi a şi b se rezolvă astfel:
-se utilizează un vector intermediar, c;
-se compară elementul de pe poziţia întâi din primul vector cu elementul de pe poziţia întâi din al doilea vector; dacă este mai mic elementul primului vector, acesta se copiază în vectorul c, apoi se creşte indicele de parcurgere astfel încât la următoarea comparaţie să indice cel de-al doilea element; dacă este mai mic elementul din b, se va copia el în c, iar indicele de parcurgere al lui b se incrementează pentru a selecta al doilea element din b;
-prin comparaţii succesive, se construieşte vectorul c ordonat, până se termină elementele din a sau b; elementele rămase în b, sau a, după caz, se vor copia în ordine în c;
Exemplu1: Fie vectorul de sortat 2, 9, 5, 3, 7, 1, 6, 4
Şirul de intrare |
2, 9, 5, 3 --- 7, 1, 6, 4 |
Împărţire (1) |
2, 9 --- 5, 3 si 7, 1 --- 6, 4 |
Împărţire(2) |
2 --- 9 si 5 --- 3 si 7 --- 1 si 6 --- 4 |
Sortare(2) – se face direct, deoarece subşirurile au maxim 2 elemente fiecare |
2 --- 9 si 3 --- 5 si 1 --- 7 si 4 --- 6 |
Interclasare (2) |
2 , 3, 5, 9 si 1 ,4 ,6 ,7
|
Interclasare(1) |
1 , 2 , 3 , 4 , 5 , 6 , 7 , 9 |
Şirul final |
1 2 3 4 5 6 7 9 |
Exemplu2: Reamintesc interclasarea.
a: 1 2 4 7 8 9 |
Se compară a[1] cu b[1]; se va copia în c elementul cel mai mic, respectiv a[1]; se va indica următorul element din vectorul a |
b: 3 5 6 |
|
c: 1 |
|
a: 1 2 4 7 8 9 |
Se compară a[2] cu b[1]; se va copia în c elementul a[2] şi se va indica în continuare a[3] |
b: 3 5 6 |
|
c: 1 2 |
|
a: 1 2 4 7 8 9 |
Se compară a[3] cu b[1]; se va copia în c elementul b[1] şi se va indica b[2] pentru următoarea comparaţie |
b: 3 5 6 |
|
c: 1 2 3 |
|
a: 1 2 4 7 8 9 |
Se compară a[3] cu b[2]; se va copia în c elementul a[3], şi se indică a[4] |
b: 3 5 6 |
|
c: 1 2 3 4 |
|
a: 1 2 4 7 8 9 |
Se compară a[4] cu b[2]; se trece în c elementul b[2]; se indică b[3] |
b: 3 5 6 |
|
c: 1 2 3 4 5 |
|
a: 1 2 4 7 8 9 |
Se compară a[4] cu b[3]; se trece în c b[3]; se termină vectorul b, deci se copiază în c toate elementele rămase neparcurse în a; |
b: 3 5 6 |
|
c: 1 2 3 4 5 6 |
|
c: 1 2 3 4 5 6 7 8 9 |
Varianta pseudocod a algoritmului:
procedura mergeSort(x,st,dr);
dacă st < dr atunci
m←[(st+dr)/2]
mergeSort(x,st,m);
mergeSort(x,m+1,dr)
interclasează subvectorii (x[st],…,x[m]),(x[m+1],…x[dr]) ;
sfârşit dacă;
sfârşit mergeSort;
Pentru a stabili complexitatea algoritmului de sortare prin interclasare, remărcam urmatoarele:
- pentru un vector cu n elemente, numărul de înjumătăţiri succesive până se ajunge la subvectori de lungime 1 sau 2 este de aproximativ log2n şi nu depinde de valorile din vector;
- la fiecare din aceste divizări succesive, se mută din x într-un vector auxiliar pentru interclasare şi invers în total n elemente.
În consecinţă, numarul de operaţii elementare executate este de ordinul O(n∙log2n).
Constatăm deci că, pentru tablouri cu număr mare de componente, timpul de calcul este mult mai mic în cazul sortării prin interclasare, decât în cazul folosirii algoritmilor simpli, cum ar fi cel al selecţiei, inserţiei sau al bulelor, a căror complexitate este O(n2).
Algoritmul de sortare prin interclasare consumă însă de două ori mai multă memorie decât cei simpli mentionaţi, deoarece necesită spaţiu suplimentar pentru vectorul auxiliar .
Implementare C++: int x[20], n; void sort(int st, int dr, int x[20]){ int aux; if (x[st]>x[dr]) { aux=x[st]; x[st]=x[dr]; x[dr]=aux;} } void interclasare(int st, int dr, int m, int x[20]){ int b[20], i, j, k; i=st; j=m+1; k=1; while(i<=m && j<=dr) if(x[i]<=x[j]){ b[k]=x[i]; i++; k++; else {b[k]=x[j]; j++; k++; }
if(i<=m) for(j=i;j<=m;j++) { b[k]=x[j]; k++; } else for(i=j;i<=dr;i++) { b[k]=x[i]; k++; } k=1; for(i=st;i<=dr;i++){ x[i]=b[k]; k++; } } void divimp(int st, int dr, int x[20]){ int m; if((dr-st)<=1) sort(st, dr, x); else {m=(st+dr)/2; divimp(st,m,x); divimp(m+1,dr,x); interclasare(st, dr, m, x); } } void main(){ int i; cin>>n; for(i=1;i<=n;i++) cin>>x[i]; divimp(1, n, x); for(i=1;i<=n;i++) cout<<x[i]<<” “; } |
Implementare Pascal: type vector=array [1..20] of integer; var i,n:integer; x,b:vector; procedure sort(st,dr:integer); var aux:integer; begin if x[st]>x[dr] then begin aux:=x[st]; x[st]:=x[dr]; x[dr]:=aux; end; end; procedure interclasare(st,dr,m:integer); var i, j, k:integer; begin i:=st; j:=m+1; k:=1; while (i<=m) and( j<=dr) do if x[i]<=x[j] then begin b[k]:=x[i]; i++; k++; end else begin b[k]:=x[j]; j++; k++; end; if i<=m then for j:=i to m do begin b[k]:=x[j]; k++; end; else for i:=j to dr do begin b[k]:=x[i]; k++; end; k:=1; for i:=st to dr do begin x[i]:=b[k]; k++; end; end; procedure divimp(st, dr:integer); var m:integer; begin if (dr-st)<=1 then sort(st, dr); else begin m:=(st+dr) div 2; divimp(st,m); divimp(m+1,dr); interclasare(st, dr, m); end; end; begin readln(n); for i:=1 to n do readln(x[i]); divimp(1,n); for i:=1 to n do write(x[i] ,’ ’) ; end. |
Mergi la pagina METODE DE SORTARE
Aplicatii
Aplicaţie1: Se citesc n numere complexe din fişierul date.in si două numere reale a,b.
Să se scrie în fişierul date.out în ordine crescătoare modulele numerelorcomplexe care nu aparţin intervalului [a,b].
Program C++: #include <fstream.h> #include <iomanip.h> ifstream fin(“date.in”); ofstream fies(“date.out”); struct complex{float re, im;}; void citirec (complex &c){ fin>>c.re>>c.im; } void citire(int &n, complex x[100], float &a, float &b){ int i; fin>>n; for(i=1; i<=n; i++) citirec(x[i]); fin>>a>>b; } float modul (complex c) { return sqrt(c.re*c.re +c.im*c.im); } void intercl(int a[100], int s, int m, int d){ int i,j,k, b[100]; i=s; j=m+1; k=1; while (i<=m && j<=d) if (a[i]<a[j]) b[k++]=a[i++]; else b[k++]=a[j++]; while (i<=m) b[k++]=a[i++]; while (j<=d) b[k++]=a[j++]; k=1; for (i=s; i<=d; i++) a[i]=b[k++];} void mergesort (int a[100], int s, int d) { int m; if (s<d) { m=(s+d)/2; mergesort(a,s,m); mergesort(a, m+1, d); intercl(a,s,m,d); } } void scriere (float a[1000], int n){ int i; for(i=1; i<=n; i++) fies<<fixed<<setprecision(3)<<a[i]<<” “; } void main () { complex c[100]; float a, b, x[100]; int i, k=0, n; citire (n, c, a, b); for (i=1; i<=n; i++) if (modul(c[i]) modul(c[i]>b)) x[++k]=modul(c[i]); mergesort(x,1,k); scriere (x, k); fin.close(); fies.close(); } |
Program Pascal: PROGRAM MergeSort1; TYPE complex=RECORD re, im : REAL; END; vectorc=ARRAY[1..100] OF complex; vectorr=ARRAY[1..100] OF REAL; VAR c:vectorc; x:vectorr; a,b:REAL; i, k, n:INTEGER; PROCEDURE citire (VAR n:INTEGER; VAR x:vectorc; VAR a,b:REAL); VAR i:INTEGER; fin:TEXT; BEGIN ASSIGN (fin, ‘date.in’); RESET(fin); READ(fin, n); FOR i:=1 TO n DO READ(fin, x[i].re, x[i].im); READ(fin, a, b); CLOSE (fin); END; FUNCTION modul (c: complex):real; BEGIN modul:=sqrt(c.re*c.re+c.im*c.im); END; PROCEDURE intercl(VAR a:vectorr; s,m,d:INTEGER); VAR i,j,k:INTEGER; b:ARRAY[1..100] OF INTEGER; BEGIN i:=s; j:=m+1; k:=1; WHILE (i<=m) AND (j<=d) DO IF a[i]<a[j] THEN BEGIN b[k]:=a[i]; i:=i+1; k:=k+1; END ELSE BEGIN b[k]:=a[j]; j:=j+1; k:=k+1; END; WHILE i<=m DO BEGIN b[k]:=a[i]; i:=i+1; k:=k+1; END; WHILE j<=d DO BEGIN b[k]:=a[j]; j:=j+1; k:=k+1; END; k:=1; FOR i:=s TO d DO a[i]:=b[k]; END; PROCEDURE MergeSort(a:vectorr; s,d:INTEGER); VAR m: INTEGER; BEGIN IF s BEGIN m:=(s+d) DIV 2; MergeSort(a,s,m); MergeSort(a,m+1,d); intercl(a,s,m,d); END; END; PROCEDURE scriere (a:vectori; n:INTEGER); VAR i:INTEGER; fies:TEXT; BEGIN ASSIGN (fies, ‘date.out’); REWRITE(fies); FOR i:=1 TO n DO WRITE(fies, a[i], ‘ ‘); CLOSE(fies); END; BEGIN citire (n,c,a,b); FOR i:=1 TO n DO IF (modul(c[i])<a) OR (modul(c[i]>b) THEN BEGIN k:=k+1; x[k];=modul(c[i]); END; MergeSort (x,1,k); scriere (x,k); END. |
Mergi la pagina METODE DE SORTARE