Sunteți pe pagina 1din 9

CN Onisifor Ghibu Oradea Cercul de Informatică

Căutarea binară

1. Prezentare generală
Căutarea binară (Binary Search) este un algoritm care caută poziţia unei valori într-o colecţie de date, sau
vector, sortată. La fiecare pas, algoritmul compară valoarea căutată cu valoarea din mijlocul vectorului. Dacă se potrivesc
atunci indicele sau poziţia valorii în vector este returnată. În caz contrar se caută în subvectorul din stânga valorii din
mijloc, dacă valoarea căutată este mai mică decât cea din mijloc, sau în subvectorul din dreapta, dacă este mai mare.
Algoritmul repetă aceiaşi paşi pentru fiecare subvector. Dacă nu se găseşte valoarea se va returna valoarea -1.
Complexitatea algoritmului este \(O(\log{n})\) (logaritmic) deoarece la fiecare pas vectorul este înjumătăţit.
Fie vectorul de mai jos. Să presupunem că dorim să verificăm dacă valoarea x = 31 se găsește în vector.

Pentru început căutarea are loc în întreg vectorul, prin urmare marginea din stânga va fi low = 0, iar marginea din
dreapta high = n – 1.
Determinăm poziția elementului din mijloc folosind formula:
mid = low + (high - low) / 2
În acest caz, mid = 0 + (9 – 0) / 2 = 4 . Elementul din mijloc e pe poziția 4.

Vom compara valoarea de pe poziția 4, cu valoarea căutată x = 31. Valorile NU sunt egale. Deoarece valoarea căutată
este mai mare decât valoarea de pe poziția mid, iar vectorul este sortat, tragem concluzia că valoarea căutată va fi în
subvectorul din dreapta.

Modificăm marginea din stînga și căutăm noul element din mijlocul subvectorului.
low = m id + 1
mid = low + (high - low) / 2
Mijlocul e pe poziția 7. Vom compara valoarea de pe poziția 7, cu valoarea căutată x = 31

1
CN Onisifor Ghibu Oradea Cercul de Informatică
Valoarea stocată la poziția 7 nu este o potrivire, ci este mai mică decât ceea ce căutăm. Asa că, valoarea trebuie să fie în
partea stângă. Mutăm marginea din dreapta

Calculăm din nou mijlocul. Poziția este 5 + (6 – 5) / 2 = 5.

Comparăm valoarea căutată cu valoarea elementului din mijloc. Valorile sunt egale, am găsit soluția 5.

// *** Binary Search iterativ*** //


// *** Binary Search recursiv*** //
int cauta(int low, int high, int x) {
// high (dreapta) - limita superioara
while(low <= high) {
// low (stanga) - limita inferioara
int cauta(int low, int high, int x) { // mai exista elemente
if(low > high) return -1; int mid = low + (high - low) / 2;

// Nu s-a gasit nicio valoare // Elementul din mijloc


int mid = low + (high - low) / 2; if(x < v[mid]) high = mid-1;
// Elementul din mijloc // Cauta in stanga
if(x<v[mid]) return cauta(s, mid-1, x);
else if(x>v[mid])low = mid + 1;
// Cauta in subvectorul din stanga
// Cauta in dreapta
else if(x > v[mid])
else return m; // Gasit!
return cauta(mid+1, high, x);
// Cauta in subvectorul din dreapta }
else return mid; // Gasit! return -1; //nu exista element
} }

2. Căutarea binară pe funcții monotone


Căutarea binară este mult mai mult decât o simplă modalitate de a găsi elemente într-un tablou sortat. O secvență
sau un tablou este într-adevăr doar o funcție care asociază valori cu indicii dintr-un tablou. Cu toate acestea, nu există
niciun motiv să restricționăm utilizarea căutarii binare doar secvențe. De fapt, putem folosi același algoritm de căutare

2
CN Onisifor Ghibu Oradea Cercul de Informatică
binară pe orice funcție monotonă al cărui domeniu este setul de numere întregi. Singura diferență este că vom folosi
valorea funcțiilor în loc de valorile din vector. Vom găsi x pentru care f (x) este egală cu o anumită valoare țintă.
Se poate aplica metoda în problemele în care pentru o întrebare răspunsul este da sau nu. Dacă pentru o soluție
potențială x răspunsul la o întrebare este da și pentru orice element după x răspunsul este de asemenea da, iar pentru
orice element înainte de x răspunsul este nu se poate aplica căutarea pentru determinarea valorii lui x . În consecință,
dacă ați pune întrebarea pentru fiecare element din spațiul de căutare (în ordine), veți primi o serie de răspunsuri
nu, urmată de o serie de răspunsuri da se poate aplica căutarea binară pentru determinarea valorii unde are loc
schimbarea monotoniei.
x 1 2 3 ... x - 1 x x + 1 x + 2 max - 1 max
f(x) Nu Nu Nu Nu Nu Da Da Da Da Da

Se poate observa cu ușurință că Da și Nu pot schimba locuri în descrierea de mai sus, ceea ce înseamnă că putem
avea o serie de da urmată de nu. În acest caz, da pentru orice x va însemna că vom primi da pentru toate elementele
înainte de x și nu pentru elementele după x.
x 1 2 3 ... x - 1 x x + 1 x + 2 max - 1 max

f(x) Da Da Da Da Da Da Nu Nu Nu Nu

În primul caz determinăm valoarea minimă x pentru care răspunsul la întrebare este DA (lower_bound), iar în
al doilea caz determină valoarea maximă pentru x pentru care răspunsul la întrebare este DA (upper_bound).
//lower bound
low  min//valoarea minima
high  max // valoarea maxima
cat timp low ≤ high executa //cat timp exista valori
mid  low + (high - low) / 2//mijloc
daca f(mid) = DA atunci //daca pentru mid raspunsul e DA
daca f(mid–1)= NU sau mid = low atunci//daca pentru mid–1 raspunsul e NU
return mid //am gasit elementul cautat
altfel
high  mid – 1//raspunsul e DA dar nu e cel mai mic element
sf. daca
altfel //daca raspunsul e NU
low  mid + 1
sf. daca
sf. cat timp

//upper bound
low  min//valoarea minima
high  max // valoarea maxima
cat timp low ≤ high executa //cat timp exista valori
mid  low + (high - low) / 2//mijloc

3
CN Onisifor Ghibu Oradea Cercul de Informatică
daca f(mid) = DA atunci //daca pentru mid raspunsul e DA
daca f(mid+1)= NU sau mid = high atunci//daca pentru mid+1 raspunsul e NU
return mid //am gasit elementul cautat
altfel
low  mid + 1//raspunsul e DA dar nu e cel mai mare element
sf. daca
altfel //daca raspunsul e NU
high  mid - 1
sf. daca
sf. cat timp

Pentru o mai bună înțelegere să considerăm următoarele exemple:


radical - https://www.pbinfo.ro/?pagina=probleme&id=1282

Se dă un număr. Să se afișeze partea întreagă a rădăcinii pătrate (EX n = 20 se afiseaza 4, n = 25 se afiseaza 5).

Solutie: Să definim funcția F(x) astfel F(x) = {

Se observă că dacă F(x)=0, atunci F(y) = 0 oricare ar fi y>x. Astfel, monotonia e îndeplinită pentru a
aplica căutarea binară (întrebarea la care putem răspunde cu da sau nu ar fi este x * x ≤ n?).
x 1 2 3 ... x - 1 x x + 1 x + 2 max - 1 max

F(x)- este x*x ≤ n? Da Da Da Da Da Da Nu Nu Nu Nu

Putem aplica algoritmul pentru determinarea celei mai mari valori pentru care răspunsul e Da(upper_bound)
bool F(int x){
return x * x <= n;
}
int radical(int n){
int l = 1, r = n;//valorile pt √ pot fi intre 1 si n
while(l <=r){
int m = l + (r - l) / 2;//mijloc
if(F(m)){//daca pentru m raspunsul este da
if(m == r or F(m + 1) == false) return m;
//daca pentru m + 1 raspunsul e NU sau nu avem m + 1  m = solutie
else l = m + 1;//caut o valoare mai mare care indeplineste conditia
}
else r = m - 1; //caut o valoare mai mica }
}

Spuneam că răspunsurile Da și Nu își pot schimba locurile. Dacă definim funcția F(x) = {

Întrebarea la care putem răspunde cu Da sau nu ar fi “Este x * x ≥ n?” . În acest caz, răspunsurile Da și Nu își
schimbă locurile.

4
CN Onisifor Ghibu Oradea Cercul de Informatică
x 1 2 3 ... x - 1 x x + 1 ... max - 1 max
F(x)-este x*x≥n Nu Nu Nu Nu Nu Da Da Da Da Da

Va trebui determinate cea mai mica valoare pentru care răspunsul este Da.
bool F(int x){
return x * x >= n;
}
int radical(int n){
int l = 1, r = n;
while(l < r){
int m = l + (r - l) / 2;
if(F(m) == true) r = m - 1;
else l = m + 1;
}
return l;
}

Fabrica1 - https://www.pbinfo.ro/?pagina=probleme&id=536

La secția de împachetare a produselor dintr-o fabrică lucrează n muncitori. Fiecare muncitor împachetează același tip de
produs, și pentru fiecare se cunoaște timpul necesar pentru împachetarea unui obiect. Să se determine durata minimă de
timp în care vor împacheta cei n muncitori cel puțin M obiecte.
Date de intrare: Programul citește de la tastatură numerele n și M, iar apoi n numere naturale nenule, reprezentând
timpul necesar fiecărui muncitor pentru împachetarea unui obiect.
Date de ieșire: Programul va afișa pe ecran numărul T, reprezentând numărul de unități de timp necesare pentru
împachetarea celor M obiecte.
Restricții și precizări
 1 ≤ n ≤ 1000
 cele n numere citite vor fi mai mici decât 1000
 1 ≤ M ≤ 1.000.000
 toate intervalele de timp sunt exprimate în aceeași unitate de măsură
Exemplu
Intrare Ieșire
6 60 30
473671
Soluție: Fie funcția F(x) = {

5
CN Onisifor Ghibu Oradea Cercul de Informatică
Evident dacă x secunde sunt suficiente pentru împachetarea a M obiecte, atunci și x + 1, x + 2 ... unități de timp
vor fi suficiente. Putem aplica căutarea binară, iar întrebarea la care se poate răspunde cu Da sau Nu e “Sunt
suficiente x secunde pentru a împacheta M obiecte?”
x 1 2 3 ... x - 1 x x + 1 ... max - 1 max
Da
F(x)-sunt suficiente x (aceasta
secunde pentru M Nu Nu Nu Nu Nu valoare Da Da Da Da
obiecte? va fi
soluția)

int cauta(){
int l = 1, r = 20000000;
while(l < r){
int mid = l + (r - l) / 2;
if(F(mid) == true) {
if(mid == l or F(mid - 1) == false) return mid;
else r = mid - 1;
}
else l = mid + 1;
}
}

Funcția F() va returna true dacă mid secunde sunt suficiente pentru împachetarea celor M obiecte și false în caz
contrar. Dar care va fi definiția funcției? Știm că ai reprezintă timpul necesar împachetării unui obiect de către muncitorul
i. În mid secunde acesta va împacheta mid / ai obiecte. În acest timp cei n muncitori vor împacheta ∑

bool F(int x){


int s = 0;
for(int i = 1; i <= n; i++) s = s + x / a[i];
return s >= m;
}

rover(OJI 2017) - https://www.pbinfo.ro/?pagina=probleme&id=1998

Soluție

Date și structuri de date folosite: A[i,j] – stabilitatea terenului în punctul (i, j)

6
CN Onisifor Ghibu Oradea Cercul de Informatică
g[i,j] – numărul minim de zone periculoase pentru a se deplasa din (1, 1)  (i, j), dacă roverul are grutatea G.
dx[], dy[] – vectori pentru deplasare sus – jos, respective stânga - dreapta
c – coadă pt a reține pozițiile în care am ajuns

cerința a)
Aplicăm un algoritm de tip lee pentru a determina numărul minim de zone periculoase pentru a se deplasa din (1, 1)  (n,
n), dacă roverul are greutatea citită G.
- Inițializăm g[i,j] cu INF
- Nu are rost să bordăm a[i,j]. O valoare a[i,j] = INF va fi considerată o zonă foarte stabilă, iar o zonă a[i,j] = -INF
va fi considerată instabilă și va fi luată în calcul la stabilirea numărului zonelor instabile de pe traseu. Așa că
înainte să ne deplasăm într-o zonă (x, y) verificăm dacă aceasta se găsește pe suprafața cercetată.
- Atunci cînd ne deplasăm într-o zonă nesigură aceasta va fi adăugată la sfârșitul cozii, iar când ne deplasăm într-o
zonă sigură aceasta va si adugată la începutul cozii.
- imediat cum valoarea g[n,n] s-a modificat oprim algoritmul.
- solutia va fi valoarea din g[n,n]

subalgoritm lee (G – parametru reprezentând greutatea roverului)


pentru i  1, n executa
pentru j  1, n executa
g[i,j]  INF //initializam cu o valoare foarte mare
sf. pentru
sf. pentru

c.adauga(1, 1)//inseram in coada punctul de plecare


daca a[1,1] < G atunci
g[1,1]  1 //daca punctul de plecare e o zona nesigura o numaram
altfel
g[1,1]  0
sf. daca

cat timp coada nu este vida executa


(x, y)  coordonatele elementului de la inceputul cozii
elimina din coada (x, y)
pentru cele 4 directii de deplasare posibile executa
xx  x + dx[i] //linia pe care ajugem
yy  y + dy[i]//coloana pe care ajungem

daca (xx, yy) se gaseste in interiorul suprafetei atunci


nesig  0
daca a[xx, yy] < G atunci//daca noua pozitie e nesigura
nesig  1 //adaugam o noua suprafata nesigura la solutie
sf. daca
7
CN Onisifor Ghibu Oradea Cercul de Informatică
//daca (x,y) -> (xx, yy) e mai eficient decat cel de pana atunci
daca g[xx, yy] > g[x,y] + nesig atunci
g[xx, yy]  g[x,y] + nesig//actualizam traseul
daca nesig = 0 atunci
insereaza (xx, yy) la inceputul cozii
altfel
insereaza (xx, yy) la sfarsitul cozii
sf. daca
daca g[n,n] ≠ INF atunci
returneaza g[n,n]
sf. daca
sf. daca
sf. daca
sf. pentru
sf. cat timp
returneaza g[n,n]
sf. subalgoritm

cerința b)

Să definim funcția F(x) astfel F(x) = {

Se observă că dacă F(x)=0, atunci F(y) = 0 oricare ar fi y>x, iar daca F(x)=1, atunci F(y) = 1
oricare ar fi y < x Astfel, monotonia e îndeplinită pentru a aplica căutarea binară (întrebarea la care putem
răspunde cu da sau nu ar fi este x greutatea cu care sa traversam 0 zone nesigure?).
x 1 2 3 ... x - 1 x x + 1 x + 2 max - 1 max
Da
F(x)- este x
greutatea a.i sa (sol Nu Nu Nu Nu
Da Da Da Da Da
traversam 0 zone utie
nesigure? !)

subalgoritm cautare_binara
l  1, r  10000
cat timp l ≤ r executa
mid  l + (r - l) / 2;
daca lee(mid) = 0 atunci//daca cu greautatea mid traversam in siguranta
daca lee(mid + 1) > 0 sau mid = r atunci
return mid // solutie
altfel
8
CN Onisifor Ghibu Oradea Cercul de Informatică
l  mid + 1
sf. daca
altfel
r  mid - 1;
sf. daca
sf. cat timp
sf. subalgoritm

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