100din100

Cautarea binara pentru olimpiada in C++

Publicat la 21 martie 2020 · algoritmi olimpiada clasa 9 cpp


Ce este căutarea binară?

Să zicem că ai un vector a[] cu n elemente crescătoare. Căutarea binară este un algoritm eficient care determină dacă orice număr x apare sau nu în şir (în caz afirmativ putem afla poziția, câte elemente egale cu x sunt etc.).

Aproape în fiecare an, la mai toate clasele, apar probleme cu căutarea binară, atât la OJI, cât şi la ONI[1].

ATENȚIE! Formulele nu trebuie reținute, ci deduse.

Cuprinsul lecției

Deducerea algoritmului de căutare binară

Să luăm următorul enunț ca exemplu:

CERINȚĂ. Se dau următoarele date de intrare: un număr natural n, n numere naturale în ordine crescătoare (a[i] ≤ a[i + 1], pentru orice 1 ≤ i < n) care constituie un vector (a[]), un număr natural q şi q numere naturale. Pentru fiecare dintre cele q numere aflați dacă se află în vectorul a[].
DATELE DE INTRARE au fost descrise anterior.
DATELE DE IEŞIRE. Vor exista q răspunsuri de "DA" sau "NU", pentru fiecare întrebare.


Algoritmul naiv (NERECOMANDAT!)

Parcurgem toate elementele în ordine până când găsim elementele cerute. Dacă am ajuns la i == n şi, cu toate acestea, nu am găsit numărul, atunci acesta nu există în vector. Complexitatea O(q * n). Soluția aceasta nu este bună în cazul în care n şi q sunt foarte mari, de exemplu n = q = 1.000.000, care iese din aproape orice limită de timp.


pentru (i de la 1 la q) {
	citim x;
	bool am_găsit = false;
	pentru(j de la 1 la n) {
		dacă(x este egal cu a[j]) {
			am_găsit = true;
		}
	}
	dacă(am_găsit) afişez "DA";
	altfel afişez "NU";
}
						

Algoritmul de căutare binară

Cheia algoritmului este că şirul este crescător. Asta înseamnă că dacă un număr a[i] < nr de căutat, atunci toate a[j] cu j ≤ i sunt < nr de căutat; invers pentru numerele mai mari.


Cea mai eficientă abordare este să luăm numărul din mijlocul şirului, adică a[n / 2]. Dacă numărul este mai mic decât ce căutăm, atunci din start tăiem primii n / 2 termeni, şi reciproc şi pentru numerele mai mari. Continuăm tot aşa, tăiând jumătate din cât a rămas. Dacă găsim la vreun pas numărul, ne oprim şi afişăm corespunzător. Dacă ajungem la situația în care nu mai putem tăia în jumătate şirul nostru (adică am tot tăiat până când a rămas un singur element), ne oprim şi afişăm că elementul nu este în sir.


Iată o simulare pentru şirul a[] = {7, 7, 11, 20, 85, 98, 99} şi elementul de căutat x = 85:



În loc să facem 5 verificări cu metoda naivă, facem doar 3, aproape jumătate (în cazul acesta).
Iată o simulare pentru acelaşi şir, dar cu x = 19:



Complexitatea soluției este O(log2 n) pentru fiecare căutare — un număr extrem de mic raportat la valori mari ale lui n. Ca idee, dacă n = 1.000.000, log2 n = 19.93(adică se fac 20 de comparații în cel mai rău caz, în loc de 1.000.000).


OK, am înțeles algoritmul. Dar cum "tăiem" şirul? Vom considera doi indici, st şi dr, cu valorile inițiale st = 1 şi dr = n. La fiecare pas, vom realiza căutarea între aceşti indici. Dacă elementul din mijloc, (st + dr) / 2, este mai mare decât ce căutăm noi, atunci eliminăm tot ce este ≤ (st + dr) / 2, adică dr = ((st + dr) / 2) - 1;. La fel şi invers. Iată codul final:


#include <iostream>
#define MAX 100

using namespace std;

int n, a[MAX + 1], q, x;

int main()
{
	//Citire. Ştim clar că numerele şirului//pentru mai multe detalii: https://100din100.netlify.app
	//a[] sunt crescătoare (din enunț)//pentru mai multe detalii: https://100din100.netlify.app
	cin>>n;
	for(int i = 1; i <= n; i++) {
		cin>>a[i];
	}
	cin>>q;
	for(int i = 1; i <= q; i++) {
		cin>>x;
		int st = 1, dr = n;
		int mij; //În loc să tot scriem (st + dr) / 2//pentru mai multe detalii: https://100din100.netlify.app
		//vom calcula valoarea în variabila mij//pentru mai multe detalii: https://100din100.netlify.app
		bool found = false;
		while(found == false && st <= dr) { //condiția că mai putem împărți şirul//pentru mai multe detalii: https://100din100.netlify.app
			mij = (st + dr) / 2;
			if(x == a[mij]) { //am găsit numărul//pentru mai multe detalii: https://100din100.netlify.app
				found = true;
				cout<<"DA ";
			} else if(x < a[mij]) //x se află în stânga mijlocului, eliminăm a doua jumătate//pentru mai multe detalii: https://100din100.netlify.app
				dr = mij - 1;
			else //e implicit că x > a[mij], aşadar eliminăm partea stângă (prima jumătate)//pentru mai multe detalii: https://100din100.netlify.app
				st = mij + 1;
		}
		if(found == false)
			cout<<"NU ";
	}
}
						

Test din căutarea binară

Completează următoarea secvență de cod, fără a adăuga vreun spațiu:

//QUERY este elementul de căutat
int st = 1, dr = n, mij;
bool gasit = false;
while(st <= dr) {
mij = (st + dr) / 2;
if(a[] == QUERY) gasit = true;
...
}
· Vezi răspunsul

//pentru mai multe detalii: https://100din100.netlify.app

Răspunde la următoarea întrebare:

Pentru un şir ordonat crescător a cu n = 210 elemente, în cel mai nefavorabil caz, trebuie făcute comparații.
· Vezi răspunsul

Răspunde la următoarea întrebare:

Complexitatea căutării binare este O( n).
· Vezi răspunsul

Alte resurse

Am găsit următoarele site-uri sau pagini web ca fiind resurse bune pentru căutarea binară:

Căutarea Binară pe Wikipedia
Căutarea Binară pe Tutoriale-Pe.NET
Căutarea Binară pe pbInfo
Căutarea Binară pe Infoarena

Alte articole

Primul tau program, variabile si operatii - TUTORIAL COMPLET C++

Eşti elev de liceu şi nu înțelegi informatica? Acest clip ar trebui să te ajute să înțelegi cele mai elementare aspecte privind informatica de liceu - algoritmica...

Rezolvări probleme PbInfo

Problemele de informatică pot fi dificile uneori, şi este util să vedem o soluție bună pentru a ne autoverifica. De multe ori sunt necesare doar nişte modificări minore, de aceea este bine să analizăm soluțiile bune cu atenție!

Video - Probleme Rezolvate PbInfo

Aici gasiti rezolvarea mai multor probleme de pe site-ul pbinfo.ro, în format video, pe canalul nostru de YouTube.

Tipuri de date in C++ si C - Tutorial Incepatori

De ce avem nevoie de date? În timp ce lucrăm cu valori, avem nevoie (uneori chiar suntem siliți!) să memorăm datele undeva, în memorie. Prin intermediul variabilelor putem accesa o zonă de …

Smenul lui Mars (Difference Arrays) in C++

Ce este Şmenul lui Mars? Să zicem că avem un şir a[] cu n elemente. Unele probleme cer efectuarea unor operații de tipul sum(st, dr, val), cu semnificația că adunăm la …

Cautarea binara pentru olimpiada in C++

Ce este căutarea binară? Să zicem că ai un vector a[] cu n elemente crescătoare. Căutarea binară este un algoritm eficient care determină dacă orice număr x apare sau n…

Al doilea cel mai mic/mare element al unui sir in C++

Dându-se un şir de numere naturale distincte, aflați al doilea cel mai mic număr din şir. Exemplu:Intrare 9 5 8 2 4 Ieşire 4 Explicație4 este al doilea cel mai mi…

Afişare cu 2 zecimale exacte, fără şi cu rotunjire - TUTORIAL C++

Tutorialul acesta te învață cum să afişezi un număr real cu mai multe zecimale exacte. Multe probleme cer...

Algoritmi elementari - video

Tutoriale uşor de urmărit, sub forma unor videoclipuri!

Prelucrarea cifrelor unui numar pentru incepatori in C++

Acest articol urmăreşte aplicarea diferitelor aplicații cu cifrele unui număr: suma cifrelor, numărul de cifre, oglinditul unui număr ş.a.m.d. Puteți găsi multe probleme care cer prelucrarea cif…

Ridicarea la putere in timp logaritmic pentru olimpiada in C++

Un număr de forma b la puterea e nu poate fi calculat precum celelalte operații (adunarea, scăderea, înmulțirea, împărțirea) pur şi simplu. În articolul acesta vom prezenta un mod foarte …

Ce este coada/queue si cum functioneaza? Tutorial clasa a 10-a

Ce este coada? Coada (Queue din engleză) este o structură de date liniară care funcționează prin inserarea elementelor noi la spate şi prin eliminarea elementelor doar prin față. Altfel spu…

Ciurul lui eratostene - generarea numerelor prime - olimpiada C++

Să zicem că vrem să aflăm dacă mai multe numere sunt sau nu prime. Desigur, putem aplica algoritmul de aflare a numărului de divizori pentru toate numerele, doar că dacă avem foarte multe şi sun…

Vectori caracteristici si vectori de frecventa - Materie Olimpiada Informatica C++

Ce este un vector de frecvență sau un vector caracteristic? Vectorii caracteristici rețin dacă un element se află într-un vector sau nu. Similar, vectorii de frecvență rețin numărul de apar…

Verifica daca o data este valida in C++

Dându-se o dată (zi lună an), trebuie verificat dacă data este validă sau nu. Exemplu:Intrare zi = 3, luna = 4, an = 2021 Ieşire DA Pentru a verifica da…

Citirea si Afisarea in fisiere in C++ - Tutorial Incepatori

De ce citirea din fişier? De multe ori este necesară citirea şi afişarea în fişier, unul din motive fiind faptul că nu trebuie să reintroducem datele de intrare de fiecare dată când rulăm p…

Primul program - Operatori si expresii - Tutorial incepatori C++

Alcătuirea unui program pentru rezolvarea unei probleme se rezumă defapt la rezolvarea unor probleme mai mici. Spre exemplu, pentru a afla suma numerelor prime dintr-un şir, trebuie să ştim cum …

Verifica daca un an este bisect in C++

Dându-se un an, trebuie verificat dacă este un an bisect sau nu. Exemplu:Intrare 2021 Ieşire NU Definiția anului bisect Deşi pare evident, anii bis…

Sume partiale. Suma elementelor dintr-o submatrice in C++

Cu ce ne ajută sumele parțiale? Unele probleme cer aflarea sumei elementelor unei secvențe dintr-un şir dat. Metoda naivă, care face suma tuturor elementelor din secvența cerută, deobicei n…

Divizorii unui numar - tutorial incepatori in C++

Prezentul articol te va ajuta să îndeplineşti diferite aplicații cu divizorii unui număr. Trebuie cunoscută parcurgerea divizorilor unui număr, înainte de toate, ca să ne asigurăm că ştim s…

Sortarea vectorilor si a structurilor (pentru incepatori) in C++

Sortarea în informatică reprezintă procesul de a ordona un şir de obiecte (numere, caractere, sau chiar şiruri) după un anumit criteriu. Spre exemplu, putem ordona crescător sau descrescăto…

Tablelul ASCII - clasa a X-a - char C++

Ce este tabelul ASCII? Calculatorul reține numere (valori de 1 şi de 0), aşadar a fost nevoie de o corespondență între numere şi caractere pentru a putea reprezenta litere, si…

Creeaza un joc 2D in PYTHON pentru incepatori - Capitolul 0 (Instalare)

Care-i faza? În aceste câteva tutoriale vom învăța cum să îți creezi propriul joc video în Python. Puteți viziona atât pe YouTube, cât şi în format text pe site-ul nostru (aici adică). …

Parcurgerea matricei in spirala in C++

Cu ce ne ajută parcurgerea matricei pătratice în spirală? În concursuri şi olimpiade apar probleme legate de parcurgerea matricei în spirală. Deşi ideea de bază este destul de uşoară, algor…

Învață să programezi gratis!

Am lansat InfoAs, o platformă de informatică cu sute de probleme, lecții și concursuri, totul gratuit. Încearcă acum!