Stack and Queue
Page content
Queue
FIFO
package queue
import "sync"
type node struct {
data interface{}
next *node
}
type Queue struct {
head *node
tail *node
count int
lock *sync.Mutex
}
func NewQueue() *Queue {
return &Queue{lock: &sync.Mutex{}}
}
func (q *Queue) Len() int {
q.lock.Lock()
defer q.lock.Unlock()
return q.count
}
func (q *Queue) Push(data interface{}) {
q.lock.Lock()
defer q.lock.Unlock()
ele := &node{data: data}
if q.head == nil {
q.head = ele
q.tail = ele
} else {
q.tail.next = ele
q.tail = ele
}
q.count++
}
func (q *Queue) Poll() interface{} {
q.lock.Lock()
defer q.lock.Unlock()
if q.head == nil {
return nil
}
res := q.head
q.head = res.next
if q.head == nil {
q.tail = nil
}
q.count--
return res.data
}
func (q *Queue) Peek() interface{} {
q.lock.Lock()
defer q.lock.Unlock()
if q.head == nil {
return nil
}
return q.head.data
}
Stack
LIFO
package stack
import "sync"
type node struct {
value interface{}
next *node
}
type Stack struct {
head *node
count int
lock *sync.Mutex
}
func NewStack() *Stack {
return &Stack{lock: &sync.Mutex{}}
}
func (s *Stack) Len() int {
s.lock.Lock()
defer s.lock.Unlock()
return s.count
}
func (s *Stack) Peek() interface{} {
s.lock.Lock()
defer s.lock.Unlock()
if s.head == nil {
return nil
}
return s.head.value
}
func (s *Stack) Pop() interface{} {
s.lock.Lock()
defer s.lock.Unlock()
if s.head == nil {
return nil
}
res := s.head
s.head = res.next
s.count--
return res.value
}
func (s *Stack) Push(value interface{}) {
s.lock.Lock()
defer s.lock.Unlock()
node := &node{value: value}
if s.head == nil {
s.head = node
} else {
node.next = s.head
s.head = node
}
s.count++
}
Circular Queue
Circular Queue is an extend version of regular queue where the last element is connected to the first element so that it makes a circle
Dequeueing elements from fixed sized regular queue makes empty space in memory. That’s where circular queue was invented so that it reuses the empty memory as the rear has the pointer to the first element.
# https://leetcode.com/explore/learn/card/queue-stack/228/first-in-first-out-data-structure/1337/
class MyCircularQueue:
def __init__(self, k: int):
self.queue = [None] * k
self.head = -1
self.tail = -1
self.size = k
def enQueue(self, value: int) -> bool:
if self.isFull():
return False
# move head to 0 as the element will be enqueued
if self.isEmpty():
self.head = 0
# Tail will be 0th index when tail is at the end of the queue as it circulates
self.tail = (self.tail + 1) % self.size
self.queue[self.tail] = value
return True
def deQueue(self) -> bool:
if self.isEmpty():
return False
# If there there is only one element in the queue
if self.head == self.tail:
self.head = -1
self.tail = -1
return True
# Circulates head pointer to the 0th index if it reaches the last element
self.head = (self.head + 1) % self.size
return True
def Front(self) -> int:
if self.isEmpty():
return -1
return self.queue[self.head]
def Rear(self) -> int:
if self.isEmpty():
return -1
return self.queue[self.tail]
def isEmpty(self) -> bool:
return self.head == -1
def isFull(self) -> bool:
return (self.tail + 1) % self.size == self.head
# Your MyCircularQueue object will be instantiated and called as such:
# obj = MyCircularQueue(k)
# param_1 = obj.enQueue(value)
# param_2 = obj.deQueue()
# param_3 = obj.Front()
# param_4 = obj.Rear()
# param_5 = obj.isEmpty()
# param_6 = obj.isFull()
Reference
Circular Queue in Data Structure: Overview, Implementation Using Array and Linked List