Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

Autor artykułu: mgr Jerzy Wałaszek

©2023 mgr Jerzy Wałaszek
I LO w Tarnowie

Wyszukiwanie binarne

SPIS TREŚCI
Tematy pomocnicze

Problem

W uporządkowanym rosnąco zbiorze Z  należy wyszukać element o wartości (o kluczu) k.

Rozwiązanie

Postąpimy w sposób następujący.

Wyznaczymy element środkowy zbioru. Sprawdzimy, czy jest on poszukiwanym elementem. Jeśli tak, to element został znaleziony i możemy zakończyć poszukiwania. Jeśli nie, to poszukiwany element jest albo mniejszy od elementu środkowego, albo większy. Ponieważ zbiór jest uporządkowany, to elementy mniejsze od środkowego będą leżały w pierwszej połówce zbioru, a elementy większe w drugiej połówce. Zatem w następnym obiegu zbiór możemy zredukować do pierwszej lub drugiej połówki – jest w nich o połowę mniej elementów. Mając nowy zbiór postępujemy w sposób identyczny – znów wyznaczamy element środkowy, sprawdzamy, czy jest poszukiwanym elementem. Jeśli nie, to zbiór dzielimy znów na dwie połowy – elementy mniejsze od środkowego i elementy większe od środkowego. Poszukiwania kontynuujemy w odpowiedniej połówce zbioru aż znajdziemy poszukiwany element lub do chwili, gdy po podziale połówka zbioru nie zawiera dalszych elementów.

Ponieważ w każdym obiegu pętli algorytm redukuje liczbę elementów o połowę, to jego klasa złożoności obliczeniowej jest równa O ( log n  ). Jest to bardzo korzystna złożoność. Na przykład w algorytmie wyszukiwania liniowego przy 1000000 elementów należało wykonać aż 1000000 porównań, aby stwierdzić, iż elementu poszukiwanego nie ma w zbiorze. W naszym algorytmie wystarczy 20 porównań.

Oczywiście algorytm wyszukiwania liniowego może być zastosowany dla dowolnego zbioru. Nasz algorytm można stosować tylko i wyłącznie w zbiorze uporządkowanym. Ze względu na podział zbioru na kolejne połówki, ćwierci itd. algorytm nosi nazwę wyszukiwania binarnego (ang. binary search ).

Musimy uściślić sposób podziału zbioru na coraz mniejsze fragmenty. Zbiór Z  odwzorowujemy w tablicy Z  składającej się z n  elementów ponumerowanych kolejno od 0 do n-1. Określmy dwa indeksy:

i p  – indeks pierwszego elementu zbioru
i k  – indeks końcowego elementu zbioru

indeksy elementów tablicy 0 1 2 ... n-2 n-1  
indeksy początku i końca  i p         i k  

Indeksy i p  i i k  określają obszar zbioru w tablicy Z. Początkowo będą oczywiście równe: i p  = 0 oraz i k  = n  - 1.

Na podstawie tych dwóch indeksów obliczamy indeks elementu środkowego i sr:

Jeśli zbiór Z  jest uporządkowany rosnąco, to:

Z [ 0 ] Z [ 1 ] ... Z [ i sr-1 ] Z [ i sr  ] Z [ i sr+1 ] ... Z [ n-2 ] Z [ n-1 ]
i p i sr i k
elementy ≤ Z [ i sr  ]   elementy ≥ Z [ i sr  ]

Zatem w przypadku, gdy k  < Z [ i sr  ], to przechodzimy do pierwszej połówki, w której indeksy przebiegają od i p  do i sr  - 1. Element Z [ i sr  ] pomijamy, gdyż wiadomo, że o niego nam nie chodzi.

Jeśli k  > Z [ i sr  ], to przechodzimy do drugiej połówki o indeksach od i sr  + 1 do i k.

Algorytm wyszukiwania binarnego

Wejście:

i p  –  indeks pierwszego elementu w tablicy Z, i p    ∈ C.
i k  – indeks ostatniego elementu w tablicy Z, i k   ∈ C.
Z  – tablica do wyszukania elementu. Indeksy od i p  do i k.
k  – wartość poszukiwanego elementu – tzw. klucz.

Wyjście:

p  = indeks elementu o kluczu k  lub
p
  = -1, jeśli nie odnaleziono elementu o takim kluczu.

Zmienne pomocnicze:

i sr  –  indeks elementu środkowego. i sr   ∈ C.

Lista kroków:

K01: p  ← -1 zakładamy, iż k nie występuje w zbiorze
K02: Dopóki i p  ≤ i k,
wykonuj kroki K02...K10
w pętli poszukujemy elementu o wartości k
K03: ; wyznaczamy element środkowy
K04:     Jeśli k ≠ Z [ i sr  ],
    to idź do kroku K07
 
K05:     p  ← i sr element znaleziony, kończymy
K06:     Idź do kroku K11  
K07:     Jeśli k  < Z [ i sr  ],
    to idź do kroku K10
wybieramy odpowiednią połówkę zbioru na dalsze poszukiwania
K08:     i pi sr  + 1 k > Z [ i sr ] → druga połówka
K09:     Następny obieg pętli K02  
K10:     i k  ← i sr  - 1 k < Z [ i sr ] → pierwsza połówka
K11: Zakończ z wynikiem p  

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Program wypełnia tablicę 100 elementową Z  liczbami naturalnymi w taki sposób, aby powstał z nich ciąg rosnący. Następnie generuje liczbę pseudolosową k  z zakresu od Z [ 0 ] do Z [ 99 ] i wyszukuje binarnie jej położenie w tablicy. Na koniec wyświetlana jest liczba k, jej położenie w Z oraz zawartość tablicy Z  z zaznaczonym elementem o wartości k. Jeśli k  nie występuje w Z, to zamiast położenia program wyświetla słowo BRAK. Dodatkowo program zlicza wykonane obiegi pętli i wypisuje ich liczbę.
Pascal
// Wyszukiwanie binarne
// Data:   7.05.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

program prg;

const N = 100;

var
  Z : array [ 0..N - 1 ] of integer;
  i, ip, ik, isr, k, L, p : integer;

begin
  randomize;

  // wypełniamy tablicę Z [ ] 

  Z [ 0 ] := random ( 5 );
  for i := 1 to N - 1 do Z [ i ] := Z [ i - 1 ] + random ( 5 );

  // generujemy klucz k

  k := Z [ 0 ] + random ( Z [ N - 1 ] - Z [ 0 ] + 1 );

  // poszukujemy binarnie elementu k

  L  := 0; p  := -1; ip := 0; ik := N - 1;
  while ip <= ik do
  begin
    inc ( L );
    isr := ( ip + ik ) shr 1;
    if Z [ isr ] = k then
    begin
      p := isr; break;
    end
    else if k < Z [ isr ] then ik := isr - 1
    else                       ip := isr + 1;
  end;

  // wyświetlamy wyniki

  write ( k, ' : ' );
  if p >= 0 then write ( p ) else write ( 'BRAK' );
  writeln ( ' : obiegi = ', L );
  writeln;
  for i := 0 to N - 1 do
  begin
    write ( Z [ i ] :3 );
    if p = i then write ( '<' ) else write ( ' ' );
  end;
  writeln;
  writeln;
end.
C++
// Wyszukiwanie binarne
// Data:   7.05.2008
// (C)2020 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>

using namespace std;

const int N = 100;

int main( )
{
  int Z [ N ], i, ip, ik, isr, k, L, p;

  srand ( ( unsigned )time ( NULL ) );

  // wypełniamy tablicę Z [ ] 

  Z [ 0 ] = rand( ) % 5;
  for( i = 1; i < N; i++ ) Z [ i ] = Z [ i - 1 ] + ( rand( ) % 5 );

  // generujemy klucz k

  k = Z [ 0 ] + ( rand( ) % ( Z [ N - 1 ] - Z [ 0 ] + 1 ) );

  // poszukujemy binarnie elementu k

  p = -1; L = ip = 0; ik = N - 1;
  while( ip <= ik )
  {
    L++;
    isr = ( ip + ik ) >> 1;
    if( Z [ isr ] == k )
    {
      p = isr; break;
    }
    else if( k < Z [ isr ] ) ik = isr - 1;
    else                     ip = isr + 1;
  }

  // wyświetlamy wyniki

  cout << k << ": ";
  if( p >= 0 ) cout << p; else cout << "BRAK";
  cout << ": obiegi = " << L << endl << endl;
  for( i = 0; i < N; i++ )
  {
    cout << setw ( 3 ) << Z [ i ];
    if( p == i ) cout << "<"; else cout << " ";
  }
  cout << endl << endl;
  return 0;
}
Basic
' Wyszukiwanie binarne
' Data:   7.05.2008
' (C)2020 mgr Jerzy Wałaszek
'---------------------------

Const N = 100

Dim As Integer Z ( N-1 ), i, ip, ik, isr, k, L, p

Randomize

' wypełniamy tablicę Z [ ] 

Z ( 0 ) = Cint ( Rnd * 4 )
For i = 1 To N - 1: Z ( i ) = Z ( i-1 ) + Cint ( Rnd * 4 ): Next

' generujemy klucz k

k = Z ( 0 ) + Cint ( Rnd * ( Z ( N - 1 ) - Z ( 0 ) ) )

' poszukujemy binarnie elementu k

L  = 0: p  = -1: ip = 0: ik = N - 1
While ip <= ik
  L += 1
  isr = ( ip + ik ) Shr 1
  If Z ( isr ) = k Then
    p = isr: Exit While
  Elseif k < Z ( isr ) Then
    ik = isr - 1
  Else
    ip = isr + 1
  End If
Wend

' wyświetlamy wyniki

Print k;": ";
If p >= 0 Then Print p;: Else Print "BRAK";
Print ": obiegi =";L
Print
For i = 0 To N - 1
  Print Using "###";Z ( i );
  If p = i Then Print "<";: Else Print " ";
Next
Print
Print
End
Wynik:
42 : BRAK : obiegi = 7

  2   6  10  14  17  17  19  22  23  26  27  27  27  29  32  35  39  43  43  47
 47  48  48  49  49  50  53  57  57  58  62  62  63  67  68  72  75  75  77  81
 85  86  88  92  94  96  98 100 101 103 105 106 106 109 109 113 115 116 116 116
120 123 125 126 128 128 129 133 137 137 139 142 143 145 149 149 149 149 153 157
161 162 166 167 167 168 169 173 176 180 180 180 180 184 186 186 190 194 198 202

92 : 45 : obiegi = 5

  4   6   7  11  14  18  22  23  27  30  33  36  37  37  40  44  47  47  47  47
 49  51  53  54  58  62  62  62  62  63  67  69  69  71  71  73  73  77  79  80
 83  86  90  91  91  92< 93  93  97  99  99 101 105 107 110 111 111 115 115 115
118 121 122 122 122 126 128 130 130 131 135 136 139 143 145 147 147 151 153 153
154 155 157 160 164 164 168 169 173 174 176 180 183 187 190 193 194 198 198 202
Wyszukiwanie binarne
(C)2020 mgr Jerzy Wałaszek


...

Na początek:  podrozdziału   strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2023 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.