Contact și feedback

Nu obții 100 de puncte sau ai nelămuriri în privința problemelor? Scrie-mi pe Instagram.


Ai găsit o greșeală, vrei să raportezi un utilizator sau vrei să comunici altceva? Folosește formularul de contact.


Vrei să ne transmiți o părere despre platformă? Folosește formularul de feedback.

Shortcuturi

Folosește următoarele shortcuturi pentru a naviga mai ușor pe platformă.

Generale

Meniu shortcuturi?
Căutare probleme sau utilizatori/
Navigare printre rezultatele căutării↑, ↓
Meniu de contact și feedbackCTRL + Shift + F
Ieșire din meniuriEsc

Editor probleme

Setări editorCTRL + Shift + S
Schimbare stil editorCTRL + Shift + E
Șabloane de codCTRL + Shift + 1/2/3
Golire editorCTRL + Shift + 4

Căutare binară în C++

În multe situații avem un șir de elemente (cum ar fi numere naturale) și suntem nevoiți să verificăm dacă o anumită valoare se găsește sau nu în șir (și eventual să găsim și poziția pe care se află).

Un algoritm clasic parcurge elementele de la început la final și compară valoarea de căutat cu fiecare element în parte, pe rând. Acesta este un algoritm brut și ineficient, în special pentru un număr mare de elemente, complexitatea sa fiind O(n).

Pentru un șir de valori ordonate crescător, putem să ne folosim de un algoritm de căutare binară, care reușește să răspundă la întrebarea propusă în doar O(log2 n), un timp mult mai bun.

Valoarea lui n Număr maxim de pași folosind căutarea normală (secvențială) Număr maxim de pași folosind căutarea binară
10 10 4 (60% mai rapid)
100 100 7 (93% mai rapid)
1.000.000 1.000.000 20 (99.998% mai rapid)

Cum funcționează algoritmul căutarea binară?

Algoritmul de căutare binară ia șirul (să îl numim a, cu elementele pe pozițiile de la 1 la n) cu valori ordonate (de obicei crescător) și valoarea căutată, x. Începe prin a compara elementul din mijlocul șirului lui a cu x. Există trei situații posibile:

  1. Valoarea din mijloc, a[mij], este chiar egală cu x. În acest caz ne oprim și marcăm că am găsit elementul;
  2. Valoarea din mijloc, a[mij], este mai mică decât x. Atunci, deoarece șirul este sortat crescător, nu are rost să mai verificăm elementele din stânga lui a[mij] (cu pozițiile de la 1 la mij - 1), căci categoric x este mai mare decât toate acestea. Așadar considerăm doar elementele șirului de pe pozițiile mij + 1 până la n și repetăm algoritmul pe această jumătate, luând mijlocul acestei secvențe;
  3. Valoarea din mijloc, a[mij], este mai mare decât x. Atunci, similar ca la al doilea caz, nu are rost să verificăm elementele din dreapta lui a[mij], așadar am redus șirul la jumătate.

Dacă, la final, am ajuns pe o poziție a cărei valoare diferă de x, atunci x cu siguranță nu se găsește în șir.

Vedem că algoritmul acesta este mult mai eficient, întrucât la fiecare pas împărțim șirul în două, reducând semnificativ numărul de elemente de comparat.

Exemplu vizual: căutare binară

Să luăm următorul șir, unde căutăm valoarea x = 35.

i 1 2 3 4 5 6 7
a[i] 10 23 35 37 54 67 84

Luăm poziția din mijloc: (1 + 7) / 2 = 4. Comparăm valoarea sa, 37, cu x = 35. Vedem că este mai mare, așadar nu ne mai interesează elementele din dreapta acestui element (le marcăm cu roșu).

i 1 2 3 4 5 6 7
a[i] 10 23 35 37 54 67 84

Din partea rămasă a șirului (elementele de pe pozițiile de la 1 la 3), luăm mijlocul, (1 + 3) / 2 = 2. Cum 23 este mai mic decât 35, tăiem elementele de pe pozițiile 1 și 2.

i 1 2 3 4 5 6 7
a[i] 10 23 35 37 54 67 84

Am rămas cu elementul de pe poziția 3, adică 35. Vedem că este chiar egal cu x, așadar ne oprim și spunem că am găsit elementul.

i 1 2 3 4 5 6 7
a[i] 10 23 35 37 54 67 84

În loc să facem un maxim de 7 pași (în cel mai rău caz, folosind căutarea secvențială), am făcut doar 3.

Implementarea căutării binare în cod

Cea mai simplă metodă de a implementa căutarea binară este să ne folosim de doi indici suplimentari, st și dr, care să ne spună în ce interval ne aflăm într-un anumit moment. La început, st = 1 și dr = n, însă modificăm aceste valori pe parcurs cu cât tăiem din valori.

Calcularea poziției de mijloc este foarte ușoară: tot ce trebuie să facem este să calculăm media aritmetică a celor două poziții: mij = (st + dr) / 2.

Căutarea binară în C++

#include <iostream>

using namespace std;

int main()
{
    //Declarăm și citim valorile în ordinea: lungimea șirului, șirul și valoarea căutată
    int a[100], n, x;
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    cin >> x;

    int st = 1, dr = n;
    int gasit = -1; //Poziția pe care se află x, respectiv -1 dacă nu se găsește
    while(st <= dr) { //Cât timp avem un interval valid
        int mij = (st + dr) / 2;
        if(a[mij] == x) {
            gasit = mij;
            break;
        } else if(a[mij] < x) {
            st = mij + 1;
        } else {
            dr = mij - 1;
        }
    }

    if(gasit == -1) {
        cout << "Nu am gasit valoarea " << x << " in sir!";
    } else {
        cout << "Valoarea " << x << " se gaseste in sir pe pozitia " << gasit << "!";
    }
    return 0;
}

În această lecție puteți urmări o rezolvare recursivă, pentru clasa a X-a.

Problemă rezolvată

Căutare binară a mai multor valori

Dându-se un șir a cu n numere naturale, ordonate crescător, să se verifice dacă alte m valori se găsesc sau nu în șir. Încarcă soluția ta aici.

Exemplu: Pentru n = 6, șirul a = (2, 4, 7, 8, 8, 9), și cele m = 5 valori: 1, 2, 8, 10, 9, se afișează 0 1 1 0 1.

Rezolvare: Pentru fiecare dintre cele m numere, căutăm binar și afișăm 0 sau 1, în funcție de verdict.

#include <iostream>

using namespace std;

int n, a[100001], m, x;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    cin >> m;
    for(int i = 1; i <= m; i++) {
        cin >> x;
        int gasit = 0, st = 1, dr = n;
        while(st <= dr) {
            int mij = (st + dr) / 2;
            if(a[mij] == x) {
                gasit = 1;
                break;
            } else if(a[mij] < x) {
                st = mij + 1;
            } else {
                dr = mij - 1;
            }
        }
        cout << gasit << " ";
    }
    return 0;
}

Exerciții propuse

Completează următoarele secvențe de cod:

Să se caute binar valoarea q în șirul a:

int st = 1, dr = n;
int gasit = -1;
while(!(st ??? dr)) {
    int mij = (st + dr) / 2;

    if(a[mij] == q) gasit = mij;
    else if(a[mij] < q) st = mij + 1;
    else dr = mij - 1;
}

Să se caute binar valoarea x în șirul a, cu elementele în ordine descrescătoare:

int st = 1, dr = n;
int gasit = -1;
while(st <= dr) {
    int mij = (st + dr) / 2;

    if(a[mij] == x) gasit = mij;
    else if(a[mij] ??? x) st = mij + 1;
    else dr = mij - 1;
}

Probleme propuse

# Problemă Dificultate
120. Cautare binara Ușoară (2 )
759. Salata de boeuf Grea (8 )
714. Buldo Grea (8 )
121. Cate numere in interval Medie (4 )
125. Comenzi Medie (4 )

Căutare binară pentru olimpiadă

Atenție la indici

Dacă valorile pentru st și dr sunt valori mari și există riscul de a ieși din tipul de date int atunci când calculăm valoarea de mijloc (întrucât facem suma valorilor st și dr), o alternativă este: mij = st + (dr - st) / 2.

Tip de problemă comună

Pentru olimpiade și concursuri, un tip de problemă care apare des cere găsirea unei valori minime/maxime pentru care o anumită proprietate este respectată: de pildă, problema Buldo de la OJI 2020, clasa a IX-a.

Aici, putem să luăm ca arie de valori pentru H ce trebuie calculat toate numerele de la 1 până la 1.000.000.000. Cum după o anumită valoare proprietatea nu se mai respectă, putem să căutăm binar cea mai mare valoare H pentru care proprietatea este respectată.

Pe aceeași idee există multe alte probleme date la concursuri și olimpiade (chiar și naționale).

Funcții din STL

Există câteva funcții care implementează deja algoritmul de căutare binară. Acestea se găsesc în biblioteca <algorithm> și pot returna următoarele:

#include <algorithm>
...
binary_search(a + 1, a + n + 1, x); //true, dacă x se găsește în a, respectiv false în caz contrar
lower_bound(a + 1, a + n + 1, x); //Pointer către cea mai din stânga poziție din a, egală cu x
upper_bound(a + 1, a + n + 1, x); //Pointer către cea mai din dreapta poziție din a, egală cu x

Bibliografie sau alte resurse

Cuprinsul lecției

Se încarcă…

Citește și

Codul ASCII (tabel complet)Al N-lea termen Fibonacci în C++Tutorial instalare CodeBlocks (ușor) - Introducere în informatică C++Distanța dintre două puncte în C++Instrucțiunea de decizie în C++: if, else, switch, caseCombinatorică în C++: permutări, aranjamente, combinări și alteleCel mai mic/mare divizor prim al numerelor de la 1 la N (Folosind ciurul lui Eratostene)CMMDC recursiv a două numere naturale în C++De ce cer unele probleme răspunsul modulo 666013 sau modulo 1.000.000.007?Maximul și minimul unui vector în C++Materia pentru olimpiada de informatică - tot ce trebuie să știiȘiruri de caractere în C++. Tot ce trebuie să știiȘirul lui Fibonacci în C++Sortare crescătoare recursivă în C++ - Merge sort și Bubble sortCum să citești și să afișezi în fișiere în C++Suma numerelor naturale dintr-un interval dat în C++Verifică dacă trei puncte sunt coliniare C++Verificarea unui an bisect în C++Numărul de divizori al numerelor de la 1 la N (Folosind ciurul lui Eratostene)Cifra maximă și minimă a unui număr în C++Complexitatea unui algoritm (timp și spațiu) în C++Tipuri de date în C++: numere întregi, reale, caractere și alteleNumere triunghiulare. Verificarea unui număr triunghiularInversarea unui șir de caractere în C++Instrucțiunea break (structuri repetitive)Câte numere naturale sunt într-un interval dat? (C++)Oglinditul unui număr în C++Căutare binară în C++Numărul de divizori al unui număr în C++Maximul și minimul a două valori în C++Comentarii în C++Cifra de control a unui numărNumărul permutărilor în C++ (formula permutărilor)Radicalul unui număr în C++ (rădăcina pătrată)Cel mai mare divizor comun (CMMDC) a două numere în C++Divide et Impera (metodă de programare C++)Interschimbarea a două variabile în C++ (3 metode)Mediana unui șir de valori în C++Oglinditul recursiv al unui număr în C++Verifică dacă o literă este mică sau mare în C++Funcții predefinite în C++ (matematice, șiruri de caractere)Structuri repetitive (while, do while, for, etc)Suma 1 + 2 + 3 + ... + N în C++Cel mai puțin semnificativ bit în C++Al N-lea termen dintr-o progresie aritmeticăInterclasarea a doi vectori în C++Află secolul unui an citit de la tastatură în C++Ciurul lui Eratostene în C++Verifică dacă un caracter este literă în C++Al N-lea termen dintr-o progresie geometricăVerificare dacă un număr este palindrom în C++Prima cifră a unui număr în C++Vectorii în C++: declarare și parcurgereRidicarea la putere în timp logaritmic în C++. Exponențiere rapidăIndicatorul lui Euler al numerelor de la 1 la N (Folosind ciurul lui Eratostene)Maximul și minimul a n valori în C++Suma divizorilor numerelor de la 1 la N (Folosind ciurul lui Eratostene)Maximul și minimul a trei valori în C++Cum să afișezi partea întreagă a unui număr real în C++Ce este o variabilă unsigned în C++?Numărul de cifre ale factorialului unui numărCel mai semnificativ bit în C++Copiuțe: Cifrele unui numărAplicații cu ciurul lui Eratostene în C++: suma divizorilor, numărul divizorilorIndicatorul lui Euler în C++Citirea și afișarea matricelor în C++Citește un șir de caractere cu spații în C++Valoarea absolută (modulul) unui număr în C++Numărul minim de peroane pentru o gară în C++Cea mai lungă secvență de elemente crescătoare în C++Cel mai mic număr cu suma cifrelor N în C++Transformarea unui număr din baza 2 în baza 10 în C++Matrice Fibonacci - al n-lea termen Fibonacci în timp logaritmicVectorii în C++: citire și afișareRecursivitate în C++Aria și circumferința unui cerc în C++Transformarea unei litere mici în literă mare în C++Algoritm recursiv pentru căutare binară (clasa a X-a)Numărul de divizori primi ai unui număr în C++Operații cu numere mari în C++ - Toate funcțiile explicateCifra maximă a unui număr recursiv în C++Suma divizorilor unui număr în C++Bordarea unei matrice în C++Afișarea divizorilor primi ai unui număr în C++Rădăcina cubică a unui număr în C++ (cube root)Instrucțiunea for (structuri repetitive)Verifică dacă un bit de pe o anumită poziție este 1 sau 0 în C++Verifică dacă un număr este par sau impar fără modulo în C++Generarea șirului Fibonacci generalizat în C++Instrucțiunea do while (structuri repetitive)Do while vs while în C++ - Care e diferența?Tipul struct în C++. Ce sunt structurile de date neomogenePointer în C++. Variabile de tipul char * (char steluță)Aflarea sumei primelor N sume GaussCifrele unui număr. Prelucrarea cifrelor unui număr în C++Afișarea elementelor unui vector recursiv în C++Ce înseamnă endl în C++?Ce înseamnă variabilă globală și locală în C++?CMMMC a două numere în C++ (cel mai mic multiplu comun)Verificare dacă șir de caractere este palindrom în C++Funcții în C++. Ce sunt subprogrameleMatrice pătratice în C++. Diagonala principală și secundarăTransformarea unei litere mari în literă mică în C++Numărul combinărilor în C++ (formula combinărilor)Transformarea unui număr din baza 10 în baza 2 în C++Vectori de frecvență (de apariții) în C++Suma elementelor unui vector recursiv în C++Verifică dacă un caracter este cifră în C++Cum să calculezi instant 2 la puterea N în C++Instrucțiunea while (structuri repetitive)Verifică dacă un număr dat este o putere de 2 în C++Verificare număr prim în C++ (Clasa a IX-a)Factorialul unui număr în C++Ce este o funcție void în C++?Numărul de apariții al unui număr într-un vector în C++Matrice în C++. Declararea și parcurgerea tablourilor bidimensionaleInstrucțiunea continue (structuri repetitive)Inversarea unui vector în C++Cel mai frecvent element dintr-un șir în C++Verifică dacă un număr aparține șirului Fibonacci în C++Verifică dacă o literă este vocală în C++Aria unui triunghi folosind coordonatele acestora în C++Calculul combinărilor de n luate câte k (nCk) în C++Numărul aranjamentelor în C++ (formula aranjamentelor)

© Drepturi de autor

Echipa InfoAs își rezervă drepturile de autor pentru conținutul acestei pagini. Copierea conținutului fără acordul scris expres al InfoAs reprezintă o încălcare a Legii 8/1996 și va fi tratată ca atare.

Trimite lecția

Toată lecția

Doar videoclipul pe YouTube

Informatica devine ușoară cu InfoAs

Intră în cont