Разумевање имплементације Куеуе у Питхон-у

Strukture podataka zauzimaju ključnu poziciju u programiranju. One omogućavaju organizovanje podataka na način koji je efikasan za upotrebu. Redovi predstavljaju jednu od najosnovnijih struktura podataka.

U ovom članku ćemo se posvetiti redovima i njihovoj implementaciji u Pajtonu.

Šta je red?

Red je linearna struktura podataka koja funkcioniše po principu „prvi ušao, prvi izašao“ (FIFO – First In, First Out). On je suprotnost steku.

Red možemo zamisliti kao red ljudi koji čekaju na šalteru bioskopske blagajne. Ilustrujmo to na sledeći način:

Na šalteru, osoba koja je prva došla, prva će biti uslužena. Tek kada ona završi, sledeća osoba dolazi na red. Ljudi se ovde ponašaju po FIFO principu. Ko prvi stigne, prvi će obaviti posao. Slične situacije se mogu videti i u drugim aspektima svakodnevnog života.

Struktura podataka red sledi isti princip. Sada kada znate šta su redovi i kako funkcionišu, hajde da pogledamo operacije koje se mogu izvršavati nad redovima.

Operacije nad redom

Slično steku, i kod redova imamo dve glavne operacije:

enqueue(podaci)

Ova operacija dodaje nove podatke na kraj reda. Kraj reda se naziva rep.

dequeue()

Ova operacija uklanja podatke sa početka reda. Početak reda se naziva glava.

Radi boljeg razumevanja, pogledajmo ilustracije operacija nad redom. Jedna slika vredi hiljadu reči.

Možemo napisati i dodatne pomoćne funkcije za dobijanje više informacija o redu. Broj pomoćnih funkcija nije ograničen, ali fokusirajmo se za sada na one najvažnije, navedene u nastavku:

rear()

Vraća poslednji element u redu.

front()

Vraća prvi element u redu.

isEmpty()

Vraća informaciju o tome da li je red prazan.

Da li vam je dosadilo? Mislim na teorijske teme.

Meni jeste!

Ali, moramo savladati teoriju pre nego što pređemo na implementaciju. Bez brige, uskoro ćemo se posvetiti kodu.

Podrazumeva se da imate instaliran Pajton na računaru. Ako nemate, možete koristiti i neki online kompajler.

Implementacija reda

Implementacija reda ne bi trebalo da traje duže od 15 minuta. Kada savladate osnove, moći ćete da ga implementirate za nekoliko minuta nakon ovog uputstva.

Postoji nekoliko načina za implementaciju reda u Pajtonu. Pogledajmo različite implementacije korak po korak.

#1. Lista

Lista je ugrađeni tip podataka u Pajtonu. Koristićemo tip podataka lista za implementaciju reda unutar klase. Proći ćemo kroz različite korake za implementaciju strukture podataka red od nule, bez upotrebe dodatnih modula. Hajde da počnemo.

Korak 1:

Napišite klasu pod nazivom Queue.

class Queue:
  pass

Korak 2:

Potrebna nam je varijabla za čuvanje podataka u redu. Nazovimo je „elements“. Naravno, to je lista.

class Queue:

  def __init__(self):
    self.elements = []

Korak 3:

Da bismo ubacili podatke u red, potreban nam je metod u klasi. Metod se zove „enqueue“, kao što smo već spomenuli.

Metod prihvata podatke i dodaje ih na kraj reda („elements“). Možemo koristiti metod „append“ tipa podataka lista za dodavanje podataka na kraj.

class Queue:

  # ...

  def enqueue(self, data):
    self.elements.append(data)
    return data

Korak 4:

Red mora imati i izlaz. To se postiže pomoću metoda „dequeue“. Pretpostavljam da ste već pogodili da ćemo koristiti metod „pop“ tipa podataka lista. Ako ste pogodili, odlično!

Metod „pop“ tipa podataka lista briše element sa liste na određenom indeksu. Ako ne navedemo indeks, on briše poslednji element liste.

U ovom slučaju, želimo da obrišemo prvi element liste, pa moramo proslediti indeks 0 metodu „pop“.

class Queue:

  # ...

  def dequeue(self):
    return self.elements.pop(0)

To je sasvim dovoljno za osnovni red. Međutim, trebaju nam pomoćne funkcije da bismo testirali da li operacije nad redom rade ispravno. Napisaćemo i te pomoćne funkcije.

Korak 5:

Metod „rear()“ se koristi za dobijanje poslednjeg elementa u redu. Negativno indeksiranje u tipu podataka lista nam pomaže da dobijemo poslednji element.

class Queue:

  # ...

  def rear(self):
    return self.elements[-1]

Korak 6:

Metod „front()“ se koristi za dobijanje prvog elementa u redu. Prvi element reda možemo dobiti pomoću indeksa liste.

class Queue:

  # ...

  def front(self):
    return self.elements[0]

Korak 7:

Metod „is_empty()“ se koristi za proveru da li je red prazan. Možemo da proverimo dužinu liste.

class Queue:

  # ...

  def is_empty(self):
    return len(self.elements) == 0

Uf! Završili smo implementaciju strukture podataka red. Sada moramo da kreiramo objekat klase „Queue“.

Hajde da to uradimo.

class Queue:

  # ...

if __name__ == '__main__':
  queue = Queue()

Sada imamo objekat „Queue“. Testirajmo ga sa nekoliko operacija.

  • Proverite da li je red prazan ili ne pomoću metoda „is_empty“. Trebalo bi da vrati True.
  • Dodajte brojeve 1, 2, 3, 4, 5 u red pomoću metoda „enqueue“.
  • Metod „is_empty“ bi trebalo da vrati False. Proverite.
  • Odštampajte prednji i zadnji element koristeći metode „front“ i „rear“.
  • Uklonite element iz reda pomoću metoda „dequeue“.
  • Proverite prednji element. Trebalo bi da vrati element 2.
  • Sada uklonite sve elemente iz reda.
  • Metod „is_empty“ bi trebalo da vrati True. Proverite.

Mislim da je ovo dovoljno za testiranje naše implementacije reda. Napišite kod za svaki gore navedeni korak da biste testirali red.

Jeste li napisali kod?

Ako niste, ne brinite.

Pogledajte kod ispod.

class Queue:

  def __init__(self):
    self.elements = []

  def enqueue(self, data):
    self.elements.append(data)
    return data

  def dequeue(self):
    return self.elements.pop(0)

  def rear(self):
    return self.elements[-1]

  def front(self):
    return self.elements[0]

  def is_empty(self):
    return len(self.elements) == 0

if __name__ == '__main__':
  queue = Queue()

  ## checking is_empty method -> True
  print(queue.is_empty())

  ## adding the elements
  queue.enqueue(1)
  queue.enqueue(2)
  queue.enqueue(3)
  queue.enqueue(4)
  queue.enqueue(5)

  ## again checking is_empty method -> False
  print(queue.is_empty())

  ## printing the front and rear elements using front and rear methods respectively -> 1, 5
  print(queue.front(), end=' ')
  print(queue.rear())

  ## removing the element -> 1
  queue.dequeue()

  ## checking the front and rear elements using front and rear methods respectively -> 2 5
  print(queue.front(), end=' ')
  print(queue.rear())

  ## removing all the elements
  queue.dequeue()
  queue.dequeue()
  queue.dequeue()
  queue.dequeue()

  ## checking the is_empty method for the last time -> True
  print(queue.is_empty())

Pretpostavljam da pokrećete gornji program. Možete dobiti izlaz sličan sledećem rezultatu.

True
False
1 5
2 5
True

Možemo direktno koristiti tip podataka lista kao strukturu podataka red. Ova implementacija pomaže vam da bolje razumete implementaciju reda u drugim programskim jezicima.

Takođe, možete koristiti ovu implementaciju klase red u drugim programima jednostavnim kreiranjem objekta, kao što smo to radili ranije.

Implementirali smo red od nule koristeći tip podataka lista. Da li postoje ugrađeni moduli za red? Da! Imamo ugrađene implementacije redova. Pogledajmo ih.

#2. deque iz kolekcija

Realizovan je kao dvostrani red (deque – double-ended queue). Pošto podržava dodavanje i uklanjanje elemenata sa oba kraja, možemo ga koristiti i kao stek i kao red. Hajde da vidimo implementaciju reda pomoću „deque“.

Implementiran je pomoću druge strukture podataka, koja se zove dvostruko povezana lista. Dakle, performanse ubacivanja i brisanja elemenata su konzistentne. Pristup elementima iz sredine dvostruko povezane liste traje O(n) vremena. Možemo ga koristiti kao red, jer nema potrebe za pristupom elementima iz sredine reda.

Pogledajmo različite metode koje nam „deque“ nudi.

  • append(podaci) – koristi se za dodavanje podataka u red
  • popleft() – koristi se za uklanjanje prvog elementa iz reda

Ne postoje alternative za metode „front“, „rear“ i „isEmpty“. Možemo odštampati ceo red da bismo zamenili metode „front“ i „rear“. Takođe, možemo koristiti metod „len“ da bismo proverili da li je red prazan.

Pratili smo niz koraka za testiranje implementacije reda u prethodnom primeru. Hajde da sledimo iste korake i ovde.

from collections import deque

## creating deque object
queue = deque()

## checking whether queue is empty or not -> True
print(len(queue) == 0)

## pushing the elements
queue.append(1)
queue.append(2)
queue.append(3)
queue.append(4)
queue.append(5)

## again checking whether queue is empty or not -> False
print(len(queue) == 0)

## printing the queue
print(queue)

## removing the element -> 1
queue.popleft()

## printing the queue
print(queue)

## removing all the elements
queue.popleft()
queue.popleft()
queue.popleft()
queue.popleft()

## checking the whether queue is empty or not for the last time -> True
print(len(queue) == 0)

Dobićete rezultat sličan sledećem izlazu.

True
False
deque([1, 2, 3, 4, 5])
deque([2, 3, 4, 5])
True

#3. Red iz modula queue

Pajton ima ugrađen modul pod nazivom „queue“, koji sadrži klasu pod imenom „Queue“ za implementaciju reda. Slična je onoj koju smo mi ranije implementirali.

Prvo, hajde da pogledamo različite metode klase „Queue“.

  • put(podaci) – dodaje ili gura podatke u red
  • get() – uklanja prvi element iz reda i vraća ga
  • empty() – vraća da li je red prazan ili ne
  • qsize() – vraća dužinu reda.

Hajde da implementiramo red sa gore navedenim metodama.

from queue import Queue

## creating Queue object
queue_object = Queue()

## checking whether queue is empty or not -> True
print(queue_object.empty())

## adding the elements
queue_object.put(1)
queue_object.put(2)
queue_object.put(3)
queue_object.put(4)
queue_object.put(5)

## again checking whether queue is empty or not -> False
print(queue_object.empty())

## removing all the elements
print(queue_object.get())
print(queue_object.get())
print(queue_object.get())

## checking the queue size
print("Size", queue_object.qsize())

print(queue_object.get())
print(queue_object.get())

## checking the whether queue_object is empty or not for the last time -> True
print(queue_object.empty())

Proverite izlaz gornjeg koda.

True
False
1
2
3
Size 2
4
5
True

Postoje i druge metode u klasi „Queue“. Možete ih istražiti pomoću ugrađene funkcije „dir“.

Zaključak

Nadam se da ste naučili o strukturi podataka red i njenoj implementaciji. To je sve u vezi sa redovima. Možete koristiti red na različitim mestima gde je potrebno obraditi podatke po FIFO principu (prvi ušao/prvi izašao). Koristite red pri rešavanju problema kada god je to potrebno.

Da li ste zainteresovani za savladavanje Pajtona? Pogledajte ove resurse za učenje.

Srećno kodiranje 🙂 👨‍💻