Documente Academic
Documente Profesional
Documente Cultură
Complexitate
Ludmila NOVAC
Dr., conf. univ.
Dep. Informatică
Problema de căutare, aprecierea complexităţii
algoritmilor de căutare, viteza medie de căutare,
lungimea medie de căutare.
1. Tabele neordonate.
- Algoritmul căutării secvenţiale (metoda secvenţială de căutare).
- Metoda de căutare în Tabele neordonate structurate arborescent.
(căutarea în arborele binar de căutare)
2. Tabele ordonate. Tabele ordonate după cheie.
- Metoda binară de căutare (căutarea binară).
- Căutarea după metoda lui Fibonacci.
- Căutarea prin interpolare.
- Căutarea în Tabele ordonate (hash-tabele).
- Tabele ordonate după frecvenţa de adresare la înregistrări
tabelare.
2. Tabele ordonate.
Tabele ordonate după cheie.
- Metoda binară de căutare (căutarea binară).
- Căutarea după metoda lui Fibonacci.
- Căutarea prin interpolare.
- Căutarea în Tabele ordonate (hash-tabele).
- Tabele ordonate după frecvenţa de adresare
la înregistrări tabelare.
Căutarea binară
Presupunem că lista de elemente este ordonată crescător, K1 < K2 < ... < KN
şi se caută K in listă. Ideea algoritmului de căutare binară este de a testa întâi dacă
elementul K coincide cu elementul din mijloc al listei. Dacă da, se obţine o căutare cu
succes şi algoritmul se termina. În caz contrar, putem avea unul din următoarele cazuri:
Procedeul continuă pană când K este găsit sau până când K se caută într-o listă
vidă, deci K nu este găsit.
b) Căutăm K=21:
Algoritm de căutare binară
(varianta iterativă):
Presupunem K1 < K2 < ... < KN şi se caută cheia K în listă.
Folosim doi indici l, u pentru a preciza limitele între care se caută cheia K.
Iniţial l = 1 şi u = N. Folosim şi variabila de tip boolean gasit care este iniţial
falsă şi devine adevărată atunci când elementul a fost găsit.
Algoritm de căutare binară
(varianta recursivă):
Presupunem K1 < K2 < ... < KN şi se caută cheia K în listă.
Folosim doi indici l, u pentru a preciza limitele între care se caută cheia K.
Iniţial l = 1 şi u = N. Folosim şi variabila de tip boolean gasit care este iniţial
falsă şi devine adevărată atunci când elementul a fost găsit.
Analiza algoritmului:
• Operaţia principală care se efectuează este comparaţia dintre
elementul căutat şi elementele listei. Se observă că de fiecare dată
când se încearcă găsirea elementului se face comparaţia cu
elementul din mijlocul listei, după care, dacă nu este găsit se face
căutarea într-o listă de două ori mai mică.
• Functia CăutareInterpolare(V,n,x)
st ← 0 dr ← n-1 gasit ← fals
dacă ((x<=v[dr]) şi (x>=v[st])) execută
repetă m ← st +(x-v[st])*[(dr-st)/(v[dr]-v[st])]
dacă x ≥ v[m] atunci
st ← m+ 1
altfel dr ← m-1
sfârşit dacă
până când ( (v[m]≠x) şi (st <dr)şi (v[st]=v[dr]) şi (x≥v[st]) şi (x≤v[dr]) )
sfârşit dacă
dacă v[m] =x atunci gasit ← adevarat
sfârşit dacă
sfârşit functie
Căutarea prin interpolare
• Implementare în C++
int CăutareInterpolare(int v[], int n, int x)
{
int st,dr,m;
st=0; dr=n-1;
if ((x<=v[dr]) && (x>=v[st]))
do
{
m=st+(x-v[st])*(dr-st)/(v[dr]-v[st]);
if(x>v[m]) st=m+1;
else dr=m-1;
} while((v[m]!=x) && (st=v[st]) && (x<=v[dr]));
if(v[m]==x) return 1;
else return 0;
}
Căutarea prin interpolare. Exemplu
Cheia este X=23
1) st=0, dr =7,
m=0+(23-1)*(7-0)/(38-1)=22*7/37=4,16 1 4 9 10 15 21 23 38
m=4 0 1 2 3 4 5 6 7
2) st=5, v[st]=21
m=5+(23-21)*(7-5)/(38-21)=5+2*2/17=5,235
1 4 9 10 15 21 23 38
m=5
0 1 2 3 4 5 6 7
3) st=6, v[st]=23
m=6+(23-23)*(7-6)/(38-23)=6+0*(15)=6
m=6 1 4 9 10 15 21 23 38
v[m]=23=Cheia x 0 1 2 3 4 5 6 7
Tabele ordonate
Să vedem cum:
• Elementele sunt puse într-un tablou alocat static pe poziţiile cheilor
lor. Prin adresare directă, un element cu cheia k va fi memorat în
locaţia k. Toate cele 3 operaţii sunt extrem de simple (necesită doar
o accesare de memorie), dar dezavantajul este că această tehnică
"mănâncă" foarte multă memorie: O(|U|), unde U este universul de
chei.
• hash (engl. hash = a toca, a fărâmiţa, tocătură).
• http://www.cs.ubbcluj.ro/~gabitr/Cursul12.pdf
Funcţiile hash
• Funcţiile hash (numite şi funcţii de dispersie sau funcţii de rezumat; din
englezescul hash functions) sunt, în ultimă instanţă, nişte funcţii matematice
destul de oarecare; ele sunt grupate sub umbrela funcţiilor hash mai
degrabă din punct de vedere al scopului urmărit de matematicieni decât din
punct de vedere al formei lor intrinseci.
Dacă este definită funcţia f(k), astfel, ca pentru orice ki, i=0, ..., m-1,
f(ki) are o valoare întreagă între 0 şi n-1, unde f(ki)≠f(kj), i≠j, atunci
înregistrarea tabelară cu cheia K se reflectă bireciproc în elementul T[f(K)].
• La includerea unei noi înregistrări algoritmul rămâne determinat până atunci, când
vectorul, în care se reflectă tabelul, conţine măcar o poziţie liberă.
• Dacă această condiţie nu se îndeplineşte este posibilă ciclarea, împotriva căreia
trebuie de luat măsuri speciale.
De exemplu, se poate introduce un contor de poziţii verificate, dacă acest număr a
devenit mai mare ca n, atunci algoritmul trebuie să fie oprit.
Căutarea înregistrărilor în tabele de repartizare
La căutarea înregistrării cu cheia dată K se foloseşte următorul algoritm:
// c l a s s "h a s h i n g _ e l e m"
class hashing_elem : public usual_elem
{
public:
hashing_elem(){ }
A P –
B Q 11
C R 2
D S 4
E T –
F U 1
G V 2
H W 2
I X 1
J Y –
K Z –
L 1
M –
N 1
O
D_medie=(1+1+2+4+1+2+2+1+1+1)/10 =16/10=1,6
Analiza coliziunilor
A P – 2
B Q 11 2
C R – 2
D S – –
E T – –
F U 11 –
G V – –
H W 1 –
I X – –
J Y – –
K Z 1 –
L – –
M 1 –
N –
O –
Tabele de repartizare cu înlănţuirea internă
Încărcarea poziţiilor vectorului de reflectare constă din două etape:
• prima etapă se aseamănă cu repartizarea prin înlănţuirea externă;
• a doua etapă se îndeplineşte după terminarea creării tabelului primar şi
celui secundar. Ea constă în mutarea lanţurilor din tabelul secundar în
poziţiile libere ale tabelului primar.
Astfel tabelele din exemplul precedent vor fi transformate în următorul tabel.
A P 2
B Q 1
C R 1
D S 2
E T 2
F U –
G V 1
H W 1
I X –
J Y 1
K Z –
L –
M 1
N –
O 1
Metode de rezolvare a coliziunilor
• Înlănţuire
• Liste statice
• Adresare deschisă
• Double hashing-ul lui Mihai Pătraşcu
Înlănţuire
• În fiecare poziţie din tabel ţinem o listă înlănţuită; insert, delete şi search
parcurg toată lista.
Pe un caz pur teoretic, toate cele N elemente ar putea fi repartizate în aceeaşi
locaţie, însă pe cazuri practice lungimea medie a celui mai lung lanţ este de
lg(N).
• Varianta: în loc de listă, de utilizat arbori.
Liste statice
• Varianta îmbunătăţită a metodei anterioare:
http://www.cs.ubbcluj.ro/~gabitr/Cursul12.pdf
Metode de transformare a cheilor:
• Variabilele de tip string pot fi transformate în numere în baza
256 prin înlocuirea fiecărui caracter cu codul său ASCII.
Motivul?
Exemplul 1
Presupunem că avem o tabelă cu 32 poziţii şi cheia
A K E Y = 00001 01011 00101 11001 (Cod pe 5 bits)=(44217)10 ≡80 (mod 101)
Baza 32 (semne) =>
AKEY=
Exemplul 2:
• Din aceleaşi motive, alegerea unei valori ca 1000 sau 2000 nu este prea
inspirată, deoarece ţine cont numai de ultimele 3-4 cifre ale reprezentării
zecimale.
Funcţii de dispersie foarte des folosite
2. Metoda înmulţirii
Funcţia hash este h(x) = [M * {x*A}] 0 < A < 1, iar prin {x*A}
se înţelege partea fracţionară a lui (x*A), adică (x*A - [x*A]).
• Exemplu:
dacă alegem M = 1234 şi A = 0.3, iar x = 1997, atunci avem
h(x) = [1234 * {599.1}] = [1234 * 0.1] = 123. Se observă că funcţia h
produce numere între 0 şi M-1.
Într-adevăr 0 ≤ {x*A} < 1 0 ≤ M * {x*A} < M. (Catalin Francu)
Observaţie: valoarea lui M nu mai are o mare importanţă.
M poate fi cât de mare ne convine, eventual o putere a lui 2.
În practică, s-a observat că dispersia este mai bună pentru unele valori ale
lui A şi mai proastă pentru altele;
• Donald Knuth propune valoarea
• Dacă funcţia aleasă are comportament cât mai apropiat de o
generare de numere aleatoare, elementele vor fi
"împrăştiate" în tabel în mod uniform. Pentru fiecare input,
fiecare ieşire ar trebui să fie într-un anumit sens, la fel de
probabilă. Ideal ar fi ca fiecare element să fie stocat singur în
locaţia lui. Acest lucru însă nu este posibil, pentru că N < |U|
şi, deci, de multe ori mai multe elemente vor fi repartizate în
aceeaşi locaţie.
• Acest fenomen se numeşte coliziune.