mirror of
https://github.com/dholerobin/Lecture_Notes.git
synced 2025-03-15 21:59:56 +00:00
222 lines
3.8 KiB
Markdown
222 lines
3.8 KiB
Markdown
![]() |
Queues
|
||
|
------
|
||
|
|
||
|
- preserves order - FIFO
|
||
|
- queue of people in front of a ticker place
|
||
|
|
||
|
**Operations:**
|
||
|
|
||
|
stack: push and pop, peek
|
||
|
|
||
|
queue:
|
||
|
- enqueue / pushfront
|
||
|
- dequeue / popfront / removefront
|
||
|
- front
|
||
|
- can't be done efficiently with just enqueue and dequeue
|
||
|
- note: dequeue != deque. DEQue stands for Double Ended Queue
|
||
|
|
||
|
|
||
|
-- --
|
||
|
|
||
|
|
||
|
Binary Numbers
|
||
|
--------------
|
||
|
> Generate all binary numbers upto $d$ digits.
|
||
|
|
||
|
- Keep 2 queues
|
||
|
- print 0
|
||
|
- Start with [1]
|
||
|
- pop and print
|
||
|
- append both 0 and 1 to it, and append to queue
|
||
|
- how to append to number? $\displaystyle x = 10x + 0, 10x + 1$
|
||
|
|
||
|
```
|
||
|
0
|
||
|
1
|
||
|
10 11
|
||
|
11 100 101
|
||
|
100 101 110 111
|
||
|
...
|
||
|
```
|
||
|
|
||
|
K-ary numbers
|
||
|
-------------
|
||
|
> Given N
|
||
|
> Print first N positive numbers, whose digits are either 1, 2, 3
|
||
|
>
|
||
|
> output: 1 2 3 11 12 13 21 22 23 31 ...
|
||
|
|
||
|
-- --
|
||
|
|
||
|
|
||
|
Some Tree:
|
||
|
```
|
||
|
1 2 3
|
||
|
11 12 13 21 22 23 31 32 33
|
||
|
```
|
||
|
- BFS: level order traversal: Queue
|
||
|
- DFS: stack
|
||
|
|
||
|
-- --
|
||
|
|
||
|
|
||
|
Implementations
|
||
|
---------------
|
||
|
|
||
|
**Queue using Array**
|
||
|
- front pointer
|
||
|
- read pointer
|
||
|
- enqueue: insert after rear. increment rear
|
||
|
- dequeue: return front. increment front
|
||
|
- issue: wasted space
|
||
|
- empty space, but overflow
|
||
|
- can be fixed by using a circular queue
|
||
|
|
||
|
|
||
|
**Queue using Stacks**
|
||
|
- enqueue: push $O(1)$
|
||
|
- dequeue: pop all into auxillary. pop and return top of auxillary. push all back again $O(n)$
|
||
|
|
||
|
|
||
|
What is we want dequeue to be fast, but enqueue can be slow?
|
||
|
|
||
|
- enqueue: pop all into auxillary stack. Push x. Pop and push all into original
|
||
|
- dequeue: pop
|
||
|
|
||
|
|
||
|
|
||
|
**Stack using Queue**
|
||
|
- push: enqueue $O(1)$
|
||
|
- pop: dequeue all into auxillary queue. Make sure you don't dequeue last element. Copy back values $O(n)$
|
||
|
|
||
|
|
||
|
Similarly, complexities can be reversed here too
|
||
|
|
||
|
|
||
|
-- --
|
||
|
|
||
|
|
||
|
Circular Queue using Array:
|
||
|
---------------------------
|
||
|
|
||
|
```
|
||
|
1 2 3 4 _ _
|
||
|
dequeue 3 times
|
||
|
enqueue 5, 6, 7
|
||
|
|
||
|
Failure, even though empty place is available
|
||
|
```
|
||
|
|
||
|
- Draw it circularly
|
||
|
- use mod with size to keep track of front and rear
|
||
|
|
||
|
```python
|
||
|
def __init__(N):
|
||
|
N
|
||
|
front = rear = -1
|
||
|
|
||
|
def enqueue(x):
|
||
|
if (rear + 1) % N == front:
|
||
|
raise Overflow
|
||
|
elif front == -1:
|
||
|
front, rear = 0, 0
|
||
|
queue[rear] = x
|
||
|
else:
|
||
|
rear = (rear + 1) % N
|
||
|
queue[rear] = x
|
||
|
|
||
|
def dequeue(self):
|
||
|
if front == -1:
|
||
|
raise Underflow
|
||
|
elif front == rear:
|
||
|
x = queue[front]
|
||
|
front, rear = -1, -1
|
||
|
return x
|
||
|
else:
|
||
|
x = queue[front]
|
||
|
front = (front + 1) % N
|
||
|
return x
|
||
|
```
|
||
|
|
||
|
|
||
|
-- --
|
||
|
|
||
|
|
||
|
Doubly Ended Queue
|
||
|
------------------
|
||
|
|
||
|
- insert_front
|
||
|
- insert_last
|
||
|
- delete_front
|
||
|
- delete_last
|
||
|
|
||
|
Standard implementations in all languages (usually circular and array)
|
||
|
Just google and use.
|
||
|
|
||
|
- use array implementation vs linked list implementation
|
||
|
- array
|
||
|
- space efficient
|
||
|
- cache - locality of reference
|
||
|
- can't increase size easily
|
||
|
- vector
|
||
|
- amortized O(1) if double
|
||
|
- linked list
|
||
|
- can increase size easily
|
||
|
- space inefficient
|
||
|
- easier to distribute over multiple machines
|
||
|
|
||
|
-- --
|
||
|
Window Max
|
||
|
----------
|
||
|
|
||
|
> Given A[n]
|
||
|
> Given $k$
|
||
|
> Find max element for every $k$ size window
|
||
|
|
||
|
|
||
|
**Naive**
|
||
|
|
||
|
Keep window of size $k$. Calculate max every time.
|
||
|
$O(nk)$
|
||
|
|
||
|
**Optimized**
|
||
|
|
||
|
Given
|
||
|
```
|
||
|
9 1 3 2 8 6 3 ...
|
||
|
```
|
||
|
window of size 6
|
||
|
|
||
|
- The 8 doesn't allow windows after 9 to have other maxes. So max can't be 1, 3, 2
|
||
|
- So we need to maintain the useful (decreasing) elements
|
||
|
|
||
|
- Read array from left to write and maintain the decreasing elements. So we need push_front
|
||
|
- But when some element in the window becomes useless, pop it from the left. So we need remove_last
|
||
|
- So we can use deque
|
||
|
|
||
|
|
||
|
|
||
|
```
|
||
|
N = 9, k = 3
|
||
|
10 1 2 9 7 6 5 11 3
|
||
|
\------------/
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
```
|
||
|
|
||
|
- first element of the useful elements is the max.
|
||
|
- pop from last if the element cant be part of next window. So, store indexes
|
||
|
|
||
|
$O(n)$
|
||
|
|
||
|
|
||
|
|
||
|
**Variation**
|
||
|
|
||
|
output max + min for every window of size k
|