Deo zbornika Učimo algoritme

Pretraga u širinu

Email Twitter LinkedIn Facebook Google

Pretraga u širinu (engl. breadth first search) se od pretrage u dubinu razlikuje po redosledu obilaženja polja, odnosno pozicija u postoru pretrage. Ovom pretragom se prvo pronalaze sve pozicije koje nastaju posle jednog poteza, zatim sve koje nastaju posle dva poteza, itd.

Kada je poznat skup S(k) pozicija dostižnih k poteza, tada se skup S(k+1) pozicija dostižnih u k+1 poteza dobija napredovanjem za jedan korak na svaki mogući način is svake od pozicija iz S(k). Ranije posećene pozicije se ne uzimaju ponovo u obzir. Postupak se nastavlja dok se ne dođe do tražene pozicije, ili se pretraže sve pozicije u zadatim okvirima.

Prednost pretrage u širinu je što se prvo posećivanje svake nove pozicije uvek postiže u najmanjem mogućem broju poteza. Zahvaljujući tome, rešenja otkrivena pretragom u širinu su uvek optimalna po broju poteza. Sa druge strane, radi pretrage u širinu potrebno je organizovati pamćenje posećenih pozicija, da bi se pretraga mogla nastaviti iz svih tih pozicija.

Algoritam pretrage u širinu koristi strukturu podataka koja se naziva red (engl. queue). Ona zaista funkcioniše kao red ljudi koji čekaju na neku uslugu: objekti mogu da se dodaju na kraj reda, a objekat koji je na početku reda može da se uzme i upotrebi. U slučaju lavirinta, objekti predstavljaju pozicije iz prostora pretrage, a to su dostignuta polja.

Izlazak iz lavirinta

Da bismo bolje ilustrovali mogućnosti algoritma pretrage u širinu, postavićemo problem lavirinta nešto drugačije. Neka je matricom a dat lavirint i polazno polje u njemu. Zadatak je da se za svako polje lavirinta odredi najmanji broj poteza koji je potreban da se do tog polja stigne kroz lavirint, kretanjem od polaznog polja.

Stavljaćemo u red koordinate polja koja su susedna posećenim, tako da ona čekaju da budu posećena. Za svako polje ćemo u pomoćnoj matrici m pamtiti broj poteza koji je potreban za stizanje do njega.

MinMoves(xstart, ystart)
  dirx[4] = {1, -1, 0, 0}; // Ovaj niz, zajedno sa sledecim zadaje 4 moguca smera kretanja
  diry[4] = {0, 0, 1, -1};

  for r = 1 to rowCnt
    for c = 1 to colCnt
      m[r][c] = infinity;

  queue<Square> q;
  q.push(Square(xstart, ystart));
  m[ystart][xstart]=0;

  while (!q.empty())
    x = q.front().x;
    y = q.front().y;
    q.pop();
    for dir = 1 to 4
      xx = x + dirx[dir];
      yy = y + diry[dir];
      if (xx > 0 && yy > 0 && xx <= rowCnt && yy <= colCnt &&
        m[yy][xx] == infinity && a[yy][xx] != kWall)
          m[yy][xx] = m[y][x] + 1;
          q.push(Square(xx, yy));

  // Ispisivanje izracunate matrice
  for r = 1 to rowCnt
    for c = 1 to colCnt
      if (m[r][c] == infinity)
        Write('.');
      else
        Write(m[r][c]);
    WriteLine();

Prilikom pretrage u širinu želimo da dodamo u red samo susede tekućeg polja koji još nisu posećeni. Ovde se posećena polja prepoznaju po tome što imaju upisan potreban broj poteza (različit od inicijalne vrednosti).

Vreme rada i zauzeće memorije su u najgorem slučaju srazmerni veličini prostora pretrage.

Izvor: Petlja.org