Explorați Cărți electronice
Categorii
Explorați Cărți audio
Categorii
Explorați Reviste
Categorii
Explorați Documente
Categorii
41
'
x
'
42
'
x
'
43
'
x
'
58
'
x
'
59
'
x
'
5A
'
zecimal: 65 66 67 88 89 90
Cifre: 0 1 2 ... 9
hexazecimal: x
'
30
'
x
'
31
'
x
'
32
'
x
'
39
'
zecimal: 48 49 50 57
Litere mici: a b c ... z
hexazecimal: x'61' x'62' x'63' x'7A'
zecimal: 97 98 99 122
Caracterul blanc: hexazecimal: x20 zecimal: 32
------------------------------------------------------------
Limbajul Pascal definete tipul primitiv char i
Limbajul C tipurile char i int sunt echivalente.
Stabilirea naturii unui caracter:
('A' <= x) AND (x <= 'Z') - x este liter mare;
('a' <= x) AND (x <= 'z') - x este liter mic;
('0' <= x) AND (x <= '9') - x este o cifr.
Limbajul Pascal pune la dispoziie dou funcii standard de transfer ntre tipurile
char
i integer
,
o ORD(c:char):integer; care returneaz numrul de ordine al
caracterului c n mulimea char (cu alte cuvinte valoarea ntreag
corespunztoare codului caracterului);
o CHAR(i:
integer):char; preciznd cel de-al i
-
lea caracter al
mulimii char (adic caracterul care are codul i).
o CHAR i ORD sunt funcii inverse.
Spre exemplu, f('5')=5, g(8)='8'. f i g sunt funcii inverse:
f(g(i))=i (0 < i < 9)
g(f(c))=c ('0' < c < '9').
------------------------------------------------------------
{Varianta Pascal}
VAR i:integer; c:char;
ORD(CHR(i))=i;
CHR(ORD(c))=c;
[1.3.2.b]
f(c)=ORD(c)-ORD('0'); {f:C I}
g(i)=CHR(i+ORD('0')); {g:I C}
------------------------------------------------------------
//Varianta C
char c; int n;
n=c-'0' //f(c)
[1.3.2.c]
c=n+'0'; //g(i)
------------------------------------------------------------
1.3.3. Tipul subdomeniu
Este destul de frecvent cazul n care o variabil a unui anumit tip poate s ia valori
doar ntr-un anumit interval limitat.
Acest lucru poate fi exprimat definind variabila ca aparinnd unui tip
subdomeniu al tipului respectiv conform relaiei:
------------------------------------------------------------
TYPE TipSubdomeniu = min..max; [1.3.3.a]
------------------------------------------------------------
unde min i max sunt limitele intervalului.
Se precizeaz faptul c tipul TipSubdomeniu se refer la un tip deja definit
(predefinit) care se numete tip scalar asociat i c min i max sunt valori ale
acestui tip.
n secvena [1.3.3.b] se prezint cteva exemple de definire a unor astfel de tipuri:
------------------------------------------------------------
TYPE TipAn = 1900..1999;
TipLitera = 'a'..'z'; [1.3.3.b]
TipCifra = '0'..'9';
TipOfiter = sublocotenent..general;
------------------------------------------------------------
n acest context fiind date variabilele y:
TipAn i c:
TipLitera
, atunci
atribuirile y:=
1973 i c:=
'W' sunt permise, iar y:=
1291 sau c:=
'9'
nu.
Legalitatea unor asemenea atribuiri nu poate fi verificat de ctre compilator
dect n cazul n care valoarea de atribuit este precizat printr-o constant sau
printr-o variabil de acelai tip.
Atribuiri de forma y:=
i i c:=
a unde i este de tip INTEGER
iar a de tip
CHAR pot fi verificate numai n timpul execuiei programului element care complic
i lungete codul generat de ctre compilator.
Practica confirm ns valoarea deosebit a unor astfel de verificri n dezvoltarea
de programe.
1.4. Tipuri structurate
1.4.1. Structura tablou. Tipul de date abstract tablou.
Un tablou este o structur omogen el constnd dintr-o mulime de componente
de acelai tip numit tip de baz.
Tabloul este o structur de date cu acces direct (random-acces), deoarece oricare
dintre elementele sale sunt direct i n mod egal accesibile.
Pentru a preciza o component individual, numelui ntregii structuri i se asociaz
un indice care selecteaz poziional componenta dorit.
La definirea unui tablou se precizeaz:
o (1) Metoda de structurare, care este implementat direct de limbaj
(ARRAY)
,
o (2) Numele tipului de date rezultat (TipTablou)
,
o (3) Tipul de baz al tabloului (TipElement)
o (4) Tipul indice (TipIndice).
------------------------------------------------------------
{Definirea unui tip tablou Varianta Pascal}
TYPE TipTablou = ARRAY[TipIndice] OF TipElement;
VAR tablou: TipTablou; [1.4.1.a]
TYPE TipMatrice = ARRAY[TipIndice1] OF TipTablou;
VAR matr: TipMatrice;
------------------------------------------------------------
TipElement nu este supus nici unei restricii, adic el poate fi oricare alt tip
(inclusiv un tip structurat)
TipIndice este n mod obligatoriu un tip ordinal (nu este admis tipul ntreg, n
schimb este permis un tip subdomeniu al acestuia)
n limbajul C lucrurile se petrec n mod asemntor cu deosebirea c tipul indice este
n mod obligatoriu tipul ntreg (int) i nu se precizeaz explicit metoda de
structurare.
-----------------------------------------------------------------
// Definirea unui tip tablou - Varianta C
/*1.4.1.a*/
typedef TipElement TipTablou[IndiceTipOrdinal];
TipTablou tablou;
typedef TipTablou TipMatrice[IndiceTipOrdinal1];
/*echivalent cu:
typedef TipElement TipMatrice[IndiceTipOrdinal][IndiceTipOrdinal1];
*/
TipMatrice matr;
-----------------------------------------------------------------
//TipElement numeTablou[nrElemente];
float tablou[10]; [1.4.1.b]
char sir[10];
------------------------------------------------------------
Tabloul este o structur de date static pentru care rezervarea de memorie se
realizeaz n faza de compilare a programului.
O valoare structurat (o instan) a unui tip de date TipTablou avnd
componentele
c
1
,
c
2
...,
c
n
poate fi iniializat printr-un constructor de
tablou i o operaie de atribuire:
tablou = TipTablou(c
1
, c
2
,...,c
n
).
------------------------------------------------------------
{Varianta Pascal}
TYPE x = (a,b,c);
Tablou = ARRAY[x] OF integer;
CONST vector: tablou=(3,1,7); [1.4.1.c]
------------------------------------------------------------
//Varianta C
int vect[5]={0,1,33,4,8};
int mat[2][3]={{11,12,13},{1,2,3}};
char str[9]="Turbo C++";
-----------------------------------------------------------
Operatorul invers al unui constructor este selectorul. Acesta selecteaz o
component individual a unui tablou.
Fiind dat o variabil tablou vector
, un selector de tablou se precizeaz
adugnd numelui tabloului, indexul i al componentei selectate: vector[i].
n locul unui indice constant poate fi utilizat o expresie index (de indice).
Evaluarea acestei expresii n timpul execuiei programului, conduce la
determinarea componentei selectate.
Dac tipul de baz al unui tablou este de asemenea ordonat, atunci n cadrul
tipului tablou poate fi definit o relaie de ordonare natural.
Ordonarea natural a dou tablouri de acelai tip este determinat de ctre acele
componente corespunztoare care sunt diferite i care au cel mai mic indice.
(2,3,5,8,9) >(2,3,5,7,11)
'CAPAC' < 'COPAC'
------------------------------------------------------------
TYPE TipTablou=ARRAY[1..n] OF TipElement;
VAR x,y:TipTablou; [1.4.1.d]
(x<y) <=> E
k
:0<k<=n:((A
i
:0<i<k:x[i]=y[i])&(x[k]<y[k]))
-----------------------------------------------------------
Un exemplu clasic n acest sens l constituie ordonarea lexicografic a
tablourilor de caractere.
Deoarece toate componentele unui tip tablou TipTablou aparin aceluiai tip de
baz TipElement avem:
Card (TipTablou) = Card (TipElement)
Card (TipIndice)
.
Tablouri de o singur dimensiune sau tablouri liniare.
Accesul la oricare element al unui astfel de tablou se realizeaz
utiliznd un singur indice n mecanismul de selecie.
TipElement precizat la definirea unui tip de date tablou poate fi la rndul su
un tip tablou. Prin acest mecanism se definesc tablourile de mai multe
dimensiuni.
Astfel de tablouri se numesc de obicei matrice
Accesul la un element al matricei se realizeaz utiliznd un numr de
indici egal cu numrul de dimensiuni ale matricei
mat[i,j,k, ,m,n].
Tipul de date abstract tablou poate fi prezentat ca i n secvena [1.4.1.e].
Exemplu de implementare Pascal a unui astfel de tip de date abstract [1.4.1.d].
------------------------------------------------------------
TDA Tablou
Model matematic: Secven de elemente de acelai tip.
Indicele asociat aparine unui tip ordinal finit. Exist
o coresponden biunivoc ntre indici i elementele
tabloului.
Notaii:
TipElement -tipul elementelor tabloului;
a - tablou unidimensional;
i - index; [1.4.1.e]
e - obiect de tip TipElement.
Operaii:
DepuneI nTabl ou(a,i,e) - procedur
care
depune
valoarea
lui e n cel de-al i-lea element al tablolui a;
e:= FurnizeazDinTablou(a,i)
-
funcie
care
returneaz
valoarea
celui
de-al
i-lea
element
al
tabloului
a.
------------------------------------------------------------
{Exemplu de implementare Varianta Pascal}
CONST NumrMaxElem = 10;
TYPE TipElement = ......;
TipIndex = 1.. NumrMaxElem;
TipTablou = ARRAY [Tip Index] OF TipElement;
VAR i: TipIndex;
a: TipTablou; [1.4.1.f]
e: TipElement;
{DepuneInTablou(a,i,e)} a[i]:=e;
{FurnizeazDinTablou(a,i)} e:=a[i];
------------------------------------------------------------
//Exemplu de implementare - Varianta C
/*1.4.1.f*/
#define NumarMaxElem valoareIntreaga
typedef ... TipElement; /*se defineste tipul elementelor ex.
typedef float TipElement dar poate fi si
un tip definit de programator, sau un tip
incomplet definit*/
typedef TipOrdinal TipIndex; /*unde TipOrdinal este un tip ordinal
(fundamental sau definit anterior)*/
typedef TipElement TipTablou[NumarMaxElem];
TipIndex i;
TipTablou a;
TipElement e;
a[i]=e; /*DepuneInTablou(a,i,e)*/
e=a[i]; /*FurnizeazaDinTablou(a,i)*/
------------------------------------------------------------------------
1.4.2. Tehnici de cutare n tablouri
Formularea problemei: se presupune c este dat o colecie de date, n care se cere
s se localizeze (fixeze) prin cutare un anumit element.
Se consider c mulimea celor n elemente este organizat n forma unui un tablou
liniar:
a: ARRAY[1..n] OF Tip Element;
De regul TipElement are o structur de articol cu un cmp specific pe post de
cheie.
Sarcina cutrii este aceea de a gsi un element al tabloul a, a crui cheie este
identic cu o cheie cutat x .
Indexul i care rezult din procesul de cutare satisface relaia a[i].cheie=x, i
el permite accesul i la alte cmpuri ale elementului localizat.
Vom presupune n continuare c TipElement const numai din cmpul "cheie",
adic el este chiar cheia. Cu alte cuvinte se va opera de fapt cu un tablou de chei.
1.4.2.1. Cutarea liniar
Atunci cnd nu exist nici un fel de informaii referitoare la colecia de date n care se
face cutarea, tehnica evident este aceea de a parcurge n mod secvenial colecia prin
incrementarea indexului de cutare pas cu pas.
Aceast metod se numete cutare liniar i este ilustrat n secvena [1.4.2.1.a].
------------------------------------------------------------
{Cautare liniar (while) - Varianta Pascal}
VAR a:ARRAY[1..n] OF TipElement;
x:TipElement; [1.4.2.1.a]
i:=1;
WHILE (i<n)AND(a[i]<>x) DO i:=i+1;
IF a[i]<>x THEN
{n tablou nu exist elementul cutat}
ELSE {avem o coinciden la indicele i}
-----------------------------------------------------------
/*cautare liniara (while) - varianta C*/
/*1.4.2.1.a*/
TipElement a[NumarMaxElem];
TipElement x;
int i=0;
while ((i<n-1) && (a[i]!=x))
i++;
if (a[i]!=x ){
/*n tablou nu exista elementul cautat*/
}
else{
/*avem o coincidenta la indicele i*/
}
-----------------------------------------------------------------
Exist dou condiii care finalizeaz cutarea:
Elementul a fost gsit adic a[i]
=
x
;
Elementul nu a fost gsit dup parcurgerea integral a tabloului.
Invariantul buclei, care de fapt este condiia care trebuie ndeplinit naintea fiecrei
incrementri a indexului i
, este:
(1<= i < n)&(A
k
:1 <= k < i:a[k]<> x)
i el exprim faptul c pentru valori ale lui k < i
, nu exist coinciden.
Condiia de terminare va fi:
((i = n)OR(a[i]= x))&(A
k
:1 <= k< i:a[k]<> x)
Aceast condiie poate fi utilizat ntr-un algoritm de cutare bazat pe ciclul REPEAT
[1.4.2.1.b],
------------------------------------------------------------
{Cautare liniar (repeat) - Varianta Pascal}
VAR a: ARRAY[1..n] OF TipElement; {n>0}
x: TipElement;
i:=0;
REPEAT [1.4.2.1.b]
i:=i+1
UNTIL (a[i]=x)OR(i=n));
IF a[i]<>x THEN
{n tablou nu exist elementul cutat}
ELSE {avem o coinciden la indicele i}
------------------------------------------------------------------------
/*cautare liniara (do) - varianta C*/
/*1.4.2.1.b*/
TipElement a[NumarMaxElem];
TipElement x;
int i=-1;
do{
i++;
}while ((i<n-1) && (a[i]!=x))
if (a[i]!=x ){
/*n tablou nu exista elementul cautat*/
}
else{
/*avem o coincidenta la indicele i*/
}
-----------------------------------------------------------------
n legtur cu acest algoritm se precizeaz urmtoarele:
La prsirea buclei mai trebuie realizat o comparaie a lui a[i] cu x n vederea
stabilirii existenei sau nonexistenei elementului cutat;
Dac elementul este gsit, el este elementul cu cel mai mic indice (dac exist mai
multe elemente identice).
Dup cum se observ fiecare pas al algoritmului necesit evaluarea expresiei
booleene (care este format din doi factori) i incrementarea indexului.
Acest proces poate fi simplificat i n consecin cutarea poate fi accelerat,
prin simplificarea expresiei booleene.
O soluie de a simplifica expresia este aceea de a gsi un singur factor care s-i
implice pe cei doi existeni.
Acest lucru este posibil dac se garanteaz faptul c va fi gsit cel puin o potrivire.
n acest scop se completeaz tabloul a cu un element adiional a[n+1] cruia i se
atribuie iniial valoarea lui x (elementul cutat). Tabloul devine:
a: ARRAY[1..n+1] OF TipElement;
Elementul x poziionat pe ultima poziie a tabloului se numete fanion, iar tehnica de
cutare, tehnica fanionului.
Evident, dac la prsirea buclei de cutare i > n
, rezult c
elementul cutat nu se afl n tablou.
Algoritmul de cutare astfel modificat apare n [1.4.2.1.c].
------------------------------------------------------------
{Cautare liniara tehnica fanionului (while)-Varianta Pascal}
VAR a: ARRAY[1..n+1] OF TipElement;
x: TipElement;
a[n+1]:=x; i:=1; [1.4.2.1.c]
WHILE (a[i]<>x) DO i:=i+1;
IF i=n+1 THEN
{n tablou nu exist elementul cutat}
ELSE {avem o coinciden la indicele i}
------------------------------------------------------------------------
/*cautare liniara metoda fanionului (while) - varianta C*/
/*1.4.2.1.c*/
TipElement a[NumarMaxElem+1];
TipElement x;
int i=0;
a[NumarMaxElem]=x;
while (a[i]!=x)
i++;
if (i == NumarMaxElem){
/*n tablou nu exista elementul cautat*/
}
else{
/*avem o coincidenta la indicele i*/
}
-----------------------------------------------------------------
Condiia de terminare dedus din acelai invariant al ciclului este:
(a[i]= x)&(A
k
:1 <= k < i:a[k]<> x)
n secvena [1.4.2.1.d] apare acelai algoritm implementat cu ajutorul ciclului REPEAT
(do).
------------------------------------------------------------
{Cautare liniara tehnica fanionului(repeat)-Varianta Pascal}
VAR a: ARRAY[1..n+1] OF TipElement;{n > 0}
x: TipElement;
i:=0; a[n+1]:=x
REPEAT [1.4.2.1.d]
i:=i+1
UNTIL a[i]=x;
IF i=n+1 THEN
{n tablou nu exist elementul cutat}
ELSE {avem o coinciden la indicele i}
------------------------------------------------------------
/*cautare liniara metoda fanionului (do) - varianta C*/
/*1.4.2.1.d*/
TipElement a[NumarMaxElem+1];
TipElement x;
int i=-1;
a[NumarMaxElem]=x;
do{
i++;
}while (a[i]!=x)
if (i == NumarMaxElem){
/*n tablou nu exista elementul cautat*/
}
else{
/*avem o coincidenta la indicele i*/
}
-----------------------------------------------------------------
Performana cutrii liniare este O(n/2), cu alte cuvinte, n medie un element este
gsit dup parcurgerea a jumtate din elementele tabloului.
n secvena [1.4.2.1.e] apare un alt exemplu de implementare n limbajul C a
tehnicilor de cutare discutate anterior.
------------------------------------------------------------
//tehnici de cautare - implementare C
//cautare liniara
//returneaza n pentru
negasit,
respectiv i<n pentru
gasit
// pe pozitia i
int cautare _liniara(int x,int a[],int n
{int i;
for(i=0;i<n && a[i]-x;i++);
return i;
} [1.4.2.1.e]
//cautare liniara metoda fanionului
//returneaza n pentru
negasit,
respectiv i<n pentru
gasit //
pe pozitia i
int cautare_fanion(int x,int a[],int n)
{int i;
a[n]=x;
for(i=0;a[i]-x;i++);
return i;
}
------------------------------------------------------------------------
1.4.2.2. Cutarea binar
Procesul de cutare poate fi mult accelerat dac se dispune de informaii suplimentare
referitoare la datele cutate.
Este bine cunoscut faptul c o cutare se realizeaz mult mai rapid ntr-un masiv de
date ordonate (spre exemplu ntr-o carte de telefoane sau ntr-un dicionar).
n continuare se prezint un algoritm de cutare ntr-o structur de date ordonat,
adic care satisface condiia:
------------------------------------------------------------
VAR a:ARRAY[1..n] OF TipElement;{n>0}
A
k
:1 < k <= n:a[k-1]<= a[k]
[1.4.2.2.a]
------------------------------------------------------------
Ideea de baz:
Se inspecteaz un element aleator a[m] i se compar cu elementul cutat x.
Dac este egal cu x cutarea se termin;
Dac este mai mic dect x
, se restrnge intervalul de cutare la elementele care
au indici mai mari ca m;
Dac este mai mare dect x
, se restrnge intervalul la elementele care au indicii
mai mici ca m.
n consecin rezult algoritmul denumit cutare binar.
Variabilele s i d sunt de tip indice i ele precizeaz limitele stnga respectiv
dreapta ale intervalului n care elementul ar mai putea fi gsit:
------------------------------------------------------------
{Cutare binar - Varianta Pascal}
VAR a:ARRAY[1..n] OF TipElement;{n>0}
x:TipElement;
s,d,m:TipIndice;
gasit:boolean;
s:=1; d:=n; gasit:=false;
WHILE (s<=d) AND (NOT gasit) DO [1.4.2.2.b]
BEGIN
m:={orice valoare cuprinsa intre s si d};
IF a[m]=x THEN
gasit:=true
ELSE
IF a[m]<x THEN
s:=m+1
ELSE
d:=m-1
END;
IF gasit THEN {avem o coinciden la indicele i}
-----------------------------------------------------------------
/*cautare binara - varianta C*/
/*1.4.2.2.b*/
TipElement a[n]; /*n>0*/
TipElement x;
TipIndice s,d,m;
int gasit;
s=0; d=n-1; gasit=0;
while((s<=d)&&(!gasit))
{
m=(s+d)/2; /*sau orice valoare cuprinsa intre s si d*/
if(a[m]==x)
gasit=1;
else
if(a[m]<x)
s=m+1;
else
d=m-1;
}
if(gasit) /*avem o coincidenta la indicele i*/
-----------------------------------------------------------------
Invariantul buclei, adic condiia ce trebuie ndeplinit naintea fiecrui pas este
(s <= d)&(A
k
:1 <= k < s:a[k]< x)&(A
k
:d < k <= n:a[k] > x)
Condiia de terminare este:
gasit
OR
((s>d)&(A
k
:1<=k<s:a[k]<x)&(A
k
:d<k<=n:a[k]>x))
Alegerea lui m este arbitrar n sensul c ea nu influeneaz corectitudinea execuiei
algoritmului, n schimb influeneaz eficiena sa.
Soluia optim n acest sens este alegerea elementului din mijlocul intervalului,
ntruct ea elimin la fiecare pas jumtate din intervalul n care se face cutarea.
n consecin rezult c numrul maxim de pai de cutare va fi O(log
2
n),
Aceast performan reprezint o mbuntire remarcabil fa de cutarea
liniar unde numrul mediu de cutri este
n
/
2 .
Eficiena cutrii binare poate fi mbuntit dac se interschimb instruciunile IF ntre
ele.
O mbuntire de fond ns a eficienei se poate obine - ca i n cazul cutrii liniare
- prin simplificarea condiiei de terminare.
Acest lucru se poate realiza dac se renun la ideea de a termina algoritmul
de ndat ce s-a stabilit coincidena.
La prima vedere acest lucru nu pare prea nelept, ns la o examinare mai
atent, se poate observa c ctigul n eficien la fiecare pas este mai
substanial dect pierderea provocat de cteva comparaii suplimentare de
elemente.
Se reamintete faptul c numrul de pai este log
2
n
.
Soluia cea mai rapid are la baz urmtorul invariant:
(A
k
:1<=k<s:a[k]<x)&(A
k
:d<k<=n:a[k]>x)
Procesul de cutare continu pn cnd intervalul de cutare ajunge de dimensiune
banal (0 sau 1 element). Aceast tehnic este ilustrat n [1.4.2.2.c].
------------------------------------------------------------
{Cutare binar ameliorat - varianta Pascal}
VAR a:ARRAY[1..n] OF TipElement;{n>0}
x:TipElement;
s,d,m:TipIndice;
{cautare binara performant}
s:=1; d:=n+1;
WHILE s<d DO
BEGIN
m:=(s+d) DIV 2;
IF a[m]<x THEN [1.4.2.2.c]
s:=m+1
ELSE
d:=m
END;
IF d>n THEN {nu exista elementul cautat};
IF d<=n THEN
IF a[d]=x THEN
{elementul exista}
ELSE {elementul nu exista};
------------------------------------------------------------
/*cautare binar ameliorat - varianta C */
/*1.4.2.2.c*/
TipElement a[n]; /*n>0*/
TipElement x;
TipIndice s,d,m;
s=0; d=n;
while(s<d){
m=(s+d)/2;
if(a[m]<x)
s=m+1;
else
d=m;
}
if(d>n) /*nu exista elementul cautat*/;
if(d<=n)
if(a[d]==x)
/*elementul exista*/;
else /*elementul nu exista*/;
------------------------------------------------------------
Condiia de terminare n acest caz este s > d .
Ciclul se termin cnd s = d
.
Cu toate acestea egalitatea s = d nu indic automat gsirea elementului cutat.
Dac d > n nu exist nici o coinciden.
Dac d<=n se observ c elementul a[d] corespunztor ultimului indice d nu
a fost comparat cu cheia,
n consecin este necesar efectuarea n afara ciclului a unui test a[d]=x care
de fapt stabilete existena coincidenei.
Acest algoritm asemenea cutrii liniare, gsete elementul cu cel mai mic indice, lucru
care nu este valabil pentru cutarea binar normal.
Alte variante de implementare a celor dou cutri binare n limbajul C apar n
secvena [1.4.2.2.d].
------------------------------------------------------------
//cautari binare - varianta C
int cautare_binara(int x,int a[],int n){
int s=0,d=n-1,m;
do{
(x>a[m=(s+d)/2])?(s=m+1):(d=m-1);
}while(a[m]-x && s<=d);
return(a[m]-x)?n:m;
} [1.4.2.2.d]
int cautare_binara_ameliorata(int x,int a[],int n){
int s=0,d=n,m;
do{
(x>a[m=(s+d)/2])?(s=m+1):(d=m);
}while(s<d);
return
((d>=n)||(d<n && a[d]-x))?n:d;
}
------------------------------------------------------------
1.4.2.3. Tehnica cutrii prin interpolare
O alt mbuntire posibil a metodei de cutare binar, const n a determina cu mai
mult precizie locul n care se face cutarea n intervalul curent, n loc de a selecta
ntotdeauna elementul de la mijloc.
Astfel cnd se caut ntr-o structur ordonat, spre exemplu cartea de telefon, un
nume ncepnd cu B este cutat la nceputul crii, n schimb un nume care ncepe cu V
este cutat spre sfritul acesteia.
Aceast metod, numit cutare prin interpolare, necesit o simpl modificare n
raport cu cutarea binar.
Astfel, n cutarea binar, noul loc n care se face accesul este determinat cu ajutorul
relaiei, unde s i d sunt limitele intervalului de cutare:
Urmtoarea evaluare a lui m , numit cutare prin interpolare se consider a fi mai
performant:
Ea ine cont de valorile efective ale cheilor n stabilirea indicelui la care se
face urmtoarea cutare
Aceast estimare ns presupune o distribuie uniform a valorilor cheilor pe
domeniul vizat.
-------------------------------------------------------------------
/* cautare prin interpolare - varianta C
int cautare_interpolare(element a[],int ultim,int x){
long m,s,d;
) s d ( * s m + =
2
1
) s d ( *
] s [ a ] d [ a
] s [ a x
s m
+ =
s=0;
d=ultim-1; [1.4.2.1.m]
do{
m=s+((x-a[s].cheie)*(d-s))/(a[d].cheie-a[s].cheie);
if (x>a[m].cheie) s=m+1;
else d=m-1;
}
while ((s<=d) && (a[m].cheie!=x) && (a[d].cheie!=a[s].cheie)
&& (x>=a[s].cheie) && (x<=a[d].cheie));
if (a[m].cheie==x) return m;
else return ultim;
}
-------------------------------------------------------------------
Proprietate. Cutarea prin interpolare utilizeaz att n caz de reuit ct i n caz de
nereuit mai puin de lg
(lg
(n) +1) comparaii [Se 88].
Funcia lg
(lg n) este o funcie care crete extrem de ncet,
Astfel spre exemplu, pentru valori ale lui n de ordinul 10
9
, lg(lg
n)<
5.
1.4.3. Structura articol. Tipul de date abstract articol
Metoda cea mai general de a obine a tipuri structurate este aceea de a reuni
elemente ale mai multor tipuri, unele dintre ele fiind la rndul lor structurate, ntr-un tip
compus.
Exemple n acest sens sunt:
o Numerele complexe din matematic care sunt compuse din dou numere
reale
o Punctele de coordonate compuse din dou sau mai multe numere reale n
funcie de numrul de dimensiuni ale spaiului la care se refer.
n matematic un astfel de tip compus se numete produsul cartezian al tipurilor
constitutive.
Setul de valori al tipului compus const din toate combinaiile posibile ale valorilor
tipurilor componente, selectnd cte o singur valoare din fiecare.
O astfel de combinaie se numete n-uplu;
Numrul total de combinaii este egal cu produsul numerelor de elemente ale fiecrui tip
constitutiv, adic cardinalitatea tipului compus este egal cu produsul cardinalitilor
tipurilor constitutive.
Termenul care descrie o dat compus de aceast natur este cuvntul record
(articol) respectiv struct
n secvenele [1.4.3.a.] i [1.4.3.b.] se prezint modul generic de definire a unui tip
articol n limbajele Pascal respectiv C.
------------------------------------------------------------
{Definire Tip articol - Varianta Pascal}
TYPE TipArticol = RECORD
NumeCmp
1
: Tip
1
;
NumeCmp
2
: Tip
2
;
[1.4.3.a]
...
NumeCmp
n
: Tip
n
END; {RECORD}
------------------------------------------------------------
//Definire Tip articol - Varianta C
typedef struct {
tip
1
numeCmp
1
;
tip
2
numeCmp
2
;
[1.4.3.b]
...
tip
n
numeCmp
n
;
} numeTip;
--------------------------------------------------------
Exemple de definire a unor tipuri de date articol.
--------------------------------------------------------
{Exemple de definire a tipului articol}
TYPE complex = RECORD
re: real;
im: real
END;{RECORD complex}
data = RECORD
zi: 1..31;
luna: 1..12;
an: 1..2010 [1.4.3.c]
END;{RECORD data}
persoana = RECORD
nume: string[12];
prenume: string[12];
dataNastere: data;
sitSociala: (necasatorit, casatorit, divortat);
sex: (barbatesc,femeiesc)
END;{RECORD persoana)
--------------------------------------------------------
Identificatorii NumeCmp
1
,
NumeCmp
2
,....
NumeCmp
n
introdui la
definirea tipului, sunt nume conferite componentelor individuale ale acestuia.
Ei sunt utilizai n selectorii de articol care permit accesul la cmpurile unei variabile
structurate de tip articol.
Pentru o variabil x:TipArticol
, cea de-a i-a component, adic cel de-al i-lea
cmp poate fi precizat prin notaia "dot" sau "punct":
x.NumeCmp
i
O atribuire a respectivei componente poate fi precizata prin construcia sintactic:
x.NumeCmp
i
:= x
i
unde x
i
este o valoare (expresie) de tip Tip
i
.
In secvena [1.4.3.d] apar cteva exemple de instaniere a tipurilor articol anterior
definite.
------------------------------------------------------------
{Exemple de instaniere a structurilor articol}
VAR z:complex;
d:data;
p:persoana;
z.im (de tip real) [1.4.3.d]
d.luna (de tip subdomeniu 1..12)
p.nume (de tip string)
p.dataNastere (de tip data)
p.dataNastere.zi (de tip subdomeniu 1..31)
--------------------------------------------------------
Exemplul care se refer la tipul persoana, pune n eviden faptul c constituenii
unui tip articol pot fi la rndul lor structurai, aceast situaie conducnd la concatenarea
selectorilor.
n mod evident, tipuri structurate diferite pot fi utilizate ntr-o manier ncuibat.
Astfel cea de-a i-a component a unui tablou a
, care la rndul su este o
component a unei variabile structurate x se precizeaz prin construcia
sintactic:
x.a[i]
Componenta avnd numele de selector NumeCmp aparinnd celei de-a i-a
componente de tip articol a unui tablou a este precizat prin construcia:
a[i].NumeCmp.
Din punct de vedere formal tipul de date abstract articol este prezentat n secvena
[1.4.3.e.].
------------------------------------------------------------
TDA Articol [1.4.3.e]
Modelul matematic:
O
colecie
finit
de
elemente
numite
cmpuri,
care
pot
aparine
unor
tipuri
diferite.
Exista
o coresponden
biunivoc ntre lista identificatorilor de cmpuri i
colecia de elemente.
Notatii:
a - obiect de tip articol;
id - identificator nume de cmp;
e - obiect
de
acelai
tip
cu
cmpul
id
din
articolul
a.
Operatori:
DepuneAr t i col (a,id,e) - procedur care memoreaz
valoarea lui e n cmpul id al lui a;
e:= FurnizeazArticol(a,id) - funcie care returneaz
valoarea cmpului id din a.
------------------------------------------------------------
Secvenele [1.4.3.f.] i [1.4.3.g.] prezint cte un exemplu de implementare n Pascal
respectiv C a tipului de date abstract articol.
------------------------------------------------------------
{Exemplu de implementare Pascal}
TYPE tip
1
= ... ; {tipuri de cmpuri}
tip
2
= ... ;
....
tip
n
= ... ;
TipArticol = RECORD
c
1
: tip
1
;
c
2
: tip
2
; [1.4.3.f]
...
c
n
: tip
n
END;{RECORD TipArticol}
VAR a: TipArticol;
{DepuneArticol(a,c
i
,e)} a.c
i
:=e;
{FurnizeazaArticol(a,c
i
)} e:=a.c
i
;
------------------------------------------------------------
//Exemplu de implementare C
struct punct {
int x;
int y;
}
struct dreptunghi {
struct punct varf1;
struct punct varf2;
} [1.4.3.g]
struct punct p1; double dist;
struct dreptunghi fereastra;
dist=sqrt((double)(p1.x*p1.x)+(double)(p1.y*p1.y));
fereastra.varf1.x=188;
--------------------------------------------------------------
1.4.3.1. Articole cu variante
De multe ori, n practica programrii, este mai convenabil ca dou tipuri simple s fie
considerate variante ale aceluiai tip.
Spre exemplu, tipul coordonate despre care s-a amintit n seciunea precedent,
poate fi privind ca o reuniune a coordonatelor carteziene i polare ale cror
constitueni sunt respectiv (a) dou lungimi i (b) o lungime i un unghi.
Pentru a identifica varianta actual a unei astfel de variabile s-a introdus o a treia
component numit discriminator de tip sau cmp selector.
------------------------------------------------------------
{Exemplu 1 de articol cu variante}
TYPE tip = (cartezian,polar); [1.4.3.1.a]
coordonate = RECORD
CASE fel: tip OF
cartezian: (x,y: real);
polar: (r: real; fi: unghi)
END;{RECORD coordonate}
VAR p: coordonate;
{daca p.fel = cartezian exista cmpurile p.x si p.y}
{daca p.fel = polar exista cmpurile p.r si p.fi}
------------------------------------------------------------
Dac se consider variabila p:coordonate
, atunci numele cmpului
discriminator este p.fel iar numele coordonatelor sunt fie p.x i p.y n cazul unei
valori carteziene (p.fel = cartezian), fie p.r i p.fi n cazul unei valori
polare (p.fel = polar).
Foarte adesea, dou sau mai multe tipuri pot fi doar parial reunite. Aceast situaie
conduce la structura de articol cu variante.
Un exemplu n acest sens este tipul persoana1 din secvena [1.4.3.1.b]:
------------------------------------------------------------
{Exemplu 2 de articol cu variante}
TYPE sex: (barbatesc,femeiesc);
persoana1 = RECORD
nume,prenume: alfa; [1.4.3.1.b]
dataNastere: data;
situatieSociala: (necasatorit,casatorit,
divortat, vaduv);
CASE sexul: sex OF
barbatesc: (greutate: real; musta: boolean);
femeiesc : (masuri:ARRAY[1..3] OF integer)
END;{RECORD persoana1}
--------------------------------------------------------
Forma general generic a unui tip articol cu variante este:
--------------------------------------------------------
{Definirea generica a unui articol cu variante}
TYPE TipArticolVariante = RECORD
s
1
: t
1
; s
2
: t
2
;...s
n-1
: t
n-1
;
CASE s
n
: t
n
OF
c
1
: (s
1,1
: t
1,1
;...s
1,n1
: t
1,n1
);
......
c
k
: (s
k,1
: t
k,1
;...s
k,nk
: t
k,nk
) [1.4.3.1.c]
......
c
m
:(s
m,1
: t
m,1
;...s
m,nm
: t
m,nm
)
END;{RECORD TipArticolVariante}
-------------------------------------------------------
s
i
i s
ij
sunt numele selectorilor componentelor tipurilor constitutive t
i
respectiv
t
i,j
,
s
n
este numele cmpului discriminator avnd tipul t
n
.
Constantele c
1
,.......,c
m
sunt valori ale tipului (scalar) t
n
.
O variabil x a tipului TipArticolVariante const din componentele
x.s
1
, x.s
2
,...,x.s
n
, x.s
k,1,
...,x.s
k,nk
dac i numai dac valoarea curent a cmpului discriminator x.s
n
=
c
k
.
Componentele x.s
1
,..., x.s
n
reprezint partea comun a celor m variante.
Deoarece utilizarea selectorului de component x.s
k,h
(1
<
h
<
n
k
) n condiiile n
care
x.s
n
<>
c
k
reprezint o grav eroare de programare, se recomand gruparea
operaiilor de prelucrare corespunztoare variantelor individuale, n instrucii selective
(CASE) a cror structur reflect ntocmai structura tipului articol cu variante
prelucrat [1.4.3.1.d].
------------------------------------------------------------
{Exemplu de utilizare a unui articol cu variante}
VAR x: TipArticolVariante;
BEGIN {secvena de prelucrare}
. . .
CASE x.s
n
OF
c
1
: S
1
;
c
2
: S
2
;
...
c
m
: S
m
END;{CASE} [1.4.3.1.d]
....
END; {secvena de prelucrare}
------------------------------------------------------------
S
k
reprezint o secven de program corespunztoare cazului n care x trebuie
prelucrat n varianta k, adic este selectat spre execuie numai cnd cmpul indicator
x.s
n
are valoarea c
k
.
n aceast situaie singura grij a programatorului este aceea ca fiecare secven S
k
s
conin selectori referitori numai la varianta k:
x.s
k,1
, x.s
k,2
,..., x.s
k,nk
Echivalentul mai simplu al unui articol cu variante din Pascal este union n limbajul
C. n secvena [1.4.3.1.e] se prezint un exemplu de astfel de structur.
------------------------------------------------------------
// Articol cu variante - implementare C
struct {
char *nume;
int fanioane;
int tip_uniune; //cmp discriminator
union {
int ival; [1.4.3.1.e]
float rval;
char strval;
} u;
} tab_simb[NRSIMB]
------------------------------------------------------------
Exemplul 1.4.3.1. Prelucrarea articolelor cu variante. Considernd tipul de date
coordonate definit n secvena [1.4.3.1.a], se cere s se calculeze distana dintre
punctele a i b,ambele de tip coordonate, indiferent de maniera n care sunt
exprimate.
------------------------------------------------------------
{Exemplu de prelucrare a unui articol cu variante - Pascal}
{VAR a,b: coordonate;
CASE a.fel OF [1.4.3.1.f]
cartezian: CASE b.fel OF
cartezian: d:= Sqrt(Power((a.x-b.x),2.0)
+Power((a.y-b.y),2.0));
polar: d:= Sqrt(Power((a.x-b.r*Cos(b.fi)),2.0)
+Power((a.y-b.r*Sin(b.fi)),2.0))
END;
polar: CASE b.fel OF
cartezian: d:= Sqrt(Power((a.r*Cos(a.fi)-b.x),2.0)
+Power((a.r*Sin(a.fi)-b.y),2.0));
polar: d:=Sqrt(Power((a.r),2.0)+Power((b.r),2.0)
+2*a.r*b.r*Cos(a.fi-b.fi))
END
END;
-----------------------------------------------------------
1.4.4. Structura mulime. Tipul de date abstract mulime
Cea de-a treia structur fundamental alturi de tablou i articol este structura
mulime, care se definete astfel:
------------------------------------------------------------
TYPE TipMultime = SET OF TipDeBaza; [1.4.4.a]
------------------------------------------------------------
Valorile posibile ale unei variabile x a tipului TipMultime, sunt mulimi de
elemente ale lui TipDeBaza.
Se numete mulime de baz mulimea tuturor elementelor lui TipDeBaza.
Mulimea tuturor submulimilor de elemente ale lui TipDeBaza formeaz puterea
mulimii de baz.
Tipul TipMultime are ca domeniu de valori, puterea mulimii de baz asociat lui
TipDeBaza.
Cu alte cuvinte fiind dat mulimea de baz, prin mulime vom nelege orice
submulime a acesteia, inclusiv mulimea vid, respectiv orice element al puterii
mulimii de baz corespunztoare
Spre exemplu dac se alege drept mulime de baz {a,b,c}, atunci se pot utiliza
urmtoarele opt submulimi drept constante ale tipului mulime asociat tipului de baz
[1.4.4.b].
------------------------------------------------------------
TYPE TipMultime = SET OF (a,b,c); [1.4.4.b]
[]; [a]; [b]; [c]; [a,b]; [a,c]; [b,c]; [a,b,c];
------------------------------------------------------------
n secvena [1.4.4.c] se prezint cteva exemple de definire a unor tipuri de date mulime,
de instaniere i de utilizare a unor structuri de date asociate.
------------------------------------------------------------
TYPE TipCuloare = (alb,rosu,portocaliu,galben,verde,
albastru,maro,negru);
multimeLitere = SET OF char;
multimeCifre = SET OF '0'..'9';
setOperatori = SET OF('+','-','*','/');
culori = SET OF TipCuloare;
VAR l1,l2: multimeLitere;
c1,c2: multimeCifre; [1.4.4.c]
o1: setOperatori;
cul1,cul2: culori;
paleta: ARRAY[1..10] OF culori; {tablou de multimi}
BEGIN {exemplu de utilizare}
...
l1:= ['a','b','d']; l2:= ['a','b','c','d','e','f']
c1:= []; c2:= ['0','4','5','7']
o1:= ['+','*'];
cul1:= [rosu,maro,negru];
cul2:= [alb];
paleta[3]:= [galben,verde,rosu,portocaliu];
...
END; {exemplu de utilizare}
--------------------------------------------------------
Cardinalitatea unui tip mulime este:
Card(TipMultime)=2
Card(TipDeBaza)
Aceast formul poate fi dedus simplu din faptul c fiecare dintre elementele lui
TipDeBaza (al cror numr este egal cu cardinalitatea lui TipDeBaza), poate fi
reprezentat printr-una din valorile "absent" sau "prezent" i c toate elementele sunt
independente unele fa de altele.
n cadrul tipului mulime se definesc urmtoarele legi de compoziie intern, valabile
pentru dou mulimi de acelai tip:
asignare(:=),
reuniune (OR sau +),
scdere (-)
,
intersecie (AND sau *),
negare (NOT).
De asemenea se mai definesc i operatorii relaionali care conduc la valori booleene:
egalitate(=),
inegalitate (<>),
incluziune (<=),
incluziune invers (>=).
Dac e este o expresie aparinnd lui TipDeBaza i m este o variabil de tip
mulime avnd asociat acelai tip de baz, atunci este definit i relaia de
apartenen, notat cu e
IN
m
.
Din punct de vedere formal tipul de date abstract mulime se poate defini ca i n
secvena [1.4.4.d] iar n secvna [1.4.4.e] apare un exemplu de implementare n
limbajul Pascal.
------------------------------------------------------------
TDA Multime
Modelul matematic: elementele aparin unui tip ordinal
finit i sunt membre ale unei mulimi definite n sens
matematic.
Notaii: [1.4.4.d]
TipElement - tipul de baza;
S,T,V - mulimi cu elemente de TipElement;
e - valoare (obiect) de TipElement;
b - valoare boolean.
Operatori:
CopiazMulime(S,T) - procedur
care
copiaz mulimea
T n mulimea S;
b:= Egal i t at eMul t i me(S,T) - funcie care returneaz
true dac S este egal cu T;
b:= AparineMulime(S,e) - funcie care returneaz
true dac e este membru al lui S;
b:= Submulime(S,T) - funcie care returneaz true
dac S este submulime a lui T;
V:= Reuni une(S,T) - funcie
care
returneaz
mulimea
V ca reuniune a mulimilor S i T;
V:= Intersecie(S,T) - funcie care returneaz
mulimea V ca i intersecie a lui S i T;
V:= Diferena(S,T) - funcie
care
returneaz
mulimea
V ca i diferen a lui S i T;
MulimeVid(S) - procedur care-l face pe S identic
cu mulimea vid;
S:= CreazMulime(e) - funcie
care
creeaz
mulimea
S care conine doar elementul e.
------------------------------------------------------------
{Implementare a tipului mulime - varianta Pascal}
TYPE TipElement = ... ; [1.4.4.e]
TipMulime = SET OF TipElement;
VAR S,T,V: TipMultime;
e: TipElement;
b: boolean;
{CopiazMulime(S,T)} S:= T;
{EgalitateMulime(S,T)} b:= (S=T);
{AparineMulime(S,e)} b:= (e IN S);
{Submulime(S,T)} b:= (S<=T);
{Reuniune(S,T)} V:= S+T;
{Intersecie(S,T)} V:= S*T;
{Diferen(S,T)} V:= S-T;
{MulimeVid(S)} S:= [];
{CreazMulime(e)} S:= [e];
-----------------------------------------------------------
Exemplu 1.4.4.a. Construcia unei mulimi elementare. O valoare a unei variabile
de tip mulime poate fi construit n dou moduri:
o Static prin asignarea variabilei cu o constant a tipului respectiv [1.4.4.f];
o Dinamic prin asignarea variabilei cu o expresie de calcul avnd drept operanzi,
mulimi ncadrate n acelai tip de baz. n acest caz trebuie s se porneasc ns
de la o mulime dat prin elementele sale, numit mulime elementar [1.4.4.g].
------------------------------------------------------------
{Construcia static a unei mulimi}
VAR litera: multimeLitere; cifra: multimeCifre;
BEGIN
... [1.4.4.f]
litera:=['a'..'z'];
cifra:=['0'..'9'];
...
END;
------------------------------------------------------------
{Construcia dinamic a unei mulimi}
VAR litera:
multimeLitere; cifra:
multimeCifre; ch:
char;
BEGIN
litera:= []; {multimi elementare}
cifra:= []; [1.4.4.g]
FOR ch:= 'a' TO 'z' DO
litera:= (litera + [ch]);
FOR ch:= '0' TO '9' DO
cifra:= (cifra + [ch]);
...
END;
------------------------------------------------------------
1.4.5. Structura secven. Tipul de date abstract secven
Caracteristica comun a structurilor de date prezentate pn n prezent (tablouri,
articole, mulimi) este aceea c toate au cardinalitatea finit, respectiv cardinalitatea
tipurilor lor componente este finit.
Din acest motiv, implementarea lor nu ridic probleme deosebite.
Cele mai multe dintre aa numitele structuri avansate: secvenele, listele, arborii,
grafurile, etc, sunt caracterizate prin cardinalitate infinit.
Aceast diferen fa de structurile clasice este de profund importan avnd
consecine practice semnificative.
Spre exemplu structura secven avnd tipul de baz T
0
se definete dup cum
urmeaz:
------------------------------------------------------------
S
0
=< > (secvena vid)
S
i
=<S
i-1
,s
i
> unde 0
<
i i s
i
T
0
------------------------------------------------------------
Cu alte cuvinte, o secven cu tipul de baz T
0
, este:
o Fie o secven vid
o Fie o concatenare a unei secvene (cu tipul de baz T
0
) cu o valoare (s
i
) a
tipului T
0
.
Definirea recursiv a unui tip secven conduce la o cardinalitate infinit.
o Fiecare valoare a tipului secven conine n realitate un numr finit de
componente de tip T
0
,
o Acest numr este nemrginit deoarece, pornind de la orice secven se poate
construi o secven mai lung.
O consecin important a acestui fapt este:
Volumul de memorie necesar reprezentrii unei structuri avansate, nu poate fi
cunoscut n momentul compilrii,
Ca atare, este necesar aplicarea unor scheme de alocare dinamic a
memoriei, n care memoria este alocat structurilor care "cresc" i este eliberat
de ctre structurile care "descresc".
Pentru a implementa aceast cerin, este necesar ca limbajul superior utilizat n
implementare s fie prevzut cu acces la funcii sistem care permit:
Alocarea
/
eliberarea dinamic a memoriei
Legarea
/
referirea dinamic a componentelor
n aceste condiii cu ajutorul instruciilor limbajului pot fi descrise i utilizate
structuri avansate de date.
Tehnicile de generare i de manipulare a unor astfel de structuri avansate sunt
prezentate n capitolele urmtoare ale cursului
Structura secven este din acest punct de vedere o structur intermediar;
Ea este o structur avansat din punctul de vedere al cardinalitii care este
infinit
Este ns att de curent utilizat nct includerea sa n mulimea structurilor
fundamentale este consacrat.
Aceast situaie este influenat i de faptul c alegerea unui set potrivit de
operatori referitori la structura secven, permite implementatorilor s adopte
reprezentri potrivite i eficiente ale acestei structuri.
Drept consecin, mecanismele alocrii dinamice a memoriei devin suficient
de simple pentru a permite o implementare eficient, neafectat de detalii, la
nivel de limbaj superior.
1.4.5.1. Tipul de date abstract secven
Includerea structurii secven n rndul structurilor fundamentale, presupune
restrngerea setului de operatori de o asemenea manier nct se permite numai accesul
secvenial la componentele structurii.
Aceast structur este cunoscut i sub denumirea de fiier secvenial sau pe scurt
fiier.
Structura secven este supus unicei restricii de a avea componente de acelai tip,
cu alte cuvinte este o structur omogen.
Numrul componentelor, denumit i lungime a secvenei, se presupune a fi
necunoscut att n faza de compilare, ct i n faza de execuie a codului.
Mai mult chiar, acest numr nu se presupune constant el putndu-se modifica
n timpul execuiei.
Cardinalitatea tipului secven este n consecin infinit.
n dependen de maniera de implementare a structurilor de tip secven, acestea se
nregistreaz de regul pe suporturi de memorie extern reutilizabile cum ar fi benzile
magnetice sau discurile n alocare secvenial.
Acest lucru face posibil tratarea relativ simpl a structurilor de tip secven i
permite ncadrarea lor n rndul structurilor fundamentale, dei de drept ele aparin
structurilor dinamice.
Secvena este o structur ordonat. Ordonarea elementelor structurii este stabilit de
ordinea n timp a crerii componentelor individuale.
Datorit mecanismului de acces secvenial preconizat, selectarea prin indici a
componentelor individuale devine improprie.
n consecin la definirea unui tip de secven se precizeaz numai tipul de baz.
TYPE TipSecven = FILE OF TipDeBaz;
n cadrul unei secvene definite ca mai sus n orice moment este accesibil o singur
component, denumit component curent, care este precizat printr-un pointer
(indicator) asociat secvenei.
Acest indicator avanseaz secvenial, practic dup execuia oricrei operaii
asupra secvenei.
n plus oricrei secvene i se asociaz un operator boolean standard sfrit de fiier
notat cu Eof(f:TipSecventa) care permite sesizarea sfritului secvenei.
Modul concret de acces la componente, precum i posibilitile de prelucrare efectiv,
rezult din semantica operatorilor definii pentru tipul de date abstract secven este
prezentat sintetic n [1.4.5.1.a]
.
Implementrile recente ale limbajelor Pascal i C introduc n setul de instruciuni
accesibile programatorului i operatori pentru prelucrarea secvenelor implementate ca
i fiiere secveniale.
n secvena [1.4.5.1.b] apare o astfel de implementare definit n limbajul Pascal.
Variante asemntoare stau la dispoziie i n limbajul C.
------------------------------------------------------------
TDA Secven
Modelul matematic: secven de elemente de acelai tip. Un
indicator la secven indic elementul urmtor la care
se poate realiza accesul. Accesul la elemente este
strict secvenial.
Notaii:
TipElement - tipul
unui
element
al
secvenei.
Nu poate
fi de tip secven;
f - variabil secven;
e - variabil de TipElement; [1.4.5.1.a]
b - valoare boolean;
numeFisierDisc - ir de caractere.
Operatori:
At r i bui e(f,numeFisierDisc) - atribuie variabilei
secven f numele unui fiier disc precizat;
Rescr i e(f) - procedur
care
mut
indicatorul
secvenei la
nceputul lui f i deschide fiierul f n regim de
scriere. Dac fiierul f nu exist el este creat.
Daca f exist, vechea sa variant se pierde i se
creeaz un nou fiier f vid;
ResetSecven(f) - procedur care mut indicatorul la
nceputul secvenei f i deschide secvena n regim
de consultare. Dac f nu exist se semnaleaz eroare
de execuie;
DeschideSecven(f) - procedur care n anumite
implementri joac rol de rescrie sau reset de
secven;
b:= Eof (f) - funcie care returneaz valoarea true dac
indicatorul secvenei indic marcherul de sfrit de
fiier al lui f;
FurnizeazSecven(f,e) - procedur care acioneaz n
regim de consultare. Atta vreme ct Eof(f) este
fals, furnizeaz n e urmtorul element al secvenei
f i avanseaz indicatorul acesteia;
DepuneSecven(f,e) - pentru secvena f deschis n
regim
de
scriere,
procedura
copiaz
valoarea
lui e n
elementul urmtor al secvenei f i avanseaz
indicatorul acesteia;
Adaug(f) - procedur care deschide secvena f n
regim de scriere, poziionnd indicatorul la
sfritul acesteia, cu posibilitatea de a aduga
elemente noi numai la sfritul secvenei.
InchideSecvena(f) - nchide secvena.
------------------------------------------------------------
{Implementarea tipului secven - Varianta Pascal}
TYPE TipElement = ... ;
TipSecven = TEXT;
VAR f: TipSecven; [1.4.5.1.b]
e: TipElement;
numeFisierDisc: string;
{Atribuie(f,numeFisierDisc)} assign(f,numeFisierDisc)
{Rescrie(f)} rewrite(f)
{DepuneSecven(f,e)} write(f,e) ; writeln(...)
{ResetSecven(f)} reset(f)
{Eof(f)} eof(f)
{FurnizeazSecven(f,e)} read(f,e); readln(...)
{Adaug(f)} append(f)
{InchideSecven(f)} close(f)
------------------------------------------------------------
1.4.5.2. Tipul de date abstract fiier cu acces direct
Principalul dezavantaj al structurii secven const n faptul c accesul la
componentele sale se realizeaz n manier strict secvenial prin intermediul unui
pointer a crui poziionare este inaccesibil programatorului n mod direct.
Din acest motiv, pornind de la tipul de date abstract secven, a fost dezvoltat o
structur mai flexibil numit fiier cu acces direct.
Astfel, unui fiier cu acces direct i se asociaz un indicator prin intermediul cruia pot fi
accesate oricare din componentele fiierului.
n acest scop fiecare component a fiierului este identificat printr-un indice care i
precizeaz poziia n fiier exact ca i la structura tablou.
Numerotarea componentelor ncepe cu 0,1,2,... i continu pn la
DimensiuneFiier-1.
Crearea i modificarea structurii fiier cu acces direct se realizeaz ns tot n manier
secvenial.
Cu alte cuvinte, se pot aduga sau modifica nregistrri dar nu se pot insera
altele noi ntre cele existente.
Tipul de date abstract asociat acestei structuri apare n secvena [1.4.5.2.a] iar n
secvena [1.4.5.2.b] un exemplu de implementare Pascal.
------------------------------------------------------------
TDA Fiier cu acces direct
Modelul matematic: secven de elemente de acelai tip. Un
indicator asociat fiierului indic elementul la care
se
poate
realiza
accesul.
Acesta
poate
fi
oricare element
al
structurii.
Fiecare
component
a
structurii este
identificat
printr-un
indice.
Numartoarea ncepe cu
0,1,2,... i continu pn la DimensiuneFisier-1.
Notaii:
TipElement - tipul unui element al fiierului. Nu poate
fi de tip fiier;
f - fiier cu acces direct;
e - variabil de TipElement; [1.4.5.2.a]
i - indice n fiier.
Operatori:
At r i bui e(f,numeFisierDisc) - atribuie variabilei fiier
f numele unui fiier disc precizat;
Rescr i e(f)
-
procedur
care
mut
indicatorul
fiierului la
nceputul
acestuia.
Daca
fiierul f nu
exist el
este
creat.
Daca f exist,
vechea
sa
variant se pierde i
se creeaz un nou fiier f vid. Indicatorul asociat
fiierului ia valoarea 0;
Reset (f) - procedur care mut indicatorul la nceputul
fiierului f. Indicatorul ia valoarea 0. Daca f nu
exist se semnaleaz eroare;
Deschi deFi si er (f) - procedur care n anumite
implementri joac rol de rescrie sau reset
de fiier;
i:= Di mensi uneFi si er (f) - funcie care returneaz
numrul curent de componente al fiierului f
(numrul de componente memorate n f);
i:= PoziieFiier(f) - funcie care returneaz numrul
nregistrrii curente (cea precizat
de indicatorul fiierului). La deschiderea
unui fiier PoziieFiier ia valoarea 0;
Caut(f,i) - selecteaz o nregistrare precizat printr-
un numr poziionnd indicatorul fiierului pe
nregistrarea respectiv;
FurnizeazFiier(f,e) - procedur care furnizeaz n e
elementul curent al fiierului f i avanseaz
indicatorul acestuia;
Depune(f,e) - procedur care depune valoarea lui
e n fiierul f n poziia precizat de indicatorul
fiierului i avanseaz indicatorul la elementul
urmtor;
nchi deFi si er (f) - nchide fiierul f.
------------------------------------------------------------
{Implementarea tipului secven cu acces direct- Varianta
Pascal}
TYPE TipElement = ... ;
TipFisierAccesDirect = FILE OF TipElement;
TipIndice = integer;
VAR f: TipFisierAccesDirect;
e: TipElement; [1.4.5.2.b]
i: TipIndice;
{Rescrie(f)} rewrite(f)
{Reset(f)} reset(f)
{i:= DimensiuneFisier(f)} i:= filesize(f)
{i:= PozieFiier(f)} i:= filepos(f)
{Caut(f,i)} seek(f,i)
{DepuneFiier(f,e)} write(f,e);
writeln(...);
{FurnizeazFiier(f,e)} read(f,e); readln(...);
{nchideFiier(f)} close(f)
------------------------------------------------------------
Variante similare de implementare ale TDA secven exist i pentru limbajele C
respectiv C++.
Dac la nivel principial conceptele prezentate rmn valabile, la nivel de
implementare pot s apar diferenieri importante.
2. Noiunea de algoritm. Analiza algoritmilor
2.1. Noiunea de algoritm
Termenul algoritm i are sorgintea n numele autorului persan Abu Ja'far
Mohamed Ibn Musa Al Khowarismi care n anul 825 .e.n. a redactat un tratat
de matematic n care prezenta pentru prima dat metode de rezolvare generice
pentru anumite categorii de probleme.
Dicionarul explicativ al limbii romne [DEX75] ofer urmtoarea definiie:
"Ansamblu de simboluri i de operatori, folosii n matematic i logic,
permind gsirea n mod mecanic (prin calcul) a unor rezultate".
Alte dicionare ofer alte definiii, spre exemplu: "Orice metod de rezolvare a
unei anumite probleme".
n activitatea de programare vom conveni ca prin algoritm s nelegem o
"modalitate de rezolvare a unei probleme utiliznd un sistem de calcul".
Un algoritm este de fapt o metod sau o reet pentru a obine un rezultat dorit.
Un algoritm const din:
o Un set de date iniiale care abstractizeaz contextul problemei de rezolvat
o Un set de relaii de transformare care sunt operate pe baza unor reguli al
cror coninut i a cror succesiune reprezint nsi substana algoritmului
o Un set de rezultate preconizate sau informaii finale, care se obin
trecnd de regul printr-un ir de informaii (rezultate) intermediare.
Un algoritm se bucur de urmtoarele proprieti:
o Generalitate - un algoritm nu rezolv doar o anume problem ci o clas
generic de probleme de acelai tip;
o Finitudine - informaia final se obine din cea iniial trecnd printr-un
numr finit de transformri;
o Unicitate - transformrile i ordinea n care ele se aplic sunt univoc
determinate de regulile algoritmului. Ori de cte ori se aplic acelai
algoritm asupra aceluiai set de date iniiale se obin aceleai rezultate.
Scopul capitolului: analiza performanei algoritmilor.
2.2. Analiza algoritmilor
La ce servete analiza algoritmilor
?
o Permite precizarea predictiv a comportamentului algoritmului;
o Prin analiz pot fi comparai diferii algoritmi i poate fi astfel ierarhizat
experiena i ndemnarea diverilor productori [HS78].
Analiza algoritmilor se bazeaz de regul pe ipoteze:
o Sistemele de calcul sunt considerate convenionale adic ele execut cte
o singur instrucie la un moment dat
o Timpul total de execuie al algoritmului rezult din nsumarea timpilor
instruciilor individuale componente.
o Desigur aceast ipotez nu este valabil la sistemele de calcul paralelele i
distribuite.
n astfel de cazuri aprecierea performanelor se realizeaz de regul
prin msurtori experimentale i metode statistice.
n general, analiza unui algoritm se desfoar n dou etape:
o (1) Analiza aprioric
Const n aprecierea din punct de vedere temporal a operaiilor
care se utilizeaz i a costului lor relativ.
Conduce de regul la stabilirea expresiei unei funcii care
mrginete timpul de execuie al algoritmului
o (2) Testul ulterior
Const n stabilirea unui numr suficient de seturi de date iniiale
care s acopere practic toate posibilitile de comportament ale
algoritmului
Testarea comportamentul algoritmului pentru fiecare set n parte
Se finalizeaz prin culegerea unor date n baza crora pot fi
elaborate o serie de statistici referitoare la consumul de timp
specific execuiei algoritmului n cauz (profilul algoritmului).
Concluzie:
o Analiza aprioric are drept scop principal determinarea teoretic a
ordinului de mrime al timpului de execuie al unui algoritm
o Testul ulterior are ca scop principal determinarea efectiv a acestui ordin
prin stabilirea profilului algoritmului
2.3. Notaii asimptotice
Ordinul de mrime al timpului de execuie al unui algoritm:
o Reprezint o msur a eficienei algoritmului
o Permite compararea relativ a variantelor de algoritmi.
Studiul eficienei asimptotice a unui algoritm, se realizeaz utiliznd mrimi de
intrare cu dimensiuni suficient de mari pentru a face relevant numai ordinul de
mrime al timpului de execuie al algoritmului.
Intereseaz cu precdere limita la care tinde timpul de execuie al algoritmului
odat cu creterea nelimitat a dimensiunii intrrii.
De regul, un algoritm care este asimptotic mai eficient dect alii, va constitui
cea mai bun alegere i pentru intrri de dimensiuni mici i foarte mici.
2.3.1. Notaia (teta)
Pentru aprecierea limitei ordinului de mrime al timpului de execuie al unui
algoritm se utilizeaz notaia .
Definiie. Fiind dat o funcie g(n), prin (g(n)) se desemneaz o mulime de
funcii definit astfel:
------------------------------------------------------------
(g(n)) = { f(n): exist constantele pozitive c
1
, c
2
i n
0
astfel nct
0
c
1
g(n) f(n)
c
2
g(n) pentru n
n
0
} [2.3.1.a]
------------------------------------------------------------
Se spune c o funcie f(n) aparine mulimii (g(n)), dac exist constantele
pozitive c
1
si c
2
, astfel nct ea poate fi cuprins (ca un "sandwich") ntre c
1
g(n)
i c
2
g(n) pentru un n suficient de mare.
Fig.2.3.a. Reprezentarea lui f(n) = (g(n))
Dei (g(n)) reprezint o mulime de funcii, se utilizeaz uzual notaia f(n)
=
(g(n)), cu semnificaia f(n) este
(g(n))
, indicnd astfel faptul c
f(n) este
membru al lui (g(n) sau c f(n) (g(n)) [2.3.1.b].
------------------------------------------------------------
f(n)
=
(g(n))
[2.3.1.b]
------------------------------------------------------------
Cu alte cuvinte pentru orice n > n
0
, f(n) este egal cu g(n) n interiorul unui
factor constant.
Se spune ca g(n) este o margine asimptotic strns ("asymptotically tight bound")
a lui f(n).
Definiia lui necesit ca fiecare membru a lui (g(n)) s fie asimptotic pozitiv,
deci f(n) s fie pozitiv pentru valori suficient de mari ale lui n.
n practic, determinarea lui n cazul unei expresii, se realizeaz de regul
lund n considerare termenii de ordinul cel mai mare i neglijnd restul
termenilor.
f(n)
c
2
g(n)
c
1
g(n)
n
n
0
Aceast afirmaie poate fi demonstrat intuitiv, utiliznd definiia formal a lui
n a arta c
) ( 3
2
1
2 2
n n n =
o Pentru aceasta, constantele c
1
, c
2
i n
0
trebuiesc determinate astfel nct,
pentru orice n n
0
s fie valabil relaia:
2
2
2 2
1
3
2
1
n c n n n c .
o Se mpart membrii inegalitii cu n
2
i se obine
2 1
3
2
1
c
n
c
o Inegalitatea din dreapta este valabil pentru orice n 1 dac l alegem pe
c
2
1/2.
o Inegalitatea din stnga este valabil pentru orice valoare a lui
n 7
dac se
alege c
1
1/14
.
o Astfel, alegnd c
1
= 1/14
, c
2
= 1/2 i n
0
= 7 se poate verifica simplu c
) ( 3
2
1
2 2
n n n =
------------------------------------------------------------
Exemplul 2.3.1. Stabilirea funciei g(n) pentru o funcie polinomial.
Pornind de la observaia ca termenii de ordin inferior ai unei funcii asimptotice
pozitive pot fi neglijai
Dac se alege pentru c
1
o valoare care este cu puin inferioar coeficientului termenului
celui mai semnificativ
Dac se alege pentru c
2
o valoare uor superioar aceluiai coeficient
Inegalitile impuse de notaia sunt satisfcute.
Coeficientul termenului celui mai semnificativ poate fi n continuare omis, ntruct el
modific pe c
1
i pe c
2
doar cu un factor constant egal cu coeficientul.
Fie spre exemplu funcia polinomial:
0
2
> + + = a c n b n a ) n ( f
o Neglijnd termenii de ordin inferior lui 2, se ajunge la concluzia ca
f(n) = (n
2
).
o Acest lucru poate fi demonstrat i formal alegnd pentru coeficieni urmtoarele
valori:
------------------------------------------------------------
4
1
a
c = ,
4
7
2
a
c = i
=
a
c
a
b
max n , 2
0
[2.3.1.c]
------------------------------------------------------------
n baza acelorai considerente, pentru orice funcie polinomial p(n) de ordinul n
unde a
i
este constant i a
d
> 0, este valabil afirmaia p(n) = (n
d
) ( [2.3.1.d]).
------------------------------------------------------------
Dac
=
=
d
i
n a p(n)
0
i
i
unde
i
a= constant i 0
d
> a
atunci
) (n p(n)
d
=
[2.3.1.d]
------------------------------------------------------------
Deoarece o funcie polinominal de grad zero este o constant, despre orice funcie
constant se poate spune ca este (n
0
) sau (1).
Dei acesta este un abuz de interpretare (deoarece n nu tinde la infinit), prin
convenie (1) desemneaz fie o constant fie o funcie constant n raport cu o
variabil.
------------------------------------------------------------
2.3.2. Notaia O (O mare)
Notaia O desemneaz marginea asimptotic superioar a unei funcii. Pentru o
funcie dat g(n), se definete O(g(n)) ca i mulimea de funcii:
------------------------------------------------------------
O(g(n)) = { f(n): exist constantele pozitive c i n
0
astfel nct
0 f(n) c
g(n) pentru n n
0
} [2.3.2.a]
------------------------------------------------------------
Notaia O se utilizeaz pentru a desemna o margine superioar a unei funcii n
interiorul unui factor constant.
Pentru toate valorile n superioare lui n
0
, valoarea funciei f(n) este pe sau
dedesubtul lui g(n) (fig.2.3.b ).
Fig.2.3.b. Reprezentarea lui f(n) = O(g(n))
Pentru a preciza c o funcie f(n) este membr a lui O(g(n)) se utilizeaz notaia
f(n) = O(g(n)).
Faptul c f(n) este (g(n)) implic c f(n) = O(g(n)) deoarece notaia este mai
puternic dect notaia O. Formal acest lucru se precizeaz prin relaia [2.3.2.b].
c g(n)
f(n)
n
n
0
------------------------------------------------------------
(g(n)) O(g(n)) [2.3.2.b]
------------------------------------------------------------
n consecin, deoarece s-a demonstrat faptul c orice funcie ptratic
a
n
2
+
b
n
+
c
, a > 0 este (n
2
), n baza relaiei [2.3.2.b] rezult ca aceasta
funcie este implicit i O(n
2
).
Este surprinztor faptul c din aceleai considerente, funcia liniara a
n
+
b este
de asemenea O(n
2
), lucru uor de verificat dac se alege
c = a
+
|
b
| i
n
0
= 1.
Notaia O este de obicei cea mai utilizat n aprecierea timpului de execuie al
algoritmilor respectiv a performanei acestora.
Ea poate fi uneori apreciat direct din inspectarea structurii algoritmului, spre
exemplu existena unei bucle duble conduce imediat la o margine de ordinul O(n
2
)
Deoarece notaia O descrie o margine superioar, cnd este utilizat pentru a
mrgini cazul cel mai defavorabil de execuie al unui algoritm, prin implicaie ea
mrginete superior comportamentul algoritmului n aceeai msur pentru
orice intrare.
In cazul notaiei lucrurile difer.
o Spre exemplu, daca (n
2
) mrginete superior cel mai defavorabil timp de
execuie al unui algoritm de sortare prin inserie, aceasta nu nseamn c
(n
2
) mrginete orice intrare.
o Astfel, dac intrarea este gata sortat, algoritmul dureaz un timp
proporional cu (n).
Tehnic vorbind, afirmaia c timpul de execuie al unui algoritm de sortare este
O(n
2
) constituie un abuz de limbaj.
Corect: indiferent de configuraia intrrii de dimensiune n, pentru orice valoare a
lui n timpul de execuie al algoritmului pentru setul corespunztor de intrri este
O(n
2
).
Cele mai obinuite ordine de mrime ale notaiei O se afl n relaiile de ordine
prezentate n [2.3.2.c], iar reprezentarea lor grafic la scar logaritmic apare n
fig.2.3.c.
------------------------------------------------------------
O(1) < O(log
n) < O(n) < O(n log n) < O(n
2
) < O(n
3
) <
< O(2
n
) < O(10
n
) < O(
n
!
) < O(n
n
) [2.3.2.c]
------------------------------------------------------------
Fig.
2.3.c. Ordine de mrime ale notaiei O
n acelai context n [2.3.2.d] se prezint cteva sume ntregi utile care sunt
frecvent utilizate n calculul complexitii algoritmilor.
------------------------------------------------------------
) n (
n n
i
n
i
2
1
O
2
) 1 (
=
+
=
=
) n (
n n n
i
n
i
3
1
2
O
6
) 1 2 ( ) 1 (
=
+ +
=
=
) n (
n n
i
n
i
4
2 2
1
3
O
4
) 1 (
=
+
=
=
[2.3.2.d]
) (
1
1
1 1
O
1
O
1
) (
+
=
+ +
=
+
= +
+
=
k
n
i
k k
k
n
k
n
k
n
i
= =
=
1
1 2
) 1 (
n
i
n
i
i i
-----------------------------------------------------------------
2.3.3. Aritmetica ordinal a notaiei O
n vederea aprecierii complexitii algoritmilor n raport cu notaia O, a fost
dezvoltat o aritmetic ordinal specific care se bazeaz pe o serie de reguli
formale [De89].
Aceste reguli sunt prezentate n continuare.
o Regula 1. O(k) < O(n) pentru k
.
o Regula 2. Ignorarea constantelor: k f(n) = O(f(n)) pentru k i f
sau O(
k f
) = O(
f )
2
0
2
1
2
2
2
3
2
4
2
5
2
6
n log
2 (n)
n
2
n
n
2
n
3
2
16
2
12
2
8
2
4
2
1
log
2 (n)
o Regula 3. Tranzitivitate: dac f(n) O(g(n)) i g(n) O(h(n))
atunci f(n) O(h(n))
------------------------------------------------------------
Demonstraie:
f(n) = O(g(n)) c
1
,
n
1
f(n) c
1
g(n) pentru n > n
1
g(n) = O(h(n)) c
2
, n
2
g(n) c
2
h(n) pentru n > n
2
Se alege n
3
= max
{n
1
,
n
2
}. n relaia f(n) c
1
g(n) se nlocuiete
g(n)
cu
expresia de mai sus. Se obine relaia:
f(n)
c
1
( c
2
h(n))
Alegnd c
3
=
c
1
c
2
se obine f(n)
c
3
h(n) pentru n
>
n
3
deci f(n)
=
O(h(n)).
------------------------------------------------------------
o Regula 4. f(n) + g(n) = O(
max
{
f(n),
g(n)
}
o Regula 5. Dac f
1
(n) = O(
g
1
(n)) i f
2
(n) = O(
g
2
(n))
atunci f
1
(n)
f
2
(n) = O(
g
1
(n)
g
2
(n))
Utiliznd aceste reguli se poate calcula o estimare a lui O pentru o expresie
aritmetic dat, fr a avea valori explicite pentru k i n.
------------------------------------------------------------
Exemplul 2.3.3. Se consider expresia
8
log(n) + 4
n
3 / 2
i se cere o estimare a sa n termenii notaiei O.
Se procedeaz dup cum urmeaz:
o log
(n) = O(n
1/ 2
) deoarece logaritmul unui numr este mai mic dect orice
putere pozitiv a numrului n baza urmtoarei teoreme:
o Fie a
>
0 i a
1
;
o Pentru exponent d
>
0 exist un numr N astfel nct pentru
x
>
N
avem
log
a
x
<
x
d
.
o n log(n) = O(n
n
1/2
) = O(n
3/2
) (Regula 5).
o 8
n log(n) = O(n
3/2
) (Regula 2).
o 4
n
3/2
= O(n
3/2
) (Regula 2).
o 8
n log(n) + 4
n
3/2
= O(max
{
8
n log(n), 4
n
3/2
}) =
=O(max
{
n
3/2
, n
3/2
}) = O(n
3/2
) (Regula 4).
Rezult n urma estimrii c expresia 8
n log(n) + 4
n
3/2
este O(n
3/2
).
------------------------------------------------------------------------
2.3.4. Notaia (Omega mare)
Notaia (omega mare) precizeaz o margine asimptotic inferioar.
Pentru o funcie dat g(n), prin (g(n)) se precizeaz mulimea funciilor
------------------------------------------------------------
(g(n))
= {f(n)
: exist constantele pozitive c si n
0
astfel nct
f(n) g(n) c 0
pentru
0
n n
} [2.3.4.a]
------------------------------------------------------------
Fig.
2.3.d. Reprezentarea lui f(n)=(g)n))
------------------------------------------------------------
Teorem: Pentru oricare dou funcii f(n) i g(n)
, f(n) =
(g(n))
dac i numai dac f(n) = O(g(n)) i f(n) =
(g(n))
. [2.3.4.b]
------------------------------------------------------------
Spre exemplu s-a demonstrat c
) (
2 2
n c n b n a = + +
pentru orice valori ale
constantelor a, b, c cu a >
0 . De aici rezult imediat c
) (
2 2
n c n b n a = + +
.
Deoarece notaia descrie o limit inferioar, atunci cnd este utilizat
pentru a mrgini cazul cel mai favorabil de execuie al unui algoritm, prin
implicaie ea mrginete inferior orice intrare arbitrar a algoritmului.
2.3.5. Utilizarea notaiilor asimptotice , O i
Exemplul a). Se consider formula
) n ( n n n + = + +
2 2
2 1 3 2
. Cum se
interpreteaz aceast formul
?
o n general, cnd ntr-o formul apare o notaie asimptotic se consider c
ea ine locul unei funcii care nu se nominalizeaz explicit.
o Astfel n exemplul de mai sus avem:
) n f( n n n + = + +
2 2
2 1 3 2
, unde
) n ( ) n f(
.
o Se observ faptul c n acest caz
1 3 + = n ) n f(
, care este ntr-adevr
(n).
Exemplul b). Utilizarea notaiei asimptotice poate fi de folos n eliminarea
detaliilor neeseniale ale unei ecuaii.
o Spre exemplu fie relaia recursiv:
) n ( ) / n ( T ) n ( T + = 2 2
c
g(n)
n
0
n
f
(n)
o Dac prezint interes doar comportamentul asimptotic al lui T(n), nu e
necesar s fie specificai toi termenii de ordin inferior.
o Ei sunt inclui ntr-o funcie anonim, precizat prin (n).
Exemplul c). Ecuaia
) n ( ) n ( n
2 2
2 = +
se interpreteaz astfel: indiferent de
maniera n care se alege funcia anonim din partea stng a ecuaiei, exist o
modalitate de a alege funcia anonim din partea dreapt, astfel nct semnul "="
s indice o ecuaie adevrat.
o n cazul de fa, pentru orice funcie
) n ( ) n f(
, exist o funcie
) n ( ) n g(
2
, astfel nct
) n g( ) n f( n = +
2
2
pentru orice n.
o De fapt membrul drept al ecuaiei evideniaz un grad mai redus de
detaliere dect cel stng.
Exemplul d). Relaiile de acest tip pot fi nlnuite, spre exemplu:
) n ( ) n ( n n n
2 2 2
2 1 3 2 = + = + +
o Prima ecuaie precizeaz faptul c exist o funcie
) n ( ) n f(
astfel nct
) n f( n n n + = + +
2 2
2 1 3 2
pentru toi n.
o A doua ecuaie precizeaz c pentru orice
) n ( ) n g(
exist o funcie
) n ( ) n h(
2
astfel nct
) n h( ) n g( n = +
2
2
pentru toi n.
o Aceast interpretare implic
) n ( n n
2 2
1 3 2 = + +
ceea ce de fapt
sugereaz intuitiv lanul de egaliti.
2.3.6. Notaia o (o mic)
Marginea asimptotic superioar desemnat prin notaia O, poate fi din punct de vedere
asimptotic strns sau lejer (lax).
Pentru desemnarea unei margini asimptotice lejere se utilizeaz notaia o (o mic).
-----------------------------------------------------------
(g(n)) o
= {
f(n)
: pentru orice constant pozitiv c
>
0 exist o constant n
0
>
0
astfel nct
g(n) c f(n) < 0
pentru
0
n n } [2.3.6.a]
-----------------------------------------------------------
Principala diferen dntre notaiile O i o rezid n faptul c n cazul f(n) =
O(g(n)), marginea 0 f(n) c
g(n) este valabil pentru anumite constante c >
0, n timp ce f(n) =o(g(n)), marginea 0 g(n) < c
g(n) este valabil pentru orice
constant c > 0
.
Intuitiv, n notaia o, funcia f(n) devine nesemnificativ n raport cu g(n) cnd n
tinde la infinit [2.3.6.b].
------------------------------------------------------------
f(n) = o(g(n)) implic
0 =
g(n)
f(n)
lim
n
[2.3.6.b]
------------------------------------------------------------
2.3.7. Notaia (omega)
Prin analogie, notaia este pentru notaia ceea ce este o pentru O.
Cu alte cuvinte notaia precizeaz o margine asimptotic inferioar lejer.
------------------------------------------------------------
(g(n))
= {
f(n)
: pentru orice constant pozitiv c
>
0 exist o constant n
0
>
0
astfel nct
f(n) g(n) c < 0
pentru
0
n n } [2.3.7.a]
------------------------------------------------------------
Proprietate: Relaia f(n) = (g(n)) implic [2.3.7.b], adic f(n) devine n mod arbitrar
semnificativ n raport cu g(n) atunci cnd n tinde la infinit.
------------------------------------------------------------
f(n) =
(g(n))
implic
=
g(n)
f(n)
lim
n
[2.3.7.b]
------------------------------------------------------------
2.3.8. Proprieti ale notaiilor asimptotice
Presupunnd c
f(n)
i
g(n)
sunt asimptotic pozitive, multe din proprietile
relaionale ale numerelor reale se aplic similar comparaiilor asimptotice.
------------------------------------------------------------
a) Tranzitivitate:
f(n) =
(g(n))
i g(n) =
(h(n))
implic f(n) =
(h(n))
f(n) =
(g(n)) O
i g(n) =
(h(n)) O
implic f(n) =
(h(n)) O
f(n) =
(g(n))
i g(n) =
(h(n))
implic f(n) =
(h(n))
f(n) =
(g(n)) o
i g(n) =
(h(n)) o
implic f(n) =
(h(n)) o
f(n) =
(g(n))
i g(n) =
(h(n))
implic f(n) =
(h(n))
b) Reflexivitate:
f(n) =
(f(n))
;
f(n) =
(f(n)) O
; [2.3.8.a]
f(n) =
(f(n))
.
c) Simetrie:
f(n) =
(g(n))
dac i numai dac g(n) =
(f(n))
d) Simetrie transpus:
f(n) =
(g(n)) O
dac i numai dac g(n) =
(f(n))
f(n) = o(g(n)) dac i numai dac g(n)=
(f(n))
------------------------------------------------------------
Analogia dintre comparaia asimptotic a dou funcii f i g i compararea a
dou numere reale a i n este prezentat n [2.3.8.b].
------------------------------------------------------------
f(n)=
(g(n)) O
a b
f(n)=
(g(n))
a b
f(n)=
(g(n))
a = b [2.3.8.b]
f(n)=
(g(n)) o
a < b
f(n)=
(g(n))
a > b
------------------------------------------------------------
O proprietate specific numerelor reale, care nu se aplic comparaiei asimptotice
este trihotomia ("trichotomy").
o Conform acestei proprieti ntre dou numere reale oarecare exist exact
una din urmtoarele relaii:
a < b ; a = b ; a > b.
o Dac oricare dou numere reale pot fi comparate conform relaiei de mai sus,
pentru dou funcii f(n) i g(n) este ns posibil ca s nu fie valabil nici
f(n) = O(g(n)), nici f(n) = (g(n)).
2.4. Aprecierea timpului de execuie
Cu ajutorul notaiei O mare se poate aprecia timpul de execuie al unui algoritm.
Se face sublinierea c se poate aprecia timpul de execuie al unui algoritm abstract
i nu al unui program ntruct acesta din urm depinde de mai muli factori:
o Dimensiunea i natura datelor de intrare,
o Caracteristicile sistemului de calcul pe care se ruleaz programul,
o Eficiena codului produs de compilator.
Notaia O mare permite eliminarea factorilor care nu pot fi controlai (spre
exemplu viteza sistemului de calcul) concentrndu-se asupra comportrii
algoritmului independent de program.
n general un algoritm a crui complexitate temporal este O(n
2
) va rula ca i
program n O(n
2
) uniti de timp indiferent de limbajul sau sistemul de calcul
utilizat.
n aprecierea timpului de execuie se pornete de la ipoteza simplificatoare deja
enunat, c fiecare instrucie exceptnd eventual apelurile de proceduri sau
funcii utilizeaz n medie aceeai cantitate de timp.
Singurele instruciuni care nu pot fi ncadrate n aceast medie de timp sunt
instruciunea IF, secvenele repetitive (buclele) i apelurile de proceduri i funcii.
Presupunnd pentru moment c apelurile de proceduri i funcii se ignor, se adopt
prin convenie urmtoarele simplificri:
o (1) Se presupune c o instruciune IF va consuma ntotdeauna timpul
necesar execuiei ramurii celei mai lungi, dac nu exist raiuni contrare
justificate;
o (2) Se presupune c ntotdeauna instruciunile din interiorul unei bucle se
vor executa de numrul maxim de ori permis de condiia de control.
------------------------------------------------------------
Exemplul 2.4.a. Se consider urmtoarea procedur care caut ntr-un tablou a cu
n elemente, un element egal cu cheie i returneaz n variabila unde ultima
locaie n care este gsit cheia sau zero n caz contrar [2.4.a].
------------------------------------------------------------
PROCEDURE CautareLiniara(n,cheie: integer,
a: TablouNumeric; VAR unde: integer);
VAR indice: integer;
BEGIN
unde: = 0
FOR indice:= 1 TO n DO
IF a[indice]= cheie THEN [2.4.a]
unde:= indice
END; {CautareLiniara}
------------------------------------------------------------
Intrarea n procedur i iniializarea O(1)
variabilei unde
Bucla FOR (n reluri) O(1+n+1) = O(n)
Instruciunea IF i O(1) O(n*1) = O(n)
ramura sa
Revenirea din procedur O(1)
Fig.
2.4.a. Schema temporal a algoritmului [2.4.a]
n figura 2.4.a apare schema temporal a algoritmului mpreun cu estimarea O
mare corespunztoare.
n analiz au fost introduse i operaiile de intrare i revenire din procedur care
nu apar ca pri explicite ale rutinei.
Pe viitor acestea vor fi omise din analiza temporal deoarece ele contribuie cu un
timp constant la execuie i nu influeneaz estimarea O mare
Exemplul 2.4.b. Se consider urmtoarea poriune de cod [2.4.b].
--------------------------------------------------------
FUNCTION SumProd(n: integer): integer;
VAR rezultat,k,i: integer;
BEGIN
rezultat:= 0;
FOR k:= 1 TO n [2.4.b]
FOR i:= 1 TO k
rezultat:= rezultat+k*i;
SumProd:= rezultat
END;{SumProd}
--------------------------------------------------------
iniializare rezultat O(1)
bucla FOR (n reluri)
bucla FOR (n reluri)
O(n*1) = O(n) O(n*n)
=
O(n
2
) O(1+n
2
)
=
O(n
2
)
interior O(1)
Fig.
2.4.b. Schema temporal a algoritmului din secvena [2.4.b]
La analiza complexitii temporale se face presupunerea c ambele bucle se reiau
de numrul maxim de ori posibil, dei acest lucru nu este adevrat deoarece
bucla interioar se execut cu limita k n ( i nu cu limita n)
Se va demonstra c prin aceast simplificare estimarea temporal final nu este
afectat.
La o analiz mai aprofundat se ine cont de faptul c bucla FOR interioar se
execut prima oar o dat, a doua oar de 2 ori .a.m.d, a k-oar de k ori.
------------------------------------------------------------
1 + 2 + 3 + ... + n = [2.4.c]
------------------------------------------------------------
n mod analog n cadrul secvenei [2.4.d] se ajunge la estimarea: O(n
n) =
O(n
3
).
------------------------------------------------------------
FOR i:= 1 TO n DO
FOR j:= 1 TO i DO
FOR k:= 1 TO i DO [2.4.d]
Secven {O(1)};
------------------------------------------------------------
Calculul exact al numrului de reluri conduce la valoarea precizat de relaia
[2.4.e], innd cont de faptul c cele dou bucle interioare se execut de i
2
ori la
fiecare reluare a buclei exterioare FOR.
------------------------------------------------------------
1
2
+ 2
2
+ 3
2
+ ... + n
2
=
6
1) (2 1) ( + + n n n
= O(n
3
) [2.4.e]
------------------------------------------------------------
Exemplul 2.4.c. se refer tot la o bucl multiplicativ.
------------------------------------------------------------
m:= 1
FOR i:= 1 TO n DO
BEGIN
m:= m *2;
FOR j:= 1 TO m DO [2.4.f]
Secventa {O(1)}
END; {FOR}
------------------------------------------------------------
n situaia n care bucla exterioar se execut pentru valorile 1, 2, 3, ... ale lui i,
bucla interioar itereaz de 2, 4, 8, ... ori conducnd la un timp de execuie de
ordinul O(2
+
4
+
8
+
...
+
2
n
).
------------------------------------------------------------
2 + 4 + 8 + ... + 2
n
= ) (
) (
n
n
1
2 O
1 2
1 2 2
+
=
[2.4.g]
------------------------------------------------------------
Aceast estimare este complet diferit de estimarea O(n
2
) pentru care exist
tentaia de a fi avansat i care este valabil pentru buclele nemultiplicative.
2.5. Profilarea unui algoritm
Presupunnd c un algoritm a fost conceput, implementat, testat i depanat pe un
sistem de calcul int
Ne intereseaz de regul profilul performanei sale, adic timpii precii de
execuie ai algoritmului pentru diferite seturi de date, eventual pe diferite sisteme
int.
Pentru aceasta sistemul de calcul int trebuie s fie dotat cu un ceas intern i cu
funcii sistem de acces la acest ceas.
Dup cum s-a mai precizat, determinarea profilului performanei face parte din
testul ulterior al unui algoritm i are drept scop determinarea precis a ordinul
de mrime al timpului de execuie al algoritmului.
n n
O n
( )
( )
+
=
1
2
2
Informaiile rezultate sunt utilizate de regul pentru a valida sau invalida, respectiv
pentru a nuana rezultatele estimrii apriorice.
Se presupune un algoritm implementat n forma unui program numit
Algoritm(X:
Intrare,Y:
Iesire)unde X este intrarea iar Y ieirea.
Pentru a construi profilul algoritmului este necesar s fie concepute:
o Seturile de date de intrare a cror dimensiune crete ntre anumite limite,
pentru a studia comportamentul algoritmului n raport cu dimensiunea
intrrii
o Seturile de date care n principiu se refer la cazurile extreme de
comportament.
o O procedur cu ajutorul creia poate fi construit profilul algoritmului n
baza seturilor de date anterior amintite.
------------------------------------------------------------
procedure Profil;
{procedura construiete profilul procedurii Algoritm(X:
Intrare,Y: Ieire)}
begin
*initializeaz procedura Algoritm;
*afiseaza("Testul
lui
Algoritm.
Timpii
n
milisecunde");
repeat
*citeste(SetDeDate); [2.5.a]
*afiseaza("Un nou set de date:", SetDeDate);
*apel TIME(t); {atribuie lui t valoarea curent
a ceasului sistem}
*apel Algoritm(SetDeDate, Rezultate);
*apel TIME(t1);
*afiseaza("TimpExecuie=", t - t1);
until sfrit(SetDeDate)
end {Profil}
------------------------------------------------------------
Procedura Profil poate fi utilizat n mai multe scopuri funcie de obiectivele
urmrite.
o (1) Evidenierea performanei intrinseci a unui algoritm precizat.
Pentru aceasta se aleg, aa cum s-a mai precizat, seturi de date cu
dimensiuni din ce n ce mai mari.
Rezultatul va fi profilul algoritmului.
Pentru deplina conturare a profilului se testeaz de asemenea i
cazurile de comportament extrem ale algoritmului (cel mai
favorabil i cel mai defavorabil).
o (2) Evidenierea performanei relative a doi sau mai muli algoritmi
diferii care ndeplinesc aceeai sarcin.
n acest scop se execut procedura Profil pentru fiecare din
algoritmi n parte, cu aceleai seturi de date iniale, pe un acelai
sistem de calcul.
Compararea profilelor rezultate permite ierarhizarea
performanelor algoritmilor analizai.
o (3) Evidenierea performanei relative a dou sau mai multe sisteme de
calcul.
n acest scop se ruleaz procedura Profil pentru un acelai
algoritm, cu aceleai date iniiale pe sistemele de calcul int
supuse analizei.
Compararea profilelor rezultate permite ierarhizarea
performanelor sistemelor de calcul analizate.
De regul, pe piaa sistemelor de calcul se utilizeaz n acest scop
algoritmi consacrai, n anumite cazuri standardizai, cunoscui sub
denumirea de "bench marks" n baza crora sunt evideniate
performanele diferitelor arhitecturi de sisteme de calcul.
Trebuie ns acordat o atenie special procedurii TIME a cror rezultate n
anumite circumstane pot fi nerevelevante.
o Astfel, n cazul sistemelor time-sharing, al sistemelor complexe (care
lucreaz cu ntreruperi) sau al sistemelor multi-procesor, timpul furnizat
de aceast funcie poate fi complet needificator.
o n astfel de cazuri, una din soluii este aceea de a executa programul de un
numr suficient de ori i de a apela la metode statistice pentru
evidenierea performanelor algoritmului testat.
3. Sortri
3.1. Conceptul de sortare
Scopul fundamental al acestui capitol este:
De a furniza un set extins de exemple referitoare la utilizarea structurilor de
date introduse n capitolul 1;
De a sublinia influena profund pe care adoptarea unei anumite structuri o
are asupra algoritmului care o utilizeaz i asupra tehnicilor de programare
care implementeaz algoritmul respectiv.
Sortarea este domeniul ideal al studiului:
Construciei algoritmilor,
Al performanelor algoritmilor,
Al avantajelor i dezavantajelor unor algoritmi fa de alii n accepiunea
unei aplicaii concrete
Al tehnicilor de programare aferente difertiior algoritmi
Prin sortare se nelege n general ordonarea unei mulimi de elemente, cu scopul de
a facilita cutarea ulterioar a unui element dat.
Sortarea este o activitate fundamental cu caracter universal.
Spre exemplu n cartea de telefoane, n dicionare, n depozitele de mrfuri i
n general n orice situaie n care trebuiesc cutate i regsite obiecte, sortarea
este prezent.
n cadrul acestui capitol se presupune c sortarea se refer la anumite elemente care au
o structur articol definit dup cum urmeaz [3.1.a]:
------------------------------------------------------------
TYPE TipElement = RECORD
cheie: integer; [3.1.a]
{Alte cmpuri definite}
END;
------------------------------------------------------------
Cmpul cheie precizat, poate fi neesenial din punctul de vedere al informaiei
nregistrate n articol, partea esenial a informaiei fiind coninut n celelalte
cmpuri.
Din punctul de vedere al sortrii ns, cheie este cel mai important cmp ntruct
este valabil urmtoarea definiie a sortrii.
o Fiind dat un ir de elemente aparinnd tipul mai sus definit
a
1
, a
2
,....,a
n
o Prin sortare se nelege permutarea elementelor irului ntr-o anumit
ordine:
a
k1
, a
k2
,.....,a
kn
o Astfel nct irul cheilor s devin monoton cresctor, cu alte cuvinte s
avem
a
k1
.cheie a
k2
.cheie ... a
kn
.cheie
Tipul cmpului cheie se presupune a fi ntreg pentru o nelegere mai facil, n
realitate el poate fi ns orice tip scalar.
O metod de sortare se spune c este stabil dac dup sortare, ordinea relativ a
elementelor cu chei egale coincide cu cea iniial, element esenial n special n cazul
n care se execut sortarea dup mai multe chei.
n cazul sortrii, dependena dintre algoritmul care realizeaz sortarea i structura de
date prelucrat este profund.
Din acest motiv metodele de sortare sunt clasificate n dou mari categorii dup cum
elementele de sortat:
o Sunt nregistrate ca i tablouri n memoria central a sistemului de calcul
ceea ce conduce la sortarea tablourilor numit sortare intern
o Sunt nregistrate ntr-o memorie extern: ceea ce conduce la sortarea
fiierelor (secvenelor) numit i sortare extern.
3.2. Sortarea tablourilor
Cerina fundamental care se formuleaz fa de metodele de sortare a tablourilor
se refer la utilizarea ct mai economic a zonei de memorie disponibile.
Din acest motive pentru nceput, prezint interes numai algoritmii care, dat fiind
tabloul a, realizeaz sortarea "in situ", adic chiar n zona de memorie alocat
tabloului.
Pornind de la aceast restricie, n continuare algoritmii vor fi clasificai n funcie
de eficiena lor, respectiv n funcie de timpul de execuie pe care l necesit.
Aprecierea cantitativ a eficienei unui algoritm de sortare se realizeaz prin
intermediul unor indicatori specifici.
Un astfel de indicator este numrul comparaiilor de chei notat cu C, pe
care le execut algoritmul.
Un alt indicator este numrul de atribuiri de elemente, respectiv
numrul de micri de elemente executate de algoritm notat cu M.
Ambii indicatori depind de numrul total n al elementelor care trebuiesc
sortate.
n cazul unor algoritmi de sortare simpli bazai pe aa-zisele metode directe de
sortare att C ct i M sunt proporionali cu n
2
adic sunt O(n
2
).
Exist ns i metode avansate de sortare, care au o complexitate mult mai mare
i n cazul crora indicatorii C i M sunt de ordinul lui n
log
2
n (
O(n
log
2
n)
).
Raportul n
2
/(n
log
2
n), care ilustreaz ctigul de eficien realizat de aceti
algoritmi, este aproximativ egal cu 10 pentru n = 64, respectiv 100 pentru n =
1000.
Cu toate c ameliorarea este substanial, metodele de sortare directe prezint
interes din urmtoarele motive:
Sunt foarte potrivite pentru explicitarea principiilor majore ale sortrii.
Procedurile care le implementeaz sunt scurte i relativ uor de neles.
Dei metodele avansate necesit mai puine operaii, aceste operaii sunt
mult mai complexe n detaliile lor, respectiv metodele directe se dovedesc
a fi superioare celor avansate pentru valori mici ale lui n.
Reprezint punctul de pornire pentru metodele de sortare avansate.
Metodele de sortare care realizeaz sortarea "in situ" se pot clasifica n trei mai
categorii:
Sortarea prin inserie;
Sortarea prin selecie;
Sprin interschimbare.
n prezentarea acestor metode se va lucra cu tipul element definit anterior, precum
i cu urmtoarele notaii [3.2.a].
------------------------------------------------------------
TYPE TipIndice = 0..n;
TipTablou = ARRAY [TipIndice] OF TipElement;
VAR a: TipTablou; temp: TipElement; [3.2.a]
------------------------------------------------------------
3.2.1. Sortarea prin inserie
Aceast metod este larg utilizat de juctorii de cri.
Elementele (crile) sunt n mod conceptual divizate ntr-o secven destinaie
a
1
...a
i-1
i ntr-o secven surs a
i
....a
n
.
n fiecare pas ncepnd cu i
=
2 , elementul i al tabloului (care este de fapt
primul element al secvenei surs), este luat i transferat n secvena destinaie
prin inserarea sa la locul potrivit.
Se incrementeaz i i se reia ciclul.
Astfel la nceput se sorteaz primele dou elemente, apoi primele trei elemente i aa
mai departe.
Se face precizarea c n pasul i, primele i-l elemente sunt deja sortate, astfel nct
sortarea const numai n a insera elementul a[i] la locul potrivit ntr-o secven
deja sortat.
n termeni formali, acest algoritm este precizat n secvena [3.2.1.a].
-----------------------------------------------------------
{Tehnica sortrii prin inserie}
FOR i := 2 TO n DO
BEGIN [3.2.1.a]
temp:=a[i];
*insereaz x la locul potrivit n a[1]...a[i]}
END;{FOR}
------------------------------------------------------------
Selectarea locului n care trebuie inserat a[i] se face parcurgnd secvena
destinaie deja sortat a[1],...,a[i-1] de la dreapta la stnga,
Oprirea se realizeaz pe primul element a[j] care are cheia mai mic sau
egal cu a[i],
Dac un astfel de element a[j] nu exist, oprirea se realizeaz pe a[1]
adic pe prima poziie.
Simultan cu parcurgerea, se realizeaz i deplasarea spre dreapta cu o poziie a
fiecrui element testat pn n momentul ndeplinirii condiiei de oprire.
Acest caz tipic de repetiie cu dou condiii de terminare readuce n atenie metoda
fanionului (&1.4.2.1).
Pentru aplicarea ei se introduce elementul auxiliar a[0] care se asigneaz
iniial cu a[i].
n felul acesta, cel mai trziu pentru j
=
0, condiia de a avea cheia lui a[j]
"mai mic sau egal" cu cheia lui a[i] se gsete ndeplinit.
Inseria propriu-zis se realizeaz pe poziia j+1.
Algoritmul care implementeaz sortarea prin inserie apare n [3.2.1.b] iar profilul su
temporal n figura 3.2.1.a.
------------------------------------------------------------
{Sortare prin insertie - Varianta Pascal}
PROCEDURE SortarePrinInsertie;
VAR i,j: TipIndice; temp: TipElement;
BEGIN
FOR i:= 2 TO n DO
BEGIN
temp:= a[i]; a[0]:= temp; j:= i-1;
WHILE a[j].cheie>temp.cheie DO
BEGIN
a[j+1]:= a[j]; j:= j-1 [3.2.1.b]
END; {WHILE}
a[j+1]:= temp
END
END; {SortarePrinInsertie}
------------------------------------------------------------
SortarePrinInserie
FOR (n
-1 iteraii)
2 atribuiri O(1)
WHILE (n
-1 iteraii) O((n-1)
n)
= O(n
2
) O(n
2
)
1 comparaie
1 atribuire O(n-1)
=
O(n)
1 atribuire O(1)
Fig.3.2.1.a. Profilul temporal al algoritmului de sortare prin inserie
Dup cum se observ, algoritmul de sortare conine un ciclu exterior dup i care se
reia de n-1 ori (bucla FOR).
n cadrul fiecrui ciclu exterior se execut un ciclu interior de lungime
variabil dup j, pn la ndeplinirea condiiei (bucla WHILE).
n pasul i al ciclului exterior FOR
, numrul minim de reluri ale ciclului
interior este 0 iar numrul maxim de reluri este i-1
.
Analiza sortrii prin inserie
n cadrul celui de-al i-lea ciclu FOR, numrul C
i
al comparaiilor de chei
executate n bucla WHILE, depinde de ordinea iniial a cheilor, fiind:
Cel puin 1 (secvena ordonat),
Cel mult i-l (secvena ordonat invers)
n medie i/2, presupunnd c toate permutrile celor n chei sunt
egal posibile
ntruct avem n-1 reluri ale lui FOR pentru i:= 2..n
, parametrul C are
valorile precizate n [3.2.1.c].
------------------------------------------------------------
1 1 C
2
min
= =
=
n
n
i
=
=
= = =
n
i
n
i
n n
i i
2
1
1
max
2
) 1 (
) 1 ( C [3.2.1.c]
4
2
2
C C
C
2
max min
med
+
=
+
=
n n
------------------------------------------------------------
Numrul maxim de atribuiri de elemente n cadrul unui ciclu FOR este C
i
+
3
i corespunde numrului maxim de comparaii
Explicaia: la numrul C
i
de atribuiri executate n cadrul ciclului
interior WHILE de tip a[j+1]:=
a[j]) se mai adaug 3 atribuiri
(temp:=
a[i],
a[0]:=
temp i a[i+1]:=
temp).
Chiar pentru numrul minim de comparaii de chei (C
i
egal cu 1) cele trei
atribuiri rmn valabile.
n consecin, parametrul M ia urmtoarele valori [3.2.1.d].
------------------------------------------------------------
) 1 ( 3 M
min
= n
2
6 5
6
2
) 3 ( ) 2 (
) 3 2 1 ( ) 2 ( ) 3 (C M
2
2
1 2 2
i max
+
=
+ +
=
= + + = + = + =
+
= = =
n n n n
i i
n
i
n
i
n
i
[3.2.1.d]
4
12 11
2
M M
M
2
max min
med
+
=
+
=
n n
------------------------------------------------------------
Se observ c att C ct i M sunt de ordinul lui n
2
(O(n
2
)).
Valorile minime ale indicatorilor rezult cnd a este ordonat, iar valorile maxime,
cnd a este ordonat invers.
Sortarea prin inserie este o sortare stabil.
n secvena [3.2.1.e] se prezint o variant C a acestei metode de sortare cu fanionul
poziionat pe poziia n.
------------------------------------------------------------
// Sortarea prin inserie - varianta C
insertie(int a[],int n) { //fanionul pe poziia a[n]
for(int i=n-2;i>=0;i--) {
a[n]=a[i];
int j=i+1;
while(a[j]<a[n]) {
a[j-1]=a[j]; j++; [3.2.1.e]
}
a[j-1]=a[n];
}
}
------------------------------------------------------------
Algoritmul de sortare prin inserie poate fi mbuntit pornind de la observaia c
secvena destinaie este deja sortat.
n acest caz cutarea locului de inserie se poate face mult mai rapid utiliznd tehnica
cutrii binare, prin mpriri succesive n pri egale a intervalului de cutare.
Algoritmul modificat se numete inserie binar [3.2.1.f].
------------------------------------------------------------
{Sortare prin inserie binar - Varianta Pascal}
PROCEDURE SortarePrinInserieBinar;
VAR i,j,stanga,dreapta,m: TipIndice; temp: TipElement;
a: TipTablou;
BEGIN
FOR i:= 2 TO n DO
BEGIN
temp:= a[i]; stanga:= 1; dreapta:= i-1;
WHILE stanga<=dreapta DO
BEGIN [3.2.1.f]
m:= (stanga+dreapta)DIV 2;
IF a[m].cheie>temp.cheie THEN
dreapta:= m-1
ELSE
stanga:= m+1
END;{WHILE}
FOR j:= i-1 DOWNTO stanga DO a[j+1]:= a[j];
a[stanga]:= temp
END {FOR}
END; {SortarePrinInserieBinar}
------------------------------------------------------------
Analiza inseriei binare
Poziia de inserat este gsit dac
a[j].cheie x.cheie a[j+1].cheie
,
adic intervalul de cutare ajunge de dimensiune 1.
Dac intervalul iniial este de lungime i sunt necesari log
2
(i)
pai pentru
determinarea locului inseriei.
ntruct procesul de sortare presupune parcurgerea prin metoda njumtirii
binare a unor secvene de lungime i (care conin i chei), pentru
i=1,2,...,n
, numrul total de comparaii C efectuate n bucla WHILE
este cel evideniat de expresia prezentat n [3.2.1.g].
------------------------------------------------------------
=
=
n
i
i log
1
2
C [3.2.1.g]
------------------------------------------------------------
Aceast sum se poate aproxima prin integrala:
------------------------------------------------------------
44269 . 1 2 / 1
) ( ) ( C
2
1
2
1
2 2
= = =
+ = = =
ln e log c
c c n log n c x log x dx x log
n
n
[3.2.1.h]
------------------------------------------------------------
Numrul comparaiilor de chei este n principiu independent de ordinea iniial a
cheilor.
De fapt numrul minim de comparaii, este necesar pentru un ir ordonat
invers, iar numrul maxim pentru un ir ordonat.
Acesta este un caz de comportament anormal al unui algoritm de sortare.
Din nefericire beneficiile cutrii binare se rsfrng numai asupra numrului de
comparaii i nu asupra numrului de micri.
De regul, mutarea cheilor i a informaiilor asociate necesit mai mult timp dect
compararea a dou chei,
Astfel ntruct M rmne de ordinul lui n
2
, performanele acestei metode de
sortare nu cresc n msura n care ar fi de ateptat.
De fapt, resortarea unui tablou gata sortat, utiliznd inseria binar, consum
mai mult timp dect inseria cu cutare secvenial.
n ultim instan, sortarea prin inserie nu este o metod potrivit de sortare cu
ajutorul calculatorului, deoarece inseria unui element presupune deplasarea cu o
poziie n tablou a unui ir de elemente, deplasare care este neeconomic.
Acest dezavantaj conduce la ideea dezvoltrii unor algoritmi n care micrile s
afecteze un numr mai redus de elemente i s se realizeze pe distane mai mari.
Sortarea prin selecie rezolv aceste probleme.
3.2.2. Sortarea prin selecie
Sortarea prin selecie folosete procedeul de a selecta elementul cu cheia minim i
de a schimba ntre ele poziia acestui element cu cea a primului element.
Se repet acest procedeu cu cele n
-1 elemente rmase, apoi cu cele n
-2, etc.,
terminnd cu ultimele dou elemente.
Aceast metod este oarecum opus sortrii prin inserie care presupune la fiecare pas
un singur element al secvenei surs i toate elementele secvenei destinaie n care se
caut de fapt locul de inserie.
Selecia n schimb presupune toate elementele secvenei surs dintre care selecteaz
pe cel cu cheia cea mai mic i l depoziteaz ca element urmtor al secvenei
destinaie.
------------------------------------------------------------
{Tehnica sortarii prin selectie}
FOR i:= 1 TO n-1 DO [3.2.2.a]
BEGIN
*gseste cel mai mic element al lui a[i]...a[n] i
asigneaz pe min cu indicele lui;
*interschimb pe a[i] cu a[min]
END;
------------------------------------------------------------
n urma procesului de detaliere rezult algoritmul prezentat n [3.2.2.b] al crui profil
temporal apare n figura 3.2.2.a.
------------------------------------------------------------
{Sortare prin selacie - Varianta Pascal}
PROCEDURE SortarePrinSelectie;
VAR i,j,min: TipIndice; temp: TipElement;
a: TipTablou;
BEGIN
FOR i:= 1 TO n-1 DO
BEGIN
min:= i; temp:= a[i];
FOR j:= i+1 TO n DO
IF a[j].cheie<temp.cheie THEN [3.2.2.b]
BEGIN
min:= j; temp:= a[j]
END;{FOR}
a[min]:= a[i]; a[i]:= temp
END {FOR}
END; {SortarePrinSelectie}
------------------------------------------------------------
SortarePrinSelectie
FOR (n
-1 iteraii)
1 atribuire
FOR (i
-1 iteraii)
H
m
-1 atribuiri
1 comparaie
1 atribuire
2 atribuiri
Fig.3.2.2.a. Profilul temporal al sortrii prin selecie
Analiza sortrii prin selecie
Numrul comparaiilor de chei C este independent de ordinea iniial a
cheilor.
------------------------------------------------------------
2
2 3
) 1 ( C
2 2
1
1
1
+
= = =
=
=
n n
i i
n
i
n
i
[3.2.2.c]
------------------------------------------------------------
Numrul atribuirilor este de cel puin 3 pentru fiecare valoare a lui i,
(temp:=
a[i],a[min]:=
a[i],a[i]:=
temp), de unde rezult:
------------------------------------------------------------
) 1 ( 3 M
min
= n [3.2.2.d]
------------------------------------------------------------
Acest minim poate fi atins efectiv, dac iniial cheile sunt deja sortate.
Pe de alt parte dac cheile sunt iniial n ordine invers M
max
se determin cu ajutorul
formulei empirice [3.2.2.e] [Wi76].
=
4
M
2
max
n
(1)
) 1 ( 3 + n
[3.2.2.e]
Valoarea medie a lui M nu este media aritmetic a lui M
min
i M
max
, ea obinndu-se
printr-un raionament probabilistic n felul urmtor.
Se consider o secven de m chei.
Fie o permutare oarecare a celor m chei notat cu k
1
, k
2
, ..., k
m
.
Se determin numrul termenilor k
j
avnd proprietatea de a fi mai mici dect
toi termenii precedeni k
1
, k
2
, ...,.k
j-1
.
Se adun toate valorile obinute pentru cele m! permutri posibile i se mparte
suma la m!
Se demonstreaz c rezultatul acestui calcul este H
m
-1, unde H
m
este suma
parial a seriei armonice [3.2.2.f][Wi76]:
------------------------------------------------------------
m
1
3
1
2
1
1 H
m
+ + + + = [3.2.2.f]
------------------------------------------------------------
Aceast valoare reprezint media numrului de atribuiri ale lui temp, executate
pentru o secven de m elemente, deoarece temp se atribuie ori de cte ori se gsete
un element mai mic dect toate elementele care-l preced.
innd cont i de atribuirile temp:=a[i],a[min]:=a[i] i a[i]:=temp,
valoarea medie a numrului total de atribuiri pentru m termeni este H
m
+2.
Se demonstreaz c dei seria este divergent, o sum parial a sa se poate calcula
cu ajutorul formulei [3.2.2.g]:
------------------------------------------------------------
4 2
m
120
1
12
1
2
1
ln H
m m
m
m
+ + [3.2.2.g]
------------------------------------------------------------
unde = 0.5772156649... este constanta lui Euler [Kn76].
Pentru un m suficient de mare valoarea lui H
m
se poate aproxima prin expresia:
------------------------------------------------------------
+ m ln H
m
[3.2.2.h]
------------------------------------------------------------
ntruct n procesul de sortare se parcurg succesiv secvene care au respectiv
lungimea m = n
, n-1
, n-2
,..., 1, fiecare dintre ele necesitnd n medie H
m
+2 atribuiri,
numrul mediu total de atribuiri M
med
va avea expresia:
------------------------------------------------------------
= = =
+ + = + + +
n
m
n
m
n
m
m n m
1 1 1
m med
ln ) 2 ( ) 2 (ln ) 2 (H M [3.2.2.i]
------------------------------------------------------------
Suma de termeni discrei, poate fi aproximat cu ajutorul calculului integral [3.2.2.j]
------------------------------------------------------------
1 ) ( ln ) 1 ln ( ln
1
1
+ = =
n n n x x dx x
n
n
[3.2.2.j]
------------------------------------------------------------
aproximare care conduce la rezultatul:
) ln ( O 1 ) 1 (ln
med
n n m n M = + + +
n concluzie, algoritmul bazat pe selecie este de preferat celui bazat pe inserie, cu
toate c n cazurile n care cheile sunt ordonate, sau aproape ordonate, sortarea prin
inserie este mai rapid.
Optimizarea performanei sortrii prin selecie poate fi realizat prin reducerea
numrului de micri de elemente ale tabloului.
n [Se88] se propune o astfel de variant n care n loc de a memora de fiecare dat
elementul minim curent n variabila temp, se reine doar indicele acestuia, mutarea
urmnd a se realiza doar pentru ultimul element gsit, la prsirea ciclului FOR
interior [3.2.2.k].
------------------------------------------------------------
{Sortare prin selecie optimizat - Varianta Pascal}
PROCEDURE SelectieOptimizat;
VAR i,j,min: TipIndice; temp: TipElement;
a: TipTablou;
BEGIN
FOR i:= 1 TO n-1 DO [3.2.2.k]
BEGIN
min:= i;
FOR j:= i+1 TO n DO
IF a[j].cheie<temp.cheie THEN min:= j;
temp:= a[min]; a[min]:= a[i]; a[i]:= temp
END {FOR}
END; {SelectieOptimizat}
------------------------------------------------------------
Msurtorile experimentale efectuate ns asupra acestei variante nu evideniaz vreo
ameliorare nici chiar pentru valori mari ale dimensiunii tabloului de sortat.
Explicaia rezid n faptul ca atribuirile care necesit n plus accesul la componenta
unui tablou se realizeaz practic n acelai timp ca i o atribuire normal.
3.2.3. Sortarea prin interschimbare
Clasificarea metodelor de sortare n diferite familii ca inserie, interschimbare sau
selecie nu este ntotdeauna foarte bine definit.
Paragrafele anterioare au analizat algoritmi care dei implementeaz inseria sau
selecia, se bazeaz pe fapt pe interschimbare.
n acest paragraf se prezint o metod de sortare n care interschimbarea a dou
elemente este caracteristica dominant.
Principiul de baz al acestei metode este urmtorul: se compar i se interschimb
perechile de elemente alturate, pn cnd toate elementele sunt sortate.
Ca i la celelalte metode, se realizeaz treceri repetate prin tablou, de la capt spre
nceput, de fiecare dat deplasnd cel mai mic element al mulimii rmase spre
captul din stnga al tabloului.
Dac se consider tabloul n poziie vertical i se asimileaz elementele sale cu nite
bule de aer n interiorul unui lichid, fiecare bul avnd o greutate proporional cu
valoarea cheii, atunci fiecare trecere prin tablou se soldeaz cu ascensiunea unei bule la
nivelul specific de greutate.
Din acest motiv aceast metod de sortare este cunoscut n literatur sub denumirea
de bubblesort (sortare prin metoda bulelor).
Algoritmul aferent acestei metode apare n continuare [3.2.3.a]:
------------------------------------------------------------
{Sortarea prin interschimbare Bubblesort - Varianta 1}
PROCEDURE Bubblesort;
VAR i,j: TipIndice; temp: TipElement;
BEGIN
FOR i:= 2 TO n DO
BEGIN [3.2.3.a]
FOR j:= n DOWNTO i DO
IF a[j-1].cheie>a[j].cheie THEN
BEGIN
temp:= a[j-1]; a[j-1]:= a[j]; a[j]:= temp
END {IF}
END {FOR}
END; {Bubblesort}
------------------------------------------------------------
Profilul temporal al algoritmului de sortare prin interschimbare este prezentat n figura
3.2.a i el conduce la o estimare a ncadrrii performanei algoritmului n ordinul O(n
2
).
Bubblesort
FOR (n
- 1 iteraii)
FOR (i
- 1 iteraii)
O(n
2
)
1 comparaie O(n) O(nn)
= O(n
2
)
3 atribuiri
Fig.3.2.a. Profilul temporal al sortrii prin interschimbare
n multe cazuri ordonarea se termin nainte de a se parcurge toate iteraiile buclei
FOR exterioare.
n acest caz, restul iteraiilor sunt fr efect, deoarece elementele sunt deja
ordonate.
O modalitate evident de mbuntire a algoritmului bazat pe aceast observaie este
aceea prin care se memoreaz dac a avut sau nu loc vreo interschimbare n cursul
unei treceri.
i n acest caz este ns necesar o ultim trecere, fr nici o interschimbare
care marcheaz finalizarea algoritmului.
-----------------------------------------------------------
{Sortarea prin interschimbare - Varianta 2}
PROCEDURE Bubblesort1;
VAR i: TipIndice; modificat: boolean;
temp: TipElement;
BEGIN
REPEAT
modificat:= false;
FOR i:= 1 TO n-1 DO
IF a[i].cheie>a[i+1].cheie THEN [3.2.3.b]
BEGIN
temp:= a[i]; a[i]:= a[i+1]; a[i+1]:= temp;
modificat:= true
END
UNTIL NOT modificat
END; {Bubblesort1}
------------------------------------------------------------
Aceast mbuntire, poate fi la rndul ei perfecionat, memornd nu faptul c a
avut loc sau nu o interschimbare ci indicele k al ultimei schimbri.
Este evident faptul c toate perechile de elemente situate sub acest indice (care au
indici mai mici) sunt ordonate, n consecin trecerile urmtoare pot fi terminate la
acest indice n loc s fie terminate la indicele predeterminat ca limit i.
La o analiz atent se poate observa o asimetrie particular:
Un element uor plasat la captul greu al tabloului este readus la locul
su ntr-o singur trecere,
n schimb un element greu plasat la captul uor al tabloului va fi
readus spre locul su doar cu cte o poziie la fiecare trecere.
Spre exemplu tabloul:
12 18 22 34 65 67 83 04
va fi sortat cu ajutorul metodei bubblesort mbuntite ntr-o singur trecere,
n schimb ce tabloul
83 04 12 18 22 34 65 67
va necesita apte treceri n vederea sortrii.
Aceast neobinuit asimetrie, sugereaz o a treia mbuntire: alternarea
sensurilor de parcurgere ale trecerilor consecutive.
Algoritmul care conine aceste mbuntiri se numete shakersort (sortare prin
amestecare) i este prezentat n [3.2.3.c].
------------------------------------------------------------
{Sortarea prin interschimbare - Varianta 3}
PROCEDURE Shakersort;
VAR j,ultim,stanga,dreapta: TipIndice;
temp: TipElement;
BEGIN
stanga:= 2; dreapta:= n; ultim:= n;
REPEAT
FOR j:= dreapta DOWNTO stanga DO [3.2.3.c]
IF a[j-1].cheie>a[j].cheie THEN
BEGIN
temp:= a[j-1]; a[j-1]:= a[j]; a[j]:= temp;
ultim:= j
END;{FOR}
stanga:= ultim+1;
FOR j:=stanga TO dreapta DO
IF a[j-1].cheie>a[j].cheie THEN
BEGIN
temp:=a[j-1]; a[j-1]:=a[j]; a[j]:=temp;
ultim:=j
END;{FOR}
dreapta:=ultim-1
UNTIL (stanga>dreapta)
END; {Shakersort}
------------------------------------------------------------
Analiza sortrilor bubblesort i shakersort.
Numrul comparaiilor la algoritmul bubblesort este constant i are valoarea:
------------------------------------------------------------
2
2 3
) 1 ( C
2 1
1
+
= =
=
n n
i
n
i
[3.2.3.d]
------------------------------------------------------------
Valorile minim, maxim i medie ale numrului de micri sunt:
------------------------------------------------------------
0 M
min
=
) 2 3 (
2
3
C 3 M
2
max
+ + = = n n [3.2.3.e]
) 2 3 (
4
3
M
2
max
+ + = n n
--------------------------------------------------------
Analiza metodei mbuntite (shakersort) arat c C
min
= n
-
1 .
Pentru ceilali indicatori, Knuth ajunge la un numr mediu de treceri
proporional cu n - k
1 n
i la un numr mediu de comparaii de chei
proporional cu 1/2
(n
2
-
n
(
k
2
+ ln n)).
Trebuie ns remarcat faptul c toate mbuntirile propuse nu afecteaz n nici
un fel numrul de interschimbri; ele reduc numai numrul de verificri
redundante.
Din pcate ns interschimbarea a dou chei este mult mai costisitoare ca timp
dect compararea lor, prin urmare toate aceste mbuntirile atent studiate au un
efect mult mai redus dect s-ar atepta n mod intuitiv.
Analiza comparativ a performanelor algoritmilor de sortare prezentai, scoate n
eviden faptul c sortarea prin interschimbare este mai puin performant
dect sortrile prin inserie sau selecie, astfel nct utilizarea ei nu este
recomandabil.
Algoritmul shakersort poate fi utilizat n mod avantajos n cazurile n care
elementele sunt aproape sortate, caz ns destul de rar ntlnit n practic.
Se poate demonstra c distana medie pe care fiecare element al unui tablou de
dimensiune n, o parcurge n procesul sortrii este de n
/3 locuri.
Astfel, deoarece n metodele prezentate pn acum, fiecare element i modific
doar cu un singur loc poziia la fiecare pas elementar, este necesar un numr de
treceri proporional cu n
2
.
O mbuntire efectiv a performanei trebuie s aib n vedere deplasarea
elementelor pe distane mai mari ntr-un singur pas.
3.2.4. Sortarea prin inserie cu diminuarea incrementului
D.L. Shell a propus n 1959, o perfecionare a metodei de sortare prin inserie
direct.
o La nceput, toate articolele care sunt desprite prin cte 4 poziii, sunt
grupate i sortate separat prin metoda inseriei.
Acest proces se numete sortare-4.
n exemplul din fig.324, unde se sorteaz 8 elemente, s-au format
4 grupe de elemente separate prin cte 4 poziii.
o Dup aceast prim trecere, se formeaz grupuri n care elementele sunt
separate prin cte dou poziii i din nou sunt sortate prin inserie.
Acest proces se numete sortare-2.
o n final, la cea de-a treia trecere, elementele sunt sortate obinuit (sortare-
1).
Se precizeaz faptul c fiecare k-sortare este de fapt o sortare prin
inserie la care pasul este k (nu 1 ca la inseria normal).
34 65 12 22 83 18 04 67
sortare-4
34 18 04 22 83 65 12 67
sortare-2
04 18 12 22 34 65 83 67
sortare-1
04 12 18 22 34 65 67 83
Fig.
3.2.4. Sortare prin inserie cu diminuarea incrementului
Dei la prima vedere aceast metod care presupune cteva treceri asupra tuturor
elementelor, nu pare foarte performant, totui la o analiz mai atent, fiecare
trecere realizeaz relativ puine modificri ale poziiilor elementelor.
Este evident c metoda conduce la sortarea elementelor i c fiecare pas profit de
cei anteriori (fiecare sortare-i combin grupuri deja sortate-j).
Este posibil orice secven de incremeni atta timp ct ultimul este egal cu
unitatea: n cel mai ru caz n acest pas se va realiza n ntregime procesul de
sortare.
Este mai puin evident, dar practica demonstreaz c o secven de incremeni
descresctori care nu sunt puteri ale lui 2 asigur o eficien superioar procesului
de sortare.
Programul prezentat n [3.2.4.b], este dezvoltat pentru o secven oarecare de
incremeni descresctori format din t elemente care ndeplinesc condiiile
[3.2.4.a.].
------------------------------------------------------------
h
1
, h
2
, ... , h
t
,
unde
h
t
= 1, h
i
> h
i+1
i 1 i < t [3.2.4.a]
------------------------------------------------------------
Incremenii sunt pstrai n tabloul h.
Fiecare sortare-h este programat ca o sortare prin inserie utiliznd tehnica
fanionului n vederea simplificrii condiiei de terminare a procesului de cutare.
Deoarece fiecare sortare necesit propriul su fanion, pentru a face procesul de
cutare ct mai simplu, tabloul a se extinde spre stnga nu cu o singur
component a[0] ci cu h[1] componente, adic un numr egal cu valoarea
celui mai mare increment.
------------------------------------------------------------
{Sortarea cu diminuarea incrementului - Shellsort}
PROCEDURE Shellsort;
CONST t=4;
VAR i,j,pas,s: TipIndice; temp: TipElement;
m: 1..t;
h: ARRAY[1..t] OF integer;
BEGIN
{atribuire incrementi}
h[1]:= 9; h[2]:= 5; h[3]:= 3; h[4]:= 1;
FOR m:= 1 TO t DO
BEGIN {s este indicele fanionului curent}
pas:= h[m]; s:= -pas;
FOR i:= pas+1 TO n DO
BEGIN
temp:= a[i]; j:= i-pas;
IF s=0 THEN s:= -pas;
s:= s+1; a[s]:= temp; [3.2.4.b]
WHILE temp.cheie<a[j].cheie DO
BEGIN
a[j+k]:= a[j]; j:= j-pas {deplasare}
END;{WHILE}
a[j+k]:= temp {inserie element}
END{FOR}
END{FOR}
END; {Shellsort}
------------------------------------------------------------
Analiza metodei shellsort. Analiza acestui algoritm pune probleme deosebite din
punct de vedere matematic, multe din ele nc nerezolvate.
n particular, nu se cunoate nici mcar secvena de incremeni cea mai potrivit.
Ceea ce este deosebit de interesant este faptul c incremenii nu trebuie s fie unii
multiplii altora.
Pentru o eficien sporit a sortrii este de dorit ca ntre diferitele lanuri de
parcurgere s aib loc ct mai multe interaciuni.
De asemenea este valabil urmtoarea teorem pe care de fapt se bazeaz
metoda.
o Dac o secven sortat-k este sortat-i ea rmne i sortat-k.
o Cu alte cuvinte, procesul de sortare cu diminuarea incrementului este
cumulativ.
Knuth indic drept cele mai potrivite secvene de incremeni cele prezentate n
[3.2.4.c] respectiv [3.2.4.d] (furnizate n ordine cresctoare):
------------------------------------------------------------
1, 4, 13, 40, 121, ...
h
t
, h
t-1
, ..., h
k
, h
k-1
, ..., h
1
[3.2.4.c]
unde h
k-1
= 3
h
k
+1
, h
t
= 1 i t =
log
3
n - 1
------------------------------------------------------------
l, 3, 7, 15, 3l, ... [3.2.4.d]
unde h
k-1
= 2
h
k
+1
, h
t
= 1 i t =
n
2
log - 1
------------------------------------------------------------
Pentru ultima secven, analiza matematic a sortrii a n elemente cu metoda
Shellsort demonstreaz necesitatea unui efort proporional cu n
1.2
.
n [3.2.4.e] se prezint o alt variant de implementare acestei metode.
Algoritmul utilizeaz incremeni bazai pe formula [3.2.4.c], unde t se calculeaz
funcie de dimensiunea tabloului n prima bucl REPEAT [Se88].
------------------------------------------------------------
{Metoda Shellsort (Varianta Sedgewick)}
PROCEDURE Shellsort1;
VAR i,j,h: TipIndice; temp: TipElement;
BEGIN
h:= 1;
REPEAT h:= 3*h+1 UNTIL h>n;
REPEAT
h:= h DIV 3;
FOR i:= h+1 TO n DO [3.2.4.e]
BEGIN
temp:= a[i]; j:= i;
WHILE (a[j-h].cheie>temp.cheie) AND (j>h) DO
BEGIN
a[j]:= a[j-h]; j:= j-h
END; {WHILE}
a[j]:= temp
END;{FOR}
UNTIL h=1
END;{Shellsort1}
------------------------------------------------------------
3.2.5. Sortarea prin metoda ansamblelor
Metoda sortrii prin selecie se bazeaz pe selecia repetat a celei mai mici chei
dintre n elemente, apoi dintre cele n
-1 rmase, etc.
Este evident c determinarea celei mai mici chei dintre n elemente necesit n
-1
comparaii, dintre n
-1 elemente necesit n
-2 comparaii etc.
Activitatea de selecie poate fi mbuntit, dac la fiecare trecere se vor reine
mai multe informaii i nu doar elementul cu cheia cea mai mic.
o Astfel spre exemplu din n/2 comparaii se poate determina cea mai mic
cheie a fiecrei perechi de elemente,
o Din alte n/4 comparaii, cea mai mic cheie a fiecrei perechi de chei
mici deja determinate i aa mai departe.
o n final, utiliznd doar n/2 + n/4 +
...
+ 4 + 2 + 1 = n
-1 comparaii, se
poate construi un arbore de selecii avnd drept rdcin cheia cea mai
mic (fig.3.2.5.a).
o Arborele de selecii este de fapt un arbore binar parial ordonat.
04
12 04
34 12 18 04
34 65 12 22 83 18 04 67
Fig.3.2.5.a. Arbore de selecii
Cum se poate utiliza acest arbore la sortare?
o Se extrage cheia cea mai mic din rdcina arborelui.
o n continuare se parcurge n sens invers drumul urmat de cheia cea mai
mic i se elimin succesiv aceast cheie nlocuind-o fie cu un loc liber, la
baza structurii arbore, fie cu elementul ramurii alternative n cazul unui
nod intermediar
12
34 12 18
34 65 12 22 83 18 67
Fig.
3.2.5.b. Selecia celei mai mici chei
Din nou, elementul care va rzbate spre rdcina arborelui va fi cel cu cheia cea
mai mic (al doilea dup cel anterior), element care poate fi extras.
12
12 18
34 12 18 67
34 65 12 22 83 18 67
Fig.
3.2.5.c. Completarea locurilor libere
Dup n astfel de pai de selecie, s-au extras succesiv cele n elemente ale mulimii
n ordine cresctoare, arborele devine vid i procesul de sortare este ncheiat.
Trebuie notat faptul c fiecare din cei n pai de selecie necesit numai log
2
n
comparaii.
n consecin, procesul de sortare integral necesit:
o n pai pentru construcia arborelui,
o Un numr de operaii elementare de ordinul lui n log
2
n
pentru sortarea
propriu-zis.
Aceasta este o mbuntire considerabil fa de metodele directe care necesit
un efort de ordinul O(n
2
) i chiar fa de Shellsort care necesit O(n
1.2
).
Este evident faptul c n cazul metodei de sortare bazat pe structura arbore,
complexitatea pailor de sortare individuali crete.
De asemenea, n vederea reinerii unei cantiti sporite de informaie, trebuie
conceput o structur de date aparte care s permit organizarea eficient a
informaiei.
o Astfel, n primul rnd trebuiesc eliminate locurile goale, care pe de o parte
sporesc dimensiunea arborelui, iar pe de alt parte sunt sursa unor
comparaii care nu sunt necesare.
o n al doilea rnd, arborele ar trebui reprezentat utiliznd locaii de
memorie pentru n elemente i nu pentru 2n
-1 elemente aa cum rezult
din figurile 3.2.5.a, b, c.
Aceste probleme au fost rezolvate de ctre J. Williams, creatorul metodei de
sortare heapsort (sortare de ansamble).
Metoda n sine, reprezint o realizare de excepie printre metodele convenionale
de sortare i utilizeaz o reprezentare special a unui arbore binar parial ordonat,
numit "ansamblu".
Un ansamblu ("heap") este definit ca o secven de chei h
s
, h
s+1
, ..., h
d
care se
bucur de proprietile [3.2.5.a]:
------------------------------------------------------------
1 i 2 i
i 2 i
+
h h
h h
pentru toi i = s, ..., d/2 [3.2.5.a]
------------------------------------------------------------
Un ansamblu poate fi asimilat cu un arbore binar parial ordonat i reprezentat
printr-un tablou.
Spre exemplu, ansamblul h
1
, h
2
, ...., h
15
poate fi asimilat cu arborele binar din
figura 3.2.5.d i poate fi reprezentat prin tabloul h n baza urmtoarei tehnici:
o Se numeroteaz elementele ansamblului, nivel cu nivel, de sus n jos, de
la stnga la dreapta;
o Se asociaz elementelor ansamblului, locaiile unui tablou de elemente h,
astfel nct elementului h
i
al ansamblului i corespunde locaia h[i].
h
1
h
2
h
3
h
4
h
5
h
6
h
7
h
8
h
9
h
10
h
11
h
12
h
13
h
14
h
15
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Fig.
3.2.5.d. Reprezentarea unui ansamblu printr-un tablou liniar h
Un ansamblu se bucur de proprietatea c primul su element este cel mai mic
dintre toate elementele ansamblului adic h
1
= min
(h
1
, ...., h
n
) .
Se presupune un ansamblu h
s+1
, h
s+2
, ...., h
d
definit prin indicii s
+1 i d
Acestui ansamblu i se adaug la stnga, pe poziia h
s
un nou element x
,
obinndu-se un ansamblu extins spre stnga h
s
, ..., h
d
.
34
h
1
04
22
04 22
12
65
83
18
12
65 83 18 34
1 2 3 4 5 6 7
1 2 3 4 5 6 7
(a) (b)
Fig. 3.2.5.e. Deplasarea unei chei ntr-un ansamblu
n figura 3.2.5.e.(a) apare ca exemplu ansamblul
h
2
, ...., h
7
, iar n aceeai figur
(b), ansamblul extins spre stnga cu un element x = 34
.
o Noul ansamblu se obine din cel anterior plasnd pe x n vrful ansamblului
i deplasndu-l "n jos" de-a lungul drumului indicat de componentele cele
mai mici, care n acelai timp urc.
o Astfel valoarea 34 este mai nti schimbat cu valoarea 04, apoi cu
valoarea 12, genernd structura din figura amintit.
o Se poate verifica cu uurin c aceast deplasare conserv condiiile care
definesc un ansamblu [3.2.5.a].
Notnd cu i
i j indicii elementelor care se interschimb, i presupunnd c x a
fost introdus pe poziia h
s
, tehnica de implementare a unei astfel de deplasri
apare n [3.2.5.b] n variant pseudocod.
------------------------------------------------------------
22 04 65 83 18 12 04 22 12 65 83 18 34
*Deplasarea unei chei de sus n jos ntr-un ansamblu -
varianta pseudocod
procedure Deplasare(s,d:
TipIndice){limitele ansamblului}
i:= s; {indic elementul curent)
j:= 2*i; {indic fiul stng al elementului curent}
temp:= h[i] {elementul care se deplaseaz}
ct timp exist niveluri n ansamblu (ji) i locul de
plasare nu a fost gsit execut
*selecteaz pe cel mai mic dintre fii elementului
indicat de i (pe h[j] sau pe h[j+1]
dac temp>fiul_selectat atunci
*deplaseaz fiul selectat n locul tatlui
su (h[i]:=h[j]);
*avanseaz pe nivelul urmtor al ansamblului
(i:=j; j:=2*i)
altfel [3.2.5.b]
retur {locul a fost gsit}
*plaseaz pe temp la locul su n ansamblu
(h[i]:=temp);
------------------------------------------------------------
Procedura Pascal care implementeaz algoritmul de deplasare apare n [3.2.5.c].
------------------------------------------------------------
{Deplasarea unei chei de sus n jos ntr-un ansamblu -
Varianta Pascal}
PROCEDURE Deplasare(s,d: TipIndice);
VAR i,j: TipIndice; temp: TipElement; ret: boolean;
BEGIN
i:= s; j:= 2*i; temp:= h[i]; ret:= false;
WHILE(j<=d) AND (NOT ret) DO
BEGIN
IF j<d THEN
IF h[j].cheie>h[j+1].cheie THEN j:= j+1;
IF temp.cheie>h[j].cheie THEN
BEGIN
h[i]:= h[j]; i:= j; j:= 2*i [3.2.5.c]
END
ELSE
ret:= true
END;{WHILE}
h[i]:= temp
END; {Deplasare}
------------------------------------------------------------
R.W. Floyd a sugerat o metod de a construi un ansamblu in situ, utiliznd procedura
de deplasare n ansamblu prezentat mai sus:
Se consider un tablou h
1
, ..., h
n
n care n mod evident elementele h
n/2
, ..., h
n
formeaz deja un ansamblu deoarece nu exist nici o pereche de indici i i j
care s satisfac relaia j=2*i (sau j=2*i+1).
Aceste elemente formeaz cea ce poate fi considerat drept irul de baz al
ansamblului asociat.
n continuare, ansamblul este extins spre stnga, la fiecare pas cu cte un
element, introdus n vrf i deplasat pn la locul su.
Prin urmare, considernd c tabloul iniial este memorat n h, procesul de
generare "in situ" al unui ansamblu poate fi descris prin secvena [3.2.5.d].
------------------------------------------------------------
{Faza creare ansamblu}
s:= (n DIV 2)+1;
WHILE s>1 DO
BEGIN [3.2.5.d]
s:= s-1; Deplasare(s,n)
END;{WHILE}
------------------------------------------------------------
n vederea sortrii elementelor, se execut n pai de Deplasare, dup fiecare pas
selectndu-se vrful ansamblului.
Problema care apare este aceea a locului n care se memoreaz vrfurile consecutive
ale ansamblului, respectiv elementele sortate, respectnd constrngerea "in situ".
Aceast problem poate fi rezolvat astfel:
n fiecare pas al procesului de sortare se interschimb ultima component a
ansamblului cu componenta aflat n vrful acestuia (h[1]).
Dup fiecare astfel de interschimbare ansamblul se restrnge la dreapta cu o
component.
n continuare se las componenta din vrf (h[1]) s se deplaseze spre locul su n
ansamblu.
n termenii procedurii Deplasare aceast tehnic poate fi descris ca n
secvena [3.2.5.e].
------------------------------------------------------------
{Faza sortare}
d:= n;
WHILE d >1 DO
BEGIN
temp:= h[1]; h[1]:= h[d]; h[d]:= temp; [3.2.5.e]
d:= d-1; Deplasare(1,d)
END;{WHILE}
------------------------------------------------------------
Cheile se obin sortate n ordine invers, lucru care poate fi uor remediat
modificnd sensul relaiilor de comparaie din cadrul procedurii Deplasare.
Rezult urmtorul algoritm care ilustreaz tehnica de sortare heapsort [3.2.5.f].
------------------------------------------------------------
{Sortare prin metoda ansamblelor Heapsort - Varianta Pascal}
PROCEDURE Heapsort;
VAR s,d: TipIndice; temp: TipElement;
PROCEDURE Deplasare;
VAR i,j: TipIndice; ret: boolean;
BEGIN
i:=s; j:= 2*i; temp:= h[i]; ret:= false;
WHILE (j<=d) AND (NOT ret) DO
BEGIN
IF j<d THEN
IF h[j].cheie<h[j+1].cheie THEN j:= j+1;
IF temp.cheie<h[j] THEN
BEGIN
h[i]:= h[j]; i:= j; j:= 2*i
END
ELSE
ret:= true
END;{WHILE}
h[i]:= temp
END; {Deplasare}
BEGIN {Faza construcie ansamblu}
s:= (n DIV 2)+1; d:= n; [3.2.5.f]
WHILE s>1 DO
BEGIN
s:= s-1; Deplasare
END;{WHILE}
WHILE d>1 DO {Faza sortare}
BEGIN
temp:= h[1]; h[1]:= h[d]; h[d]:= temp;
d:= d-1; Deplasare
END
END; {Heapsort}
-----------------------------------------------------------
Analiza metodei heapsort.
La prima vedere nu rezult n mod evident faptul c aceast metod conduce la
rezultate bune.
Analiza performanelor metodei heapsort contrazice ns aceast prere.
La faza de construcie a ansamblului sunt necesari n/2 pai de deplasare,
n fiecare fiecare pas se mut elemente de-a lungul a respectiv
log(n/2) , log(n/2
+1) , ...
, log(n-1) poziii, (n cel mai defavorabil
caz), unde logaritmul se ia n baza 2 i se trunchiaz la prima valoare
ntreag.
n continuare, faza de sortare necesit n-1 deplasri cu cel mult log (n-2) , log (n-
1) , ...
, 1 micri.
n plus mai sunt necesare 3
(n
-1) micri pentru a aeza elementele sortate n
ordine.
Toate acestea dovedesc c n cel mai defavorabil caz, tehnica heapsort are nevoie
de un numr de pai de ordinul O(n
log n) [3.2.5.g].
------------------------------------------------------------
O(n/2
log
2
(n-1) + (n-1)
log
2
(n-1) + 3
(n-1)) = O(n
log
2
n) [3.2.5.g]
------------------------------------------------------------
Este greu de determinat cazul cel mai defavorabil i cazul cel mai favorabil pentru
aceast metod.
n general ns, tehnica heapsort este mai eficient n cazurile n care elementele sunt
ntr-o mai mare msur sortate n ordine invers; evident faza de creare a arborelui nu
necesit nici o micare dac elementele sunt chiar n ordine invers.
Numrul mediu de micri este aproximativ egal cu 1/2
log n
, deviaiile de la
aceast valoare fiind relativ mici.
n manier specific metodelor de sortare avansate, valorile mici ale numrului de
elemente n, nu sunt suficient de reprezentative, eficiena metodei crescnd o dat cu
creterea lui n
.
n secvena [3.2.5.h] se prezint varianta C a algoritmului de sortare prin metoda
ansamblelor.
------------------------------------------------------------
//sortare prin metoda ansamblelor - heapsort - varianta C
deplasare(int s,int d) { //globale: int a[],int n
int i=s,j=2*s,x=a[i-1],ret=0;
while(j<=d && !ret) {
if(j<d && a[j-1]<a[j])j++;
(x<a[j-1])?(a[i-1]=a[j-1],i=j,j=2*i):(ret=1);
}
a[i-1]=x;
} [3.2.5.h]
heapsort() { //globale: int a[],int n
//construire ansamblu
int s=n/2+1,d=n;
while(s-1)deplasare(--s,n);
//sortare
while(d-1) {
int x=a[0]; a[0]=a[d-1]; a[d-1]=x;
deplasare(1,--d);
}
}
------------------------------------------------------------
3.2.6. Sortarea prin partiionare
Dei metoda bubblesort bazat pe principiul interschimbrii este cea mai puin
performant dintre metodele studiate,
C.A.R. Hoare, pornind de la acelai principiu, a conceput o metod cu performane
spectaculare pe care a denumit-o quicksort (sortare rapid).
Aceasta se bazeaz pe aceeai idee de a crete eficiena interschimbrilor prin mrirea
distanei dintre elementele implicate.
Sortarea prin partiionare pornete de la urmtorul algoritm.
Fie x un element oarecare al tabloului de sortat a
1
, ..., a
n
.
Se parcurge tabloul de la stnga spre dreapta pn se gsete primul element
a
i
> x
.
n continuare se parcurge tabloul de la dreapta spre stnga pn se gsete
primul element a
j
< x
.
Se interschimb ntre ele elementele a
i
i a
j
,
Se continu parcurgerea tabloului de la stnga respectiv de la dreapta (din
punctele n care s-a ajuns anterior), pn se gsesc alte dou elemente care se
interschimb, .a.m.d.
Procesul se termin cnd cele dou parcurgeri se "ntlnesc" undeva n
interiorul tabloului.
Efectul final este c acum irul iniial este partiionat ntr-o partiie stnga
cu chei mai mici dect x i o partiie dreapta cu chei mai mari dect x.
Considernd elementele irului memorate n tabloul a
, principiul partiionrii apare
prezentat sintetic n [3.2.6.a].
------------------------------------------------------------
*Partiionarea unui tablou - varianta pseudocod
procedure Partiionare {Partiioneaz tabloul a[s..d]}
*selecteaz elementul x (de regul de la mijlocul
intervalului de partiionat)
repet
*caut primul element a[i]>x, parcurgnd
intervalul de la stnga la dreapta
*caut primul element a[j]<x, parcurgnd
intervalul de la dreapta la stnga
dac i<=j atunci [3.2.6.a]
*interschimb pe a[i] cu a[j]
pn cnd parcurgerile se ntlnesc (i>j)
-----------------------------------------------------------
nainte de a trece la sortarea propriu-zis, se d o formulare mai precis partiionrii n
forma unei proceduri [3.2.6.b].
Se precizeaz c relaiile > respectiv < au fost nlocuite cu respectiv ale cror
negate utilizate n instruciunile WHILE sunt < respectiv >.
n acest caz x joac rol de fanion pentru ambele parcurgeri.
------------------------------------------------------------
{Procedura Partiionare - Varianta Pascal}
PROCEDURE Partitionare;
VAR x,temp: TipElement;
BEGIN
[1] i:= 1; j:= n;
[2] x:= a[n DIV 2]; [3.2.6.b]
[3] REPEAT
[4] WHILE a[i].cheie<x.cheie DO i:= i+1;
[5] WHILE a[j].cheie>x.cheie DO j:= j-1;
[6] IF i<=j THEN
BEGIN
[7] temp:= a[i]; a[i]:= a[j]; a[j]:= temp;
[8] i:= i+1; j:= j-1
END
[9] UNTIL i>j
END; {Partitionare}
------------------------------------------------------------
n continuare, cu ajutorul partiionrii, sortarea se realizeaz simplu:
Dup o prim partiionare a secvenei de elemente se aplic aceeai procedur
celor dou partiii rezultate,
Apoi celor patru partiii ale acestora, .a.m.d.
Pn cnd fiecare partiie se reduce la un singur element.
Tehnica sortrii bazat pe partiionare este ilustrat n secvena [3.2.6.c].
------------------------------------------------------------
*Sortarea prin partiionare -quicksort - varianta pseudocod
procedure QuickSort(s,d);
*partiioneaz intervalul s,d fa de Mijloc
dac exist partiie stnga atunci
QuickSort(s,Mijloc-1) [3.2.6.c]
dac exist partiie dreapta atunci
QuickSort(Mijloc+1,d);
--------------------------------------------------------
n secvena [3.2.6.d] apare o implementare a sortrii Quicksort n variant Pascal iar
n secvena [3.2.6.e] varianta de implementare n limbajul C.
------------------------------------------------------------
{Sortarea prin partiionare Quicksort - Varianta Pascal}
PROCEDURE Quicksort;
PROCEDURE Sortare(VAR s,d: TipIndice);
VAR i,j: TipIndice;
x,temp: TipElement;
BEGIN
i:= s; j:= d;
x:= a[(s+d) DIV 2];
REPEAT
WHILE a[i].cheie<x.cheie DO i:= i+1;
WHILE x.cheie<a[j].cheie DO j:= j-1; [3.2.6.d]
IF i<=j THEN
BEGIN
temp:= a[i]; a[i]:= a[j]; a[j]:= temp;
i:= i+1; j:= j-1
END
UNTIL i>j;
IF s<j THEN Sortare(s,j);
IF i<d THEN Sortare(i,d);
END; {Sortare}
BEGIN
Sortare(1,n)
END; {Quicksort}
------------------------------------------------------------
//Sortarea prin partiionare - quicksort - varianta C
quicksort(int s,int d) { //int a[],int n
int i=s,j=d,x=a[(s+d)/2];
do {
while(a[i]<x)i++;
while(a[j]>x)j--;
if(i<=j) {
int w=a[i]; [3.2.6.e]
a[i]=a[j];
a[j]=w;
i++;j--;
}
}while(i<=j);
if(s<j)quicksort(s,j);
if(d>i)quicksort(i,d);
}
------------------------------------------------------------
n continuare se prezint o manier de implementare a aceluiai algoritm utiliznd o
procedur nerecursiv.
Elementul cheie al soluiei iterative rezid n meninerea unei liste a cererilor de
partiionare.
Astfel, la fiecare trecere apar dou noi partiii.
Una dintre ele se prelucreaz imediat, cealalt se amn, prin memorarea ei ca
cerere n list.
n mod evident, lista de cereri trebuie rezolvat n sens invers, adic prima
solicitare se va rezolva ultima i invers,
Cu alte cuvinte lista se trateaz ca o stiv.
n secvena [3.2.6.f
] apare o schi de principiu a acestei implementri n
variant pseudocod.
------------------------------------------------------------
*Sortare QuickSort. Implementare nerecursiv - Varianta
pseudocod
procedure QuickSortNerecursiv;
*se introduc n stiv limitele intervalului iniial
de sortare (amorsarea procesului)
repet
*se extrage intervalul din vrful stivei care
devine IntervalCurent
*se reduce stiva cu o poziie [3.2.6.f]
repet
repet
*se partiioneaz IntervalCurent
pn cnd terminare partiionare
dac exist interval drept atunci
*se introduc limitele sale in stiv
*se face intervalul stng IntervalCurent
pn cnd intervalul ajunge de lime 1 sau 0
pn cnd stiva se golete
------------------------------------------------------------
n procedura Pascal care implementeaz algoritmul din secvena anterioar,
O cerere de partiionare este reprezentat printr-o pereche de indici care
delimiteaz zona de tablou ce urmeaz a fi partiionat.
Stiva este modelat cu ajutorul unui tablou cu dimensiunea variabil numit
stiva i de un index is care precizeaz vrful acesteia [3.2.6.g].
Dimensiunea maxim m a stivei va fi discutat pe parcursul analizei metodei.
------------------------------------------------------------
{Sortare QuickSort. Implementare nerecursiv - Varianta
Pascal}
PROCEDURE QuickSortNerecursiv;
CONST m = ...;
VAR i,j,s,d: TipIndice;
x,temp: TipElement;
is: 0..m;
stiva: ARRAY[1..m] OF
RECORD
s,d: TipIndice
END;
BEGIN
is:= 1; stiva[1].s:= 1; stiva[1].d:= n;
REPEAT {se ia cererea din vrful stivei}
s:= stiva[is].s; d:= stiva[is].d; is:= is-1;
REPEAT {partiionarea lui a[s],a[d]}
i:= s; j:= d; x:= a[(s+d) DIV 2];
REPEAT
WHILE a[i].cheie<x.cheie DO i:= i+1;
WHILE x.cheie<a[j].cheie DO j:= j-1;
IF i<=j THEN [3.2.6.g]
BEGIN
temp:= a[i]; a[i]:= a[j]; a[j]:= temp;
i:= i+1; j:= j-1
END
UNTIL i>j;
IF i<d THEN
BEGIN {partiia dreapta se introduce n stiv}
is:= is+1; stiva[is].s:= i; stiva[is].d:= d
END;
d:= j {partiia stnga devine curent}
UNTIL s>=d
UNTIL is=0
END; {QuickSortNerecursiv}
------------------------------------------------------------
Analiza metodei quicksort.
Pentru a analiza performana acestei metode, se analizeaz mai nti partiionarea.
Se presupune pentru simplificare,
(1) C setul ce va fi partiionat const din n chei distincte i unice cu
valorile {1, 2, 3, ..., n}
(2) C dintre cele n chei a fost selectat cheia cu valoarea x n vederea
partiionrii.
n consecin aceast cheie ocup a x-a poziie n mulimea ordonat a cheilor
i ea poart denumirea de pivot.
Se ridic urmtoarele ntrebri:
1. Care este probabilitatea ca dup ce a fost selectat cheia cu valoarea x ca pivot, o
cheie oarecare a partiiei s fie interschimbat
?
Pentru ca o cheie s fie interschimbat ea trebuie s fie mai mare ca x.
Sunt n-x+1 chei mai mari ca x
Rezult c probabilitatea ca o cheie oarecare s fie interschimbat este
(n
x
+
1)
/
n (raportul dintre numrul de cazuri favorabile i numrul
de cazuri posibile).
2. Care este numrul de interschimbri necesar la o partiionare a n chei pentru care s-
a selectat ca pivot cheia situat pe poziia x ?
La dreapta pivotului exist n
x
poziii care vor fi procesate n procesul de
partiionare.
Numrul posibil de interschimbri n acest context este deci egal cu produsul
dintre numrul de chei care vor fi selectate (n
x
) i probabilitatea ca o cheie
selectat s fie interschimbat.
n
x n
x n NrInt
) 1 (
) (
+
=
3. Care este numrul mediu de interschimbri pentru partiionarea unei secvene de n
chei?
La o partiionare poate fi selectat oricare din cele n chei ca i pivot, deci x
poate lua orice valoare cuprins ntre 1 i n.
Numrul mediu M de interschimbri pentru partiionarea unei secvene de n
chei se obine nsumnd toate numerele de interschimbri pentru toate valorile
lui x cuprinse ntre 1 i n i mprind la numrul total de chei n [3.2.6.h].
------------------------------------------------------------
6 6
1 6 ) 1 (
) (
1 1
M
1 1
n
n n n
x n
x n
n
NrInt
n
n
x
n
x
=
+
= =
= =
[3.2.6.h]
------------------------------------------------------------
Presupunnd n mod exagerat c ntotdeauna va fi selectat mediana partiiei
(mijlocul su valoric), fiecare partiionare va divide tabloul n dou jumti egale.
Se face precizarea c mediana este elementul situat ca i valoare n mijlocul partiiei,
dac aceasta este ordonat.
n aceste condiii este necesar un numr de treceri prin toate elementele tabloului egal
cu log n (fig.3.2.6.a).
Dup cum rezult din figura 3.2.6.a, pentru un tablou de 15 elemente sunt necesare
log
2
15 = 4 treceri prin toate elementele tabloului sau 4 pai de partiionare integral
a tabloului.
Numr apeluri Numr elemente de
partiionat pe apel
1 apel sortare
(15 elemente) 15 elemente 15
2 apeluri sortare
(7 elemente) 7 elemente 1 7 elemente 7
4 apeluri sortare
(3 elemente) 3 elem 1 3 elem 3 elem 1 3 elem 3
8 apeluri sortare
(1 element)
1 1 1 1 1 1 1 1 1 1 1 1 1
Fig.
3.2.6.a. Funcionarea principial a sortrii prin partiionare
Din pcate numrul de apeluri recursive ale procedurii este egal cu 15, adic exact cu
numrul de elemente.
Rezult c numrul total de comparaii este n
log n (la o trecere sunt comparate
toate cheile)
Numrul de micri este n/6
log n deoarece conform formulei [3.2.6.h] la
partiionarea a n chei sunt necesare n medie n/6 micri [3.2.6.i].
------------------------------------------------------------
n log n n log n
2 2
6
1
M C = = [3.2.6.i]
------------------------------------------------------------
Aceste rezultate sunt excepional de bune, dar se refer numai la cazul optim n care
s-a presupus c la fiecare trecere se selecteaz mediana, eveniment care de altfel are
probabilitatea doar 1/n.
Marele succes al algoritmului quicksort se datorete ns faptului surprinztor c
performana sa medie, la care alegerea pivotului se face la ntmplare, este inferioar
performanei optime doar cu un factor egal cu 2
1n
(2) = 1.4 deci cu aproximativ 40
%
[Wi76].
Tehnica prezentat are ns i dezavantaje.
n primul rnd ca i la toate metodele de sortare avansate, performanele ei
sunt moderate pentru valori mici ale lui n.
Acest dezavantaj poate fi contracarat prin ncorporarea unor metode de
sortare directe pentru partiiile mici, lucru realizabil relativ simplu la
aceast metod n raport cu alte metode avansate.
Un al doilea dezavantaj, se refer la cazul cel mai defavorabil n care
performana metodei scade catastrofal.
Acest caz apare cnd la fiecare partiionare este selectat cea mai mare
(cea mai mic) valoare ca i pivot.
Fiecare pas va partaja n acest caz secvena format din n elemente,
ntr-o partiie stnga cu n
1 elemente i o partiie dreapta cu un singur
element.
Vor fi necesare astfel n partiionri n loc de log
(n), iar performana
obine valori de ordinul O(n
2
).
n mod aparent, elementul esenial al acestei metode l reprezint selecia pivotului x
[GG78].
n exemplul prezentat, pivotul a fost ales la mijlocul partiiei.
El poate fi ns ales la extremitatea stng sau dreapt a acesteia, situaie n
care, cazul cel mai defavorabil l reprezint partiia deja sortat.
Tehnica quicksort se comport straniu:
Are performane slabe n cazul sortrilor banale
Are performane deosebite n cazul tablourilor dezordonate.
De asemenea, dac x se alege ntotdeauna la mijloc (mediana), atunci tabloul sortat
invers devine cazul optim al sortrii quicksort.
De fapt performana medie este cea mai bun n cazul alegerii pivotului la
mijlocul partiiei.
Hoare sugereaz ca alegerea s se fac:
(1) Fie la "ntmplare",
(2) Fie prin selecia medianei unui numr redus de chei (spre exemplu
trei chei).
O astfel de alegere judicioas a pivotului influeneaz serios n mod negativ
performana medie a algoritmului quicksort, dar nbuntete n mod
considerabil performana cazului cel mai defavorabil.
Pentru programator, n multe situaii cazul cel mai defavorabil are o influen
deosebit.
Spre exemplu n secvena [3.2.6.g] care implementeaz metoda quiqsort n
manier iterativ, n cazul cel mai defavorabil, la fiecare partiionare rezult o
partiie dreapta cu un singur element, a crei cerere de sortare se introduce n
stiv.
Este evident c n acest caz, dimensiunea maxim a stivei trebuie s fie egal
cu numrul de elemente n, situaie care nu este acceptabil.
Acest lucru este i mai grav n cazul recursivitii unde stiva gestionat n
mod automat este mult mai substanial, fiind necesar cte un nod pentru
fiecare apel recursiv, nod care presupune spaiu de memorie pentru stocarea
valorilor parametrilor locali ai apelului la care se adaug de regul i codul
efectiv al procedurii.
Aceast situaie se rezolv, introducnd n stiv cererea de sortare a partiiei
mai mari i continund cu partiionarea partiiei mai mici.
n acest caz dimensiunea m a stivei poate fi limitat la m = log
2
n
.
Pentru a implementa aceast tehnic, secvena [3.2.6.g] se modific n
poriunile n care se proceseaz cererile de partiionare conform [3.2.6.j].
------------------------------------------------------------
{Reducerea dimensiunii stivei n implementarea iterativ a
sortrii Quicksort}
IF j-s < d-i THEN
BEGIN
IF i<d THEN
BEGIN {cerere sortare dreapta n stiv}
is:= is+1; stiva[is].s:= i; stiva[is].d:= d
END;
d:= j {se continu sortarea partiiei stnga}
END
ELSE
BEGIN [3.2.6.j]
IF s<j THEN
BEGIN {cerere sortare stnga n stiv}
s:= is+1; stiva[is].s:= s; stiva[is].d:= j
END;
s:= i {se continu sortarea partiiei dreapta}
END;
------------------------------------------------------------
3.2.7. Determinarea medianei
Mediana a n elemente este definit ca fiind acel element care este mai mic (sau
egal) dect jumtate din elemente i este mai mare (sau egal) dect cealalt
jumtate.
o Spre exemplu mediana secvenei 16, 12, 99, 95, 18, 87, 10 este 18
.
Problema aflrii medianei este corelat direct cu cea a sortrii deoarece, o metod
sigur de a determina mediana este urmtoarea:
o Se sorteaz cele n elemente
o Se extrage elementul din mijloc.
Tehnica partiionrii poate ns conduce la o metod general mai rapid, cu
ajutorul creia se poate determina cel de-al
k-lea element ca valoare dintre n
elemente.
o Gsirea medianei reprezint cazul special k = n
/
2
.
o n acelai context, k = 1
precizeaz aflarea minimului, iar
k = n
, aflarea
maximului.
Algoritmul conceput de C.A.R. Hoare funcioneaz dup cum urmeaz.
o Se presupune c elementele avute n vedere sunt memorate n tabloul a cu
dimensiunea n,
o Pentru nceput se realizeaz o partiionare cu limitele s
=
1, d
=
n i cu
a[k] selectat pe post de pivot x.
o n urma acestei partiionri rezult valorile index i i j care satisfac
relaiile [3.2.7.a].
------------------------------------------------------------
1) x = a[k]
2) a[h]
x pentru toi h
<
i
3) a[h]
x pentru toi h
>
j [3.2.7.a]
4) i
>
j
------------------------------------------------------------
o Sunt posibile trei situaii:
1. Valoarea pivotului x a fost prea mic, astfel nct limita dintre cele dou
partiii este sub valoarea dorit k. Procesul de partiionare trebuie
continuat pentru elementele a[i],...,a[d] (partiia dreapta)
(fig.3.2.7.a (a)).
2. Valoarea pivotului x a fost prea mare. Operaia de partiionare continu
pentru partiia a[s],...,a[j] (partiia stnga) (fig.3.2.7.a (b)).
3. j
<
k
<
i
. n acest caz elementul a[k] separ tabloul n dou partiii, el
desemnnd mediana (fig.3.2.7.a (c)).
o Procesul de partiionare se repet pn la realizarea cazului 3.
(a)
s j i k d
(b)
s k j i d
(c)
s j
k i d
Fig.
3.2.7.a. Determinarea medianei
Algoritmul aferent este prezentat n variant peseudocod n secvena [3.2.7.b]
respectiv o prim rafinare n secvena de program [3.2.7.c].
------------------------------------------------------------
procedure Mediana (s,d,k);
ct timp exist partiie [3.2.7.b]
*alege pivotul (elementul din poziia k)
*partiioneaz intervalul curent faa de valoarea
pivotului
dac poziie pivot<k atunci *selecteaz partiia
dreapta
dac poziie pivot>k atunci *selecteaz partiia
stnga
------------------------------------------------------------
{Procedura Mediana}
s:= 1; d:= n ;
WHILE s<d DO
BEGIN
x:= a[k]; [3.2.7.c]
*se partiioneaz a[s]...a[d]
IF j<k THEN s:= i;
IF k<i THEN d:= j
END;
------------------------------------------------------------
Programul aferent apare n secvena [3.2.7.d] n variant Pascal.
------------------------------------------------------------
PROCEDURE Mediana (k:integer);
VAR s,d,i,j: TipIndice; x,temp: TipElement;
BEGIN
s:=1; d:=n;
WHILE s<d DO
BEGIN
x:= a[k]; i:= s; j:= d;
REPEAT {partitionarea} [3.2.7.d]
WHILE a[i]<x DO i:= i+1;
WHILE x<a[j] DO j:= j-1;
IF i<=j DO
BEGIN
temp:= a[i]; a[i]:= a[j]; a[j]:= temp;
i:= i+1; j:= j-1
END
UNTIL i>j;
IF j<k THEN s:= i;
IF k<i THEN d:= j
END {WHILE}
END; {Mediana}
-----------------------------------------------------------
Dac se presupune c n medie fiecare partiionare njumtete partiia n care se
gsete elementul cutat, atunci numrul necesar de comparaii C este de ordinul
lui n [3.2.7.e].
------------------------------------------------------------
1 2 1
4 2
C = + + + + = n
n n
n [3.2.7.e]
-----------------------------------------------------------
Numrul de micri M nu poate depi numrul de comparaii, el fiind de regul
mai mic.
Valorile indicatorilor C i M estimai pentru determinarea medianei subliniaz
superioritatea acestei metode i explic performana ei fa de metodele bazate pe
sortarea tabloului i extragerea celui de-al k-lea element, a cror performan n cel
mai bun caz este de ordinul O(n
log n).
n cel mai defavorabil caz, fiecare partiionare reduce setul de candidai numai cu
1, rezultnd un numr de comparaii de ordinul O(n
2
). i n acest caz metoda
medianei este indicat pentru valori mari ale lui n (n >
10).
3.2.8. Sortarea binsort. Determinarea distribuiei cheilor
n general algoritmii de sortare bazai pe metode avansate au nevoie de O(n
log n)
pai pentru a sorta n elemente.
Trebuie precizat ns faptul c acest lucru este valabil n situaia n care nu exist nici o
alt informaie suplimentar referitoare la chei, dect faptul c pe mulimea acestora
este definit o relaie de ordonare, prin intermediul creia se poate preciza dac
valoarea unei chei este mai mic respectiv mai mare dect o alta.
Dup cum se va vedea n continuare, sortarea se poate face i mai rapid dect n
limitele performanei O(n
log n), dac:
o Exist i alte informaii referitoare la cheile care urmeaz a fi sortate
o i se renun mcar parial la constrngerea de sortare "in situ".
Spre exemplu, se cere s se sorteze un set de n chei de tip ntreg, ale cror valori sunt
unice i aparin intervalului de la 1 la n.
o n acest caz, dac a i b sunt tablouri identice cu cte n elemente, a
coninnd cheile care urmeaz a fi sortate, atunci sortarea se poate realiza
direct n tabloul b conform secvenei [3.2.8.a].
------------------------------------------------------------
FOR i:= 1 TO n DO
b[a[i].cheie]:= a[i]; {O(n)} [3.2.8.a]
------------------------------------------------------------
o n secvena [3.2.8.a] se determin locul elementului a[i] i se plaseaz
elementul la locul potrivit.
o ntregul ciclu necesit O(n) pai.
o Rezultatul este ns corect numai n cazul n care exist un singur element cu
cheia x, pentru fiecare valoare cuprins ntre [1,n]. Un al doilea element cu
aceeai cheie va fi introdus tot n b[x] distrugnd elementul anterior.
Acest tip de sortare poate fi realizat i "in situ", element care prezint interes din punctul
de vedere al tehnicilor analizate.
o Astfel, fiind dat tabloul a de dimensiune n, ale crui elemente au respectiv
cheile 1, ..., n, se baleeaz pe rnd elementele sale.
o Dac elementul a[i] are cheia j, atunci se realizeaz interschimbarea lui
a[i] cu a[j].
o Fiecare interschimbare plaseaz elementul aflat n locaia i exact la locul su
n tabloul ordonat, fiind necesare n cel mai ru caz 3
n micri pentru ntreg
procesul de sortare.
o Secvena de program care ilustreaz aceast tehnic apare n [3.2.8.b].
------------------------------------------------------------
FOR i:= 1 TO n DO
WHILE a[i].cheie<>i DO
BEGIN [3.2.8.b]
temp:= a[i];a[i]:= a[a[i].cheie];
a[temp.cheie]:= temp
END;
------------------------------------------------------------
Secvenele [3.2.8.a,
b] ilustreaz tehnica de sortare numit binsort, n cadrul creia se
creaz bin-uri, fiecare bin pstrnd un element sortat cu o anumit cheie [AHU85].
Tehnica sortrii este simpl:
o se examineaz fiecare element de sortat i se introduce n bin-ul corespunztor
valorii cheii.
n secvena [3.2.8.a] bin-urile sunt chiar elementele tabloului b, unde b[i] este binul
cheii avnd valoarea i, iar n secvena [3.2.8.b] bin-urile sunt chiar elementele
tabloului a dup reaezare.
Tehnica aceasta att de simpl i de performant se bazeaz pe urmtoarele cerine
apriorice:
o (1) Domeniul limitat al cheilor (1,
n)
o (2) Unicitatea fiecrei chei.
Dac cea de-a doua cerin nu este respectat, i de fapt acesta este cazul obinuit, este
necesar ca ntr-un bin s fie memorate mai multe elemente avnd aceeai cheie.
Acest lucru se realizeaz fie prin niruire, fie prin concatenare, fiind utilizate n acest
scop structuri de date list.
Aceast situaie nu deterioreaz prea mult performanele acestei tehnici, efortul de
sortare ajungnd egal cu O(n+m), unde n este numrul de elemente iar m numrul de
chei, motiv pentru care aceast metod reprezint punctul de plecare al mai multor
tehnici de sortare a structurilor list [AHU85].
Spre exemplu, o metod de rezolvare a unei astfel de situaii este cea bazat pe
determinarea distribuiei cheilor ("distribution counting") [Se88].
Problema se formuleaz astfel: se cere s se sorteze un tablou cu n articole ale cror
chei sunt cuprinse ntre 0 i m-1.
Dac m nu este prea mare pentru rezolvarea problemei poate fi utilizat algoritmul de
"determinare a distribuiei cheilor".
Ideea algoritmului este:
o Se contorizeaz ntr-o prim trecere numrul de chei pentru fiecare valoare de
cheie care apare n tabloul a;
o Se ajusteaz valorile contoarelor;
o ntr-o a doua trecere, utiliznd aceste contoare, se mut direct articolele n
poziia lor ordonat n tabloul b.
o Formularea algoritmului este cea din secvena [3.2.8.c]. Pentru simplificare se
presupune c tabloul a este un tablou care conine doar chei.
------------------------------------------------------------
TYPE TipCheie = 0..m-1;
TipTablou = ARRAY [1..n] OF TipCheie;
VAR numar: ARRAY[0..m-1] OF TipCheie;
a,b: TipTablou;
i,j: TipIndice;
{ Sortare bazat pe determinarea distribuiei cheilor
(distribution counting)}
BEGIN
FOR j:= 1 TO m-1 DO numar[j]:= 0;
FOR i:= 1 TO n DO numar[a[i]]:= numar[a[i]]+1;
FOR j:= 1 TO m-1 DO numar[j]:= numar[j-1]+numar[j];
FOR i:=n DOWNTO 1 DO
BEGIN
b[numar[a[i]]]:= a[i]; [3.2.8.c]
numar[a[i]]:= numar[a[i]]-1
END;
FOR i:= 1 TO n DO a[i]:= b[i];
END; {Sortare cu determinarea distributiilor}
------------------------------------------------------------
Contoarele asociate cheilor sunt memorate n tabloul numar de dimensiune m
.
Iniial locaiile sunt iniializate pe zero (prima bucl FOR)
Sunt contorizate cheile (a doua bucl FOR).
n continuare sunt ajustate valorile contoarelor tabloului numar (a treia bucl FOR)
astfel nct,
Parcurgnd tabloul a de la sfrit spre nceput, cheile s poat fi introduse exact la
locul lor n tabloul b cu ajutorul contoarelor memorate n tabloul numar (a patra
bucl FOR).
Concomitent cu introducerea are loc i ajustarea contoarelor astfel nct cheile
identice s fie introduse n binul specific n ordinea relativ n care apar ele n
secvena iniial.
Ultima bucl realizeaz mutarea integral a elementelor tabloului b n tabloul a, dac
acest lucru este necesar.
Dei se realizeaz mai multe treceri prin elementele tabloului totui n ansamblu,
performana algoritmului este O(n)
.
Aceasta metod de sortare pe lng faptul c este rapid are avantajul de a fi stabil,
motiv pentru care ea st la baza mai multor metode de sortare de tip radix.
n continuare se prezint un exemplu de funcionare a algoritmului de sortare bazat pe
determinarea distribuiei cheilor.
------------------------------------------------------------
Exemplul 3.2.8. Schematic, n vederea sortrii cu determinarea distribuiei
cheilor se parcurg urmtorii pai.
1) Se consider iniial c tabloul a are urmtorul coninut:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
a b b a c a D a b b a d d a
0 1 1 0 2 0 3 0 1 1 0 3 3 0
2) Se iniializeaz tabloul numar:
0 1 2 3
0 0 0 0
3) Se contorizeaz valorile cheilor tabloului a:
0 1 2 3
6 4 1 3
4) Se ajusteaz valorile tabloului numar:
0 1 2 3
6 10 11 14
5) Se iau elementele tabloului a de la dreapta la stnga i se introduc pe rnd n tabloul b,
fiecare n poziia indicat de contorul propriu din tabloul numar. Dup introducerea fiecrui
element n tabloul b, contorul specific din tabloul numar este decrementat cu o unitate.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
a a a a a a b b b b c d d d
-----------------------------------------------------------------
3.2.9. Sortarea bazat pe baze de numeraie. Radix sort
Metodele de sortare prezentate pn n prezent, concep cheile de sortat ca entiti pe
care le prelucreaz integral prin comparare sau interschimbare.
n unele situaii ns se poate profita de faptul c aceste chei sunt de fapt numere
aparinnd unui domeniu mrginit.
Metodele de sortare care iau n considerare proprietile digitale ale numerelor sunt
metodele de sortare bazate pe baze de numeraie ("radix sort").
Algoritmii de tip baz de numeraie, trateaz cheile ca i numere reprezentate ntr-o
baz de numeraie m, unde m poate lua diferite valori ("radix") i proceseaz cifrele
individuale ale numrului.
Un exemplu sugestiv l reprezint sortarea unui teanc de cartele care au perforate
pe ele numere formate trei cifre.
o Se grupeaz cartelele n 10 grupe distincte, prima cuprinznd cheile mai mici
dect 100, a doua cheile cuprinse ntre 100 i 199, etc., adic se realizeaz o
sortare dup cifra sutelor.
o n continuare se sorteaz pe rnd grupele formate aplicnd aceeai metod,
dup cifra zecilor,
o Apoi fiecare grup nou format, dup cifra unitilor.
o Acesta este un exemplu simplu de sortare radix cu m = 10.
Pentru sistemele de calcul, unde prelucrrile se fac exclusiv n baza 2, se preteaz cel
mai bine metodele de sortare radix care opereaz cu numere binare.
n general, n sortarea radix a unui set de numere, operaia fundamental este
extragerea unui set contiguu de bii din numrul care reprezint cheia.
Spre exemplu pentru a extrage primii 2 bii ai unui numr binar format din 10 cifre
binare:
o Se realizeaz o deplasare la dreapta cu 8 poziii a reprezentrii numrului,
o Apoi se opereaz configuraia obinut, printr-o operaie "i" cu masca
0000000011.
Aceste operaii pot fi implementate direct cu ajutorul facilitilor de prelucrare a
configuraiilor la nivel de bii puse la dispoziie de limbajele moderne de programare sau
pot fi simulate cu ajutorul operatorilor ntregi DIV i MOD.
o Spre exemplu, n situaia anterioar, dac x este numrul binar n cauz, primii
doi bii se obin prin expresia (x
DIV
2
8
)MOD
2
2
.
n cadrul acestui paragraf, pentru exemplificarea sortrilor radix, se consider definit
o funcie biti(x,k,j:integer):integer care combin cele dou operaii
returnnd j bii care apar la k poziii de la marginea dreapt a lui x.
O posibil implementare n limbajul C a acestei funcii apare n secvena [3.2.9.a].
------------------------------------------------------------
unsigned biti(unsigned x, int k, int j){
return (x>>k)&~(~0<<j);} [3.2.9.a]
------------------------------------------------------------
Exist dou metode de baz pentru implementarea sortrii radix.
Prima metod examineaz biii cheilor de la stnga la dreapta i se numete sortare
radix prin interschimbare ("radix exchange sort").
o Ea se bazeaz pe faptul c rezultatul comparaiei a dou chei este determinat
de valoarea biilor din prima poziie la care ele difer.
o Astfel, elementele ale cror chei au primul bit 0 sunt trecute n faa celor care
au primul bit 1;
o n continuare n fiecare grup astfel format se aplic aceeai metod pentru bitul
urmtor i aa mai departe.
o Sortarea propriu-zis se realizeaz prin schimbarea sistematic a elementelor
n maniera precizat.
A doua metod se numete sortare radix direct ("straight radix sort").
o Ea examineaz biii din cadrul cheilor de la dreapta la stnga i se bazeaz pe
principiul interesant care reduce sortarea cheilor de b-bii la b sortri ale unor
chei de 1bit.
3.2.9.1. Sortarea radix prin interschimbare
Se presupune c se dorete sortarea elementelor tabloului a astfel nct toate
elementele ale cror chei ncep cu un bit zero s fie trecute n faa celor care ncep
cu 1.
o Aceasta va avea drept consecin formarea a dou partiii ale tabloului
iniial,
o Aceste partiii la rndul lor se sorteaz independent, conform aceleai
metode dup cel de-al doilea bit al cheilor elementelor,
o Cele 4 partiii rezultate dup al 3-lea bit i aa mai departe.
Acest mod de lucru sugereaz abordarea recursiv a implementrii metodei de
sortare. Procesul se desfoar exact ca i la partiionare:
o Se baleaz tabloul de la stnga spre dreapta pn se gsete un element a
crui cheie care ncepe cu 1;
o Se baleeaz tabloul de la dreapta spre stnga pn se gsete un element
a crui cheie ncepe cu 0;
o Se interschimb cele dou elemente;
o Procesul continu pn cnd pointerii de parcurgere se ntlnesc formnd
dou partiii.
o Se reia aceeai procedur pentru cel de-al doilea bit al cheilor elementelor
n cadrul celor dou partiii rezultate .a.m.d. [3.2.9.1.a].
------------------------------------------------------------
PROCEDURE RadixInterschimb (s,d: TipIndice, b:INTEGER);
{s,d - limitele curente ale tabloului de sortat}
{b - lungimea n bii a cheii de sortat}
VAR i,j: TipIndice;
t: TipElement;
BEGIN [3.2.9.1.a]
IF (d>s) AND (b>=0) THEN
BEGIN
i:= s; j:= d; b:= b-1;
REPEAT
WHILE(biti(a[i].cheie,b,1)=0)AND(i<j) DO i:= i+1;
WHILE(biti(a[j].cheie,b,1)=1)AND(i<j) DO j:= j+1;
t:= a[i]; a[i]:= a[j]; a[j]:= t
UNTIL j=i;
IF biti(a[d].cheie,b,1)=
0 THEN j:= j+1; {dac toi
biii testai sunt 0 se reface lungimea partiiei}
RadixInterschimb(s,j-1,b-1);
RadixInterschimb(j,d,b-1);
END {IF}
END; {RadixInterschimb}
------------------------------------------------------------
Astfel dac se presupune c tabloul a[1..15] conine chei ntregi care au
valoarea mai mic dect 2
5
(adic se reprezint utiliznd 5 cifre binare), atunci
apelul RadixInterschimb(1,15,5)
va realiza sortarea dup cum se prezint
schematic n figura 3.2.9.1.
A
S
O
R
T
I
N
G
E
X
A
M
P
L
E
00001
10011
01111
10010
10100
01001
01110
00111
00101
11000
00001
01101
10000
01100
00101
A
E
O
L
M
I
N
G
E
A
X
T
P
R
S
0
0
0
0
0
0
0
0
0
0
1
1
1
1
1
0001
0101
1111
1100
1101
1001
1110
0111
0101
0001
1000
0100
0000
0010
0011
A
E
A
E
G
I
N
M
L
O
S
T
P
R
X
0
0
0
0
0
0
0
0
0
0
1
1
1
1
1
0
0
0
0
0
1
1
1
1
1
0
0
0
0
1
001
101
001
101
111
001
110
101
100
111
011
100
000
010
000
A
A
E
E
G
I
M
M
L
O
S
R
P
T
00
00
00
00
00
01
01
01
01
01
10
10
10
10
0
1
1
1
1
0
1
1
1
1
0
0
0
1
01
01
01
01
11
01
10
01
00
11
11
10
00
00
A
A
E
E
G
L
M
N
O
P
R
S
000
000
001
001
001
011
011
011
011
100
100
100
0
0
0
0
1
0
0
1
1
0
1
1
1
1
1
1
1
0
1
0
1
0
0
1
A
A
E
E
L
M
N
O
R
S
0000
0000
0010
0010
0110
0110
0111
0111
1001
1001
1
1
1
1
0
1
0
1
0
1
A
A
E
E
G
I
L
M
N
O
P
R
S
T
X
Fig. 3.2.9.1. Sortare radix prin interschimbare
O problem serioas care afecteaz aceast metod se refer la degenerarea
partiiilor.
o Degenerarea partiiilor apare de obicei n situaia n care cheile sunt
reprezentate prin numere mici (care ncep cu multe zerouri).
o Aceast situaie apare frecvent n cazul caracterelor interpretate pe 8 bii.
Din punctul de vedere al performanei, metoda de sortare radix prin
interschimbare sorteaz n chei de b bii utiliznd un numr de comparaii de bii
egal cu n b
.
o Cu alte cuvinte, sortarea radix prin interschimbare este liniar cu
numrul de bii ai unei chei.
o Pentru o distribuie normal a biilor cheilor, metoda lucreaz ceva mai
rapid dect metoda quicksort [Se88].
3.2.9.2. Sortarea radix direct
O alt variant de implementare a sortrii radix este aceea de a examina biii
cheilor elementelor de la dreapta la stnga.
Este metoda utilizat de vechile maini de sortat cartele.
o Teancul de cartele trece de 80 de ori prin main, cte odat pentru fiecare
coloan ncepnd de la dreapta spre stnga, fiecare trecere realiznd
sortarea dup o coloan.
o n cazul cheilor, cnd se ajunge la bitul i venind dinspre dreapta, cheile
sunt gata sortate pe ultimii i-1 bii ai lor.
o Sortarea continu extrgnd toate elementele ale cror chei au zero pe
poziia i i plasndu-le n faa celor care au 1 pe aceeai poziie.
Nu este uor de demonstrat c metoda este corect: de fapt ea este corect numai
n situaia n care sortarea dup 1 bit este stabil.
Datorit acestei cerine, sortarea radix prin interschimbare nu poate fi utilizat
deoarece nu este o metod de sortare stabil.
n ultim instan trebuie sortat stabil un tablou cu numai dou valori 0 i 1.
Metoda bazat pe determinarea distribuiilor (distribution counting) poate fi utilizat
cu succes n acest scop.
o Se consider algoritmul de sortare bazat pe determinarea distribuiei
cheilor n care:
Se ia m
=
2 i
Se nlocuiete a[i].cheie cu biti(a[i].cheie,k,1)
pentru k
=
0,
1,
2, ...,
b
-1 (adic se extrage din cheie 1 bit situat la
distana k fa de sfritul cheii)
.
o Se obine astfel, o metod de sortare stabil a tabloului a, dup bitul k, de
la dreapta la stnga, rezultatul fiind memorat ntr-o tablou temporar t
.
o Se reia sortarea bazat pe determinarea distribuiilor pentru fiecare bit al
cheii respectiv pentru pentru k
=
0,
1,
2, ...,
b
-1
o Rezult c pentru sortare sunt necesare b treceri unde b este lungimea
cheii.
De fapt, nu este indicat s se lucreze cu m
=
2
, ci este convenabil ca m s fie ct
mai mare.
Dac se prelucreaz m bii odat, timpul de sortare scade, dar tabela de distribuii
crete ca dimensiune ea trebuind s conin m1
=
2
m
locaii.
n acest mod, sortarea radix-direct devine o generalizare a sortrii bazate pe
determinarea distribuiilor.
Algoritmul din secvena [3.2.9.2.a] sorteaz dup aceast metod tabloul a[1..n],
o Cheile sunt de b bii lungime,
o Cheile sunt parcurse de la dreapta la stnga, procesnd cte m bii odat.
o Se utilizeaz tabloul suplimentar t[1..n].
Procedura funcioneaz numai dac b este multiplu de m deoarece algoritmul de
sortare divizeaz biii cheilor ntr-un numr ntreg de pri de dimensiuni egale
care se proceseaz deodat.
Dac se ia
m = b
se obine sortarea bazat pe determinarea distribuiilor;
Dac se ia
m =
1
rezult sortarea radix direct.
Implementarea propus sorteaz tabloul a n tabloul t i dup fiecare pas de
sortare recopiaz tabloul t n a (ultima bucl FOR).
Acest lucru poate fi evitat, concatennd n aceeai procedur dou copii ale
algoritmului de sortare: una care sorteaz din a n t, cealalt din t n a.
------------------------------------------------------------
PROCEDURE RadixDirect;
VAR i,j,trecere: integer;
numar: ARRAY[0..m1-1] OF integer; {m1:=2
m
}
BEGIN
FOR trecere:= 0 TO (b DIV m)-1 DO
BEGIN [3.2.9.2.a]
FOR j:= 0 TO m1-1 DO numar[j]:= 0;
FOR i:= 1 TO n DO
numar[biti(a[i].cheie,trecere*m,m)]:=
numar[biti(a[i].cheie,trecere*m,m)] + 1;
FOR j:= 1 TO m1-1 DO
numar[j]:= numar[j-1]+numar[j];
FOR i:= n DOWNTO 1 DO
BEGIN
t[numar[biti(a[i].cheie,trecere*m,m)]]:=
a[i];
numar[biti(a[i].cheie,trecere*m,m)]:=
numar[biti(a[i].cheie,trecere*m,m)]-1
END;
FOR i:= 1 TO n DO a[i]:= t[i]
END {FOR}
END; {RadixDirect}
-----------------------------------------------------------
Ca performan, sortarea radix direct:
o Poate sorta n elemente cu chei de b bii n b/m treceri,
o Utiliznd spaiu suplimentar de memorie pentru 2
m
contoare
o i un buffer pentru rearanjarea tabloului cu dimensiunea egal cu cea a tabloului
original.
3.2.9.2. Performana sortrilor radix
Timpul de execuie al celor dou metode de sortare radix fundamentale, pentru n
elemente avnd chei de b bii este n esen proporional cu n
*
b
.
Pe de alt parte, timpul de execuie poate fi aproximat ca fiind n
log
(n)
, deoarece
dac toate cheile sunt diferite, b trebuie s fie cel puin log
(n)
.
n realitate, nici una din metode nu atinge de fapt limita precizat n
*
b
:
o Metoda de la stnga la dreapta se oprete cnd apare o diferen ntre chei,
o Metoda de la dreapta la stnga poate prelucra mai muli bii deodat.
Sortrile radix se bucur de urmtoarele proprieti [Se88].
o Proprietatea 1. Sortarea radix prin interschimbare examineaz n medie n
log
(n)
bii.
o Proprietatea 2. La sortarea a n chei de cte b bii, ambele sortri radix
examineaz de regul mai puini dect n
*
b bii.
o Proprietatea 3. Sortarea radix direct poate sorta n elemente cu chei de b bii, n
b/m treceri utiliznd un spaiu suplimentar pentru 2
m
contoare i un buffer pentru
rearanjarea tabloului.
3.2.9.3. Sortarea liniar
Sortarea radix direct, anterior prezentat realizeaz b/m treceri prin tabloul de sortat.
Dac se alege pentru m o valoare suficient de mare se obine o metod de sortare
foarte eficient, cu condiia s existe un spaiu suplimentar de memorie cu 2
m
locaii.
O alegere rezonabil a valorii lui m este b/4 (un sfert din dimensiunea cheii) sortarea
radix reducndu-se n acest caz la 4 sortri bazate pe determinarea distribuiilor, care
sunt practic liniare.
o De obicei valorile m = 4 sau m = 8 sunt propice pentru actuala organizare a
sistemelor de calcul i conduc la dimensiuni rezonabile ale tabloului de
contoare (16 respectiv 256 de locaii).
o n consecin fiecare pas este liniar i deoarece sunt necesari numai 8 (4) pai
pentru chei de 32 de bii, procesul de sortare este practic liniar.
o Rezult astfel este una din cele mai performante metode de sortare, care
concureaz metoda quicksort, departajarea ntre ele fiind o problem dificil.
Dezavantajele majore ale metodei sunt:
o Necesitatea distribuiei uniforme a cheilor
o Necesitatea unor spaii suplimentare de memorie pentru tabloul de contoare i
pentru zona de sortare.
3.2.10. Sortarea tablourilor cu articole de mari dimensiuni. Sortarea
indirect
n situaia n care tablourile de sortat au elemente de mari dimensiuni, regia mutrii
acestor elemente n procesul sortrii este mare.
De aceea este mult mai convenabil ca algoritmul de sortare s opereze indirect asupra
tabloului original prin intermediul unui tablou de indici, urmnd ca tabloul original
s fie sortat ulterior ntr-o singur trecere.
o Astfel, unui tablou a[1..n] cu elemente de mari dimensiuni,
o I se asociaz un tablou de indici (indicatori) p[1..n];
o Iniial se definete p[i]:=i pentru i=1,n;
o Algoritmul utilizat n sortare se modific astfel nct s se acceseze
elementele tabloului a prin construcia a[p[i]] n loc de a[i].
o Accesul la a[i] prin p[i] se va realiza numai pentru comparaii, mutrile
efectundu-se n tabloul p[i].
o Cu alte cuvinte algoritmul va sorta tabloul de indici astfel nct p[1] va
conine indicele celui mai mic element al tabloului a, p[2] indicele
elementului urmtor, etc.
n acest mod se evit regia mutrii unor elemente de mari dimensiuni. Se realizeaz
de fapt o sortare indirect a tabloului a.
Principial o astfel de sortare este prezentat n figura 3.2.10.
Tabloul a nainte de sortare:
1 2 3 4 5 6 7 8 9 10
32 22 0 1 5 16 99 4 3 50
Tabloul de indici p nainte de sortare:
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Tabloul a dup sortare:
1 2 3 4 5 6 7 8 9 10
32 22 0 1 5 16 99 4 3 50
Tabloul de indici p dup sortare:
1 2 3 4 5 6 7 8 9 10
3 4 9 8 5 6 2 1 10 7
Fig. 3.2.10. Exemplu de sortare indirect
Aceast idee poate fi aplicat practic oricrui algoritm de sortare.
Pentru exemplificare n secvena [3.2.10.a] se prezint un algoritm care realizeaz
sortarea indirect bazat pe metoda inseriei a unui tablou a.
------------------------------------------------------------
VAR a: ARRAY[0..n] OF TipElement;
p: ARRAY[0..n] OF TipIndice;
PROCEDURE InsertieIndirecta;
VAR i,j,v: TipIndice;
BEGIN [3.2.10.a]
FOR i:= 0 TO n DO p[i]:= i;
FOR i:= 2 TO n DO
BEGIN
v:= p[i]; a[0]:= a[i]; j:= i-1;
WHILE a[p[j]].cheie>a[v].cheie DO
BEGIN
p[j+1]:= p[j];
j:= j-1
END;{WHILE}
p[j+1]:= v
END {FOR}
END; {InsertieIndirecta}
------------------------------------------------------------
Dup cum se observ, cu excepia atribuirii fanionului, accesele la tabloul a se
realizeaz numai pentru comparaii.
n multe aplicaii este suficient numai obinerea tabloului p nemaifiind necesar i
permutarea elementelor tabloului. Spre exemplu, n procesul tipririi, elementele pot
fi listate n ordine, referirea la ele realizndu-se simplu, n mod indirect prin tabloul
de indici.
Dac este absolut necesar mutarea, cel mai simplu acest lucru se poate realiza ntr-un
alt tablou b.
Dac acest lucru nu se accept, se poate utiliza procedura de reaezare in situ din
secvena [3.2.10.b].
------------------------------------------------------------
PROCEDURE MutareInSitu;
VAR i,j,k: TipIndice;
t: TipElement;
BEGIN
FOR i:= 1 TO n DO
IF p[i]<>i THEN [3.2.10.b]
BEGIN
t:= a[i]; k:= i;
REPEAT
j:= k; a[j]:= a[p[j]];
k:= p[j]; p[j]:= j;
UNTIL k=i;
a[j]:= t
END {IF}
END; {MutareInSitu}
------------------------------------------------------------
n cazul unor aplicaii particulare, viabilitatea acestei tehnici depinde de lungimea
relativ a cheilor i articolelor.
Desigur ea nu se justific pentru articole mici deoarece necesit o zon de memorie
suplimentar pentru tabloul p i timp suplimentar pentru comparaiile indirecte.
Pentru articole de mari dimensiuni se indic de regul sortarea indirect, fr a se mai
realiza permutarea efectiv a elementelor.
Pentru articolele de foarte mari dimensiuni metoda se indic a se utiliza integral,
inclusiv permutarea elementelor [Se88].
3.3. Sortarea secvenelor. Sortarea extern
Metodele de sortare prezentate n paragraful anterior nu pot fi aplicate unor date care
nu ncap n memoria central a sistemului, dar care pot fi spre exemplu memorate
pe dispozitive periferice secveniale cum ar fi benzile magnetice.
n acest caz datele pot fi descrise cu ajutorul unei structuri de tip secven avnd
drept caracteristic esenial faptul c n fiecare moment este accesibil doar o
singur component.
Aceasta este o restricie foarte sever comparativ cu accesul direct oferit de
structura tablou, motiv pentru care tehnicile de sortare sunt de cu totul alt
natur.
Una dintre cele mai importante tehnici de sortare a secvenelor este sortarea prin
"interclasare" (merging).
3.3.1. Sortarea prin interclasare
Interclasarea presupune combinarea a dou sau mai multe secvene ordonate ntr-o
singur secven ordonat, prin selecii repetate ale componentelor curent accesibile.
Interclasarea este o operaie simpl, utilizat ca auxiliar n procesul mult mai
complex al sortrii secveniale.
O metod de sortare bazat pe interclasare a unei secvene a este urmtoarea:
1. Se mparte secvena de sortat a n dou jumti b i c.
2. Se interclaseaz b cu c, combinnd cte un element din fiecare, n perechi
ordonate obinndu-se o nou secven a.
3. Se repet cu secvena interclasat a, paii 1 i 2 de aceast dat combinnd
perechile ordonate n qvadruple ordonate.
4. Se repet paii iniiali, interclasnd qvadruplele n 8-uple, .a.m.d, de fiecare
dat dublnd lungimea subsecvenelor de interclasare pn la sortarea ntregii
secvene.
Spre exemplu fie secvena:
34 65 12 22 83 18 04 67
Execuia pasului 1 conduce la dou jumti de secven;
34 65 12 22
83 18 04 67
Interclasarea componentelor unice n perechi ordonate conduce la secvena
34 83 | 18 65 | 04 12 | 22 67
njumtind din nou i interclasnd perechile n qvadruple se obine:
04 12 34 83 | 18 22 65 67
Cea de-a treia njumtire i interclasarea celor dou qvadruple ntr-un 8-uplu
conduc la secvena gata sortat:
04 12 18 22 34 65 67 83
Fiecare operaie care trateaz ntregul set de date se numete faz;
Procesul prin repetarea cruia se realizeaz sortarea se numete trecere.
Procesul de sortare anterior descris const din trei treceri fiecare cuprinznd o faz de
njumtire i una de interclasare.
Pentru a realiza sortarea sunt necesare trei secvene motiv pentru care sortarea se
numete interclasare cu trei secvene. Este de fapt o interclasare neechilibrat cu 3
secvene.
3.3.1.1. Interclasarea neechilibrat cu trei secvene
Interclasarea neechilibrat cu trei secvene reprezint implementarea procedeului de
sortare precizat anterior. Schema de principiu a acestui procedeu apare n figura
3.3.1.1.
Fig.
3.3.1.1. Interclasare neechilibrat cu trei secvene
ntr-o prim etap n secvenele [3.3.1.1.a,
b] se prezint structurile de date i schia
de principiu a algoritmului.
Dup cum se observ, fiecare trecere care const dintr-o reluare a buclei REPEAT,
conine dou faze:
O faz de njumtire adic de distribuie a n-uplelor secvenei a pe cele dou
secvene b i c, respectiv
b
c
a
O faz de interclasare n care n-uplele de pe secvenele b i c se interclaseaz
n n-uple de dimensiune dubl pe secvena a.
Variabila p iniializat pe 1, precizeaz dimensiunea n-uplelor curente,
dimensiune care dup fiecare trecere se dubleaz. n consecin numrul total
de treceri va fi log
2
n .
------------------------------------------------------------
TYPE TipElement = RECORD
cheie: TipCheie;
{alte campuri} [3.3.1.1.a]
TipSecventa = FILE OF TipElement;
VAR a,b,c: TipSecventa;
------------------------------------------------------------
{Interclasare neechilibrata cu 3 secvene}
PROCEDURE Interclasare3Secvente;
p:= 1; {dimensiune n-uplu} [3.3.1.1.b]
REPEAT
*injumatatire; {distribuie pe a pe b i c}
*interclasare; {interclaseaz de pe b i c pe a]
p:= 2*p
UNTIL k=1; {k este contorul de n-uple}
------------------------------------------------------------
Variabila k contorizeaz numrul de n-uple create n procesul de interclasare.
Procesul de sortare se ncheie cnd n final rmne un singur n-uplu de dimensiune n
(k=1).
n continuare se procedeaz la rafinarea celor dou faze.
n secvena [3.3.1.1.c] apare primul pas de rafinare al fazei de njumtire, iar n
secvena urmtoare rafinarea enunului scrie
un
n-uplu
de
dimensiune
p
n
secvena
d.
------------------------------------------------------------
PROCEDURE Injumatatire(p: integer);
{distribuie n-uplele de pe a pe b si c}
{p - dimensiune n-uplu}
RESET(a); REWRITE(b); REWRITE(c);
WHILE NOT Eof(a) DO BEGIN [3.3.1.1.c]
*scrie un n-uplu pe b
*scrie un n-uplu pe c
END;
------------------------------------------------------------
PROCEDURE ScrieNuplu(d: TipSecventa);
{scrie un n-uplu de dimensiune p n secvena d}
i:= 0; {contor elemente n-uplu}
WHILE (i<p) AND NOT Eof(a) DO BEGIN
*citeste(a,x); [3.3.1.1.d]
*scrie(d,x)
i:= i+1
END;
------------------------------------------------------------
Variabila i reprezint contorul de elemente care poate lua valori ntre 0 i p. Scrierea
se termin la atingerea numrului p de elemente sau la terminarea secvenei surs.
Rafinarea fazei de interclasare apare n secvena [3.3.1.1.e].
Variabila de intrare p reprezint dimensiunea n-uplelor care se interclaseaz, iar k
este contorul de n-uple.
Practic interclasarea propriu-zis (bucla REPEAT) se ncheie la terminarea prelucrrii
secvenelor b i c.
------------------------------------------------------------
PROCEDURE Interclasare(p: integer; VAR k: integer);
{p - dimensiune n-uplu, k - contor n-uple}
Rewrite(a); Reset(b); Reset(c);
k:= 0; [3.3.1.1.e]
*iniializare interclasare
*citeste n x respectiv n y primul element din b
respectiv din c {tehnica lookahead}
REPEAT
*interclaseaza cte un n-uplu de pe b si c pe a
UNTIL EndPrelucr_b AND EndPrelucr_c
Close(a); Close(b); Close(c);
------------------------------------------------------------
Datorit particularitilor de implementare a fiierelor sunt necesare cteva precizri:
Variabila Eof(f) se poziioneaz pe true la citirea ultimului element al
fiierului f.
Citirea dintr-un fiier cu Eof poziionat pe true conduce la eroare.
Din punctul de vedere al algoritmului de interclasare, terminarea prelucrrii unui
fiier nu coincide cu poziionarea lui Eof pe true, deoarece mai trebuie
prelucrat ultimul element citit.
Pentru rezolvarea acestor constrngeri se utilizeaz tehnica scrutrii (lookahead).
Tehnica scrutrii const n introducerea unei ntrzieri ntre momentul citirii
i momentul prelucrrii unui element.
Astfel n fiecare moment se prelucreaz elementul citit n pasul anterior i
se citete un nou element.
n acest scop pentru fiecare fiier implicat n prelucrare se utilizeaz o
variabil special de TipElement pentru memorarea elementului curent, n
tandem cu o variabil boolean EndPrelucrare a crei valoare true
semnific terminarea prelucrrii ultimului element al fiierului.
Rafinarea enunului interclaseaz
cte
un
n-uplu
de
pe
b
i c
pe
a apare n secvena [3.3.1.1.f ] care aplic tehnica anterior precizat.
Variabilele specifice asociate secvenelor b i c sunt x i y respectiv
EndPrelucr_b i EndPrelucr_c.
------------------------------------------------------------
{interclaseaza cte un n-uplu de pe b si c pe a}
i:= 0; {contor n-uplu b}
j:= 0; {contor n-uplu c}
WHILE (i<p)AND(j<p) AND NOT EndPrelucr_b AND
NOT EndPrelucr_c DO
BEGIN
IF x.cheie<y.cheie THEN BEGIN
*scrie(a,x); i:= i+1;
*citeste(b,x) [3.3.1.1.f]
END
ELSE BEGIN
*scrie(a,y); j:= j+1;
*citeste(c,y)
END
END; {WHILE}
*copiaz restul n-uplului de pe b pe a (dac exist)
*copiaz restul n-uplului de pe c pe a (dac exist)
k:= k+1;
------------------------------------------------------------
O variant de implementare integral a procesului de sortare neechilibrat cu 3 benzi
apare n PROCEDURA Interclasare3Secvente secvena [3.3.1.1.g].
------------------------------------------------------------
PROCEDURE Interclasare3Secvente;
VAR a,b,c: TipSecventa;
p,k: integer;
PROCEDURE Injumatatire(p: Integer);
VAR x: TipElement;
PROCEDURE ScrieNuplu(VAR d: TipBanda);
VAR i: integer;
BEGIN {ScrieNuplu}
i:= 0;
WHILE (i<n) AND (NOT Eof(a)) DO BEGIN
Read(a,x);
Write(d,x); i:= i+1
END; {WHILE}
END; {ScrieNuplu} [3.3.1.1.g]
BEGIN {Injumatatire}
Reset(a); Rewrite(b); Rewrite(c);
WHILE NOT Eof(a) DO BEGIN
ScrieNuplu(b); ScrieNuplu(c);
END; {WHILE}
Close(a); Close(b); Close(c);
END; {Injumatatire}
PROCEDURE Interclasare(p: integer; VAR k: integer);
VAR i,j: integer;
x,y: TipElement;
EndPrelucr_b,EndPrelucr_c: Boolean;
BEGIN {Interclasare}
Reset(b); Reset(c); Rewrite(a); k:= 0;
EndPrelucr_b:= Eof(b); EndPrelucr_c:= Eof(c);
IF NOT EndPrelucr_b THEN Read(b,x); {lookahead}
IF NOT EndPrelucr_c THEN Read(c,y); {lookahead}
REPEAT
i:= 0; j:= 0; {interclasarea unui n-uplu}
WHILE (i<p)AND(j<p) AND NOT EndPrelucr_b AND
NOT EndPrelucr_c DO BEGIN
IF x.cheie < y.cheie THEN
BEGIN
Write(a,x); i:= i+1;
IF Eof(b) THEN EndPrelucr_b:= true
ELSE
Read(b,x)
END
ELSE
BEGIN
Write(a,y); j:= j+1;
IF Eof(c) THEN EndPrelucr_c:= true
ELSE
Read(c,y)
END;
END; {WHILE}
{copiaz restului n-uplului de pe b pe a}
WHILE (i<n) AND NOT EndPrelucr_b DO BEGIN
Write(a,x); i:= i+1;
IF Eof(b) THEN
EndPrelucr_b:= true
ELSE
Read(b,x)
END; {WHILE}
{copiaz restului n-uplului de pe c pe a}
WHILE (j<n) AND NOT EndPrelucr_c DO BEGIN
Write(a,y); j:= j+1;
IF Eof(c) THEN
EndPrelucr_c:= true
ELSE
Read(c,y)
END; {WHILE}
k:= k+1;
UNTIL EndPrelucr_b AND EndPrelucr_c;
Close(a); Close(b); Close(c);
END; {Interclasare}
BEGIN {Interclasare3Secvente}
p:= 1;
REPEAT
Injumatatire(p); {faza (1)}
Interclasare(p,k); {faza (2)}
p:= p*2;
UNTIL k=1;
END; {Interclasare3Secvente}
------------------------------------------------------------
3.3.1.2. Interclasarea echilibrat cu 4 secvene
Faza de njumtire care de fapt nu contribuie direct la sortare (n sensul c ea nu
permut nici un element), consum jumtate din operaiile de copiere.
Acest neajuns poate fi remediat prin combinarea fazei de njumtire cu cea de
interclasare.
Astfel simultan cu interclasarea se realizeaz i redistribuirea n-uplelor
interclasate pe dou secvene care vor constitui sursa trecerii urmtoare.
Acest proces se numete interclasare cu o singur faz sau interclasare echilibrat
cu 4 secvene (2 ci).
Fig.
3.3.1.2.a. Interclasare echilibrat cu patru secvene
ntr-o prim etap, se va prezenta un program de interclasare al unui tablou, care va fi
parcurs strict secvenial.
ntr-o etap ulterioar, interclasarea va fi aplicat unor structuri de tip fiier,
permind compararea celor dou abordri i n acelai timp demonstrnd puternica
dependen a formei programului fa de structurile de date pe care le utilizeaz.
Un tablou poate fi utilizat n locul a dou fiiere, dac este privit ca o secven cu dou
capete.
Astfel n loc de a interclasa dou fiiere surs, elementele se vor lua de la cele
dou capete ale tabloului.
Faza combinat njumtire-interclasare apare reprezentat schematic n
figura 3.3.1.2.b.
Destinaia articolelor interclasate este comutat dup fiecare pereche
ordonat la prima trecere, dup fiecare quadruplu la a doua trecere, .a.m.d,
astfel nct cele dou secvene destinaie, sunt de fapt cele dou capete ale
unui singur tablou.
Dup fiecare trecere cele dou tablouri se interschimb sursa devenind noua
destinaie i reciproc.
SURS DESTINAIE
Fig.
3.3.1.2.b. Model tablou pentru interclasarea echilibrat
n continuare lucrurile se pot simplifica reunind cele dou tablouri conceptuale ntr-
unul singur de lungime dubl:
a:
ARRAY[1..2*n] OF TipElement;
n acest tablou, indicii i i j precizeaz dou elemente surs, iar k i l dou
destinaii.
Secvena iniial va fi coninut de prima parte a tabloului a[1],...,a[n].
i j
k l
Interclasare
njumtire
Se introduce o variabil boolean sus care va preciza sensul micrii elementelor; de
la a[1],...,a[n] spre a[n+1],...,a[2*n] cnd sus este adevrat i n
sens invers cnd sus este fals. n mod evident valoarea lui sus alterneaz de la o
trecere la alta.
Se mai introduce o variabil p care precizeaz lungimea subsecvenelor ce urmeaz s
fie interclasate: valoarea sa iniial 1, se dubleaz dup fiecare trecere.
Pentru a simplifica i mai mult lucrurile se presupune c n este o putere a lui 2.
n aceste condiii, n secvena [3.3.1.2.a] apare varianta pseudocod a procedurii de
interclasare iar n secvena [3.3.1.2.b] primul pas de rafinare.
------------------------------------------------------------
PROCEDURE Interclasare
sus: boolean;
p: integer; [3.3.1.2.a]
sus:= true; p:= 1;
repeta
daca sus atunci
stnga <- sursa; dreapta <- destinaie
altfel
dreapta <- sursa; stnga <- destinatie;
*se interclaseaz secvenele de lungime p de la
dou capete ale sursei, alternativ n cele
dou capete ale destinaiei;
sus:= not sus; p:= 2*p
pn cnd p=n;
--------------------------------------------------------
PROCEDURE Interclasare;
VAR i,j,k,l: indice;
sus: boolean; p: integer;
BEGIN
sus:= true; p:= 1;
REPEAT {initializare indici}
IF sus THEN
BEGIN
i:= 1; j:= n; k:= n+1; l:= 2*n
END
ELSE [3.3.1.2.b]
BEGIN
k:= 1; l:= n; i:= n+1; j:= 2*n
END;
*interclaseaz p-tuplele secv. i-j n secv. k-l
sus:= NOT sus; p:= 2*p
UNTIL p=n
END; {Interclasare}
--------------------------------------------------------
Interclasarea este de fapt o bucl REPEAT pentru p mergnd de la 1 la n.
La fiecare trecere p se dubleaz iar sus comut.
n cadrul unei treceri:
Funcie de variabila sus se asigneaz indicii surs-destinaie
Se interclaseaz p-tuplele secvenelor surs n p-tuple de dimensiune dubl i
se depun n secvena destinaie.
n pasul urmtor al detalierilor succesive se rafineaz, enunul "interclaseaz p-
tuplele
secvenei
i-j
n
secvena
k-l".
Este clar c interclasarea a n elemente este la rndul ei o succesiune de interclasri
paria