Bináris keresés

Szekvenciális keresés: egyesével végignézzük az elemeket.

Ha egy tömb rendezett, tudunk benne hatékonyabban keresni: minden körben a középső (vagy egyik középső) elemet nézzük meg és a tömbnek csak abban a “felében” folytatjuk a keresést (ugyanígy tovább), ahol esélyünk van megtalálni a számot. Ezt az eljárást nevezzük bináris keresésnek.

Példa (az n elemű t tömbben keressük x-et):

    n = 8
    t: 1 3 4 8 9 20 30 50
      [      *           ]
      [     ]
         *
          [ ]

    x = 7

Feladat:

Adott egy tömb növekvő sorrendbe rendezett egész számokból. Adott még egy x érték. Írjuk ki, hogy megvan-e x a tömbben (igen/nem)!

Megoldás szekvenciális kereséssel

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;

int main()
{
    cout << "n = ";
    int n;
    cin >> n;

    cout << "a tomb elemei: ";
    int t[1000];
    for (int i = 0; i < n; i++)
        cin >> t[i];

    int x;
    cout << "x = ";
    cin >> x;


    bool megvan = false;

    for (int i = 0; i < n; i++) {
        if (t[i] == x)
            megvan = true;
    }

    if (megvan)
        cout << "igen" << endl;
    else
        cout << "nem" << endl;

    return 0;
}

Megoldás bináris kereséssel

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
using namespace std;

int main()
{
    cout << "n = ";
    int n;
    cin >> n;

    cout << "a tomb elemei: ";
    int t[1000];
    for (int i = 0; i < n; i++)
        cin >> t[i];

    int x;
    cout << "x = ";
    cin >> x;


    bool megvan = false;

    int bal = 0;
    int jobb = n-1;

    while (!megvan && bal <= jobb) {
        int kozep = (bal + jobb) / 2;

        if (t[kozep] == x) {
            megvan = true;
            bal = kozep;
            jobb = kozep;
        }
        else if (t[kozep] < x) {
            bal = kozep + 1;
        }
        else { // >
            jobb = kozep - 1;
        }
    }

    if (megvan)
        cout << "igen, a(z) " << bal << " indexen" << endl;
    else
        cout << "nem" << endl;

    return 0;
}

HF.

Kövessük nyomon az algoritmus futását a

    10
    1 3 4 5 6 8 8 10 20 56

tömbre és a 10, 11, 1, 56, 0, 57 keresett értékekre külön-külön!

Változatok

1.

Adott egy csökkenő sorozat és egy keresett érték, döntsük el bináris kereséssel, hogy megvan-e a sorozatban, ha igen, írjuk ki valamelyik előfordulásának (0-alapú) indexét.

HF

2.

Keressük meg egy növekvő sorozatban az x szám első előfordulásának a helyét (ha nincs meg, akkor a válasz -1).

Pl. bemenet:
    6
    1 3 3 3 3 4
    3
kimenet:
    1
    (a 3-as első előfordulása az 1-es indexen van)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
using namespace std;

int main()
{
    cout << "n = ";
    int n;
    cin >> n;

    cout << "a tomb elemei: ";
    int t[1000];
    for (int i = 0; i < n; i++)
        cin >> t[i];

    int x;
    cout << "x = ";
    cin >> x;

    int bal = 0;
    int jobb = n-1;

    while (bal < jobb) {
        int kozep = (bal + jobb) / 2;

        if (t[kozep] >= x) {
            jobb = kozep;
        }
        else if (t[kozep] < x) {
            bal = kozep + 1;
        }
    }

    // itt biztos, hogy bal==jobb
    // ha t[bal] == x, akkor ez az első
    if (t[bal] == x)
        cout << "az elso elofordulas helye: "
             << bal << endl;
    else
        cout << "nincs x";

    return 0;
}

3.

Keressük meg egy növekvő sorozatban az x szám utolsó előfordulásának a helyét (ha nincs meg, akkor a válasz legyen az első nála nagyobb elem helye, illetve ha ilyen sincs, akkor a válasz -1).

Pl. bemenet:
    6
    1 3 3 3 3 4
    3
kimenet:
    4
    (a 3-as utolsó előfordulása a 4-es indexen van)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
using namespace std;

int main()
{
    cout << "n = ";
    int n;
    cin >> n;

    cout << "a tomb elemei: ";
    int t[1000];
    for (int i = 0; i < n; i++)
        cin >> t[i];

    int x;
    cout << "x = ";
    cin >> x;

    int bal = 0;
    int jobb = n-1;

    while (bal < jobb) {
        int kozep = (bal + jobb + 1) / 2;

        if (t[kozep] > x)
            jobb = kozep - 1;
        else // <=
            bal = kozep;
    }

    // bal == jobb (biztos)

    if (t[bal] == x) {
        cout << "az utolso elofordulas indexe: "
             << bal;
    }
    else if (t[bal] < x && bal == n-1) {
        cout << "nincs elem, ami >= x (-1)" << endl;

    }
    else if (t[bal] < x) {
        cout << "az elso x-nel nagyobb elem indexe: "
             << bal+1;
    }
    else { // t[bal] > x
        cout << "az elso x-nel nagyobb elem indexe: "
             << bal;
    }

    return 0;
}

4.

Határozzuk meg egy n természetes szám négyzetgyökének az egészrészét (sqrt nélkül).

Megoldás bináris kereséssel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;

int main()
{
    cout << "n = ";
    int n;
    cin >> n;

    int a = 0, b = n;

    int eredmeny = -1;

    while (a < b && eredmeny == -1) {
        int k = (a+b+1) / 2;

        if (k*k < n) {
            a = k;
        }
        else if (k*k == n) {
            eredmeny = k;
        }
        else { // >
            b = k-1;
        }
    }
    // itt a == b mindig ha az eredmeny nincs
    // beallitva

    if (eredmeny == -1) {
        cout << a << endl;
    }
    else
        cout << eredmeny << endl;

    return 0;
}

Vagy eredmény változó nélkül:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;

int main()
{
    cout << "n = ";
    int n;
    cin >> n;

    int a = 0, b = n;

    while (a < b) {
        int k = (a+b+1) / 2;

        if (k*k <= n) {
            a = k;
        }
        else { // >
            b = k-1;
        }
    }

    // itt a == b mindig
    cout << a << endl;

    return 0;
}

Megoldás szekvenciális kereséssel (lassabb):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;

int main()
{
    cout << "n = ";
    int n;
    cin >> n;

    int eredmeny = 0;

    while (eredmeny*eredmeny <= n)
        eredmeny++;

    eredmeny--;

    cout << eredmeny << endl;
    return 0;
}