Stack & Queue
Outline
- What is data structure
- stack
- Queue
- Link List
Intro. to Data Structure
Briefly Speaking : how to store data in a computer
Like a Library
Your book is data
And how to sort and store these books
Target : find a book a quick as possible
In real world

A new Book
Where to put this book?
An old book
Delete this book
Maybe need to check
In computer
Some Valuation
- Time Complexity
- Space Complexity
- Coding Complexity
Data Structure as tools
Solving a Problem
(multi) Data Structure + (multi) Algorithm
Common Operation on DS
push/insert : put in an element
pop/delete : take out an element
query : search, if-exist, quantitiy, max, min
Stack
stack (堆疊)
Properties
- First in last out (FILO)
- each pop operation, pop out the last one enter stack
- like plates
stack implementation
- Array
- Linked List ( mention latter )
What we need in array implementation ?
- Use a variable "top" to record the position of top
- top = -1 -> the stack is empty
- push : top increase 1
- pop : top decrease 1
| Outcome |
|---|
| Stack |
|---|
| Operation |
|---|
Stack
<- top
| Outcome |
|---|
| Stack |
|---|
| Operation |
|---|
| push 1 |
Stack
<- top
| Outcome |
|---|
| Stack |
|---|
| 1 |
| Operation |
|---|
| push 1 |
Stack
<- top
| Outcome |
|---|
| Stack |
|---|
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
Stack
<- top
| Outcome |
|---|
| Stack |
|---|
| 19 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
Stack
<- top
| Outcome |
|---|
| Stack |
|---|
| 19 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
Stack
<- top
| Outcome |
|---|
| Stack |
|---|
| 35 |
| 19 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
Stack
<- top
| Outcome |
|---|
| Stack |
|---|
| 35 |
| 19 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
Stack
<- top
| Outcome |
|---|
| 35 |
| Stack |
|---|
| 19 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
Stack
<- top
| Outcome |
|---|
| 35 |
| Stack |
|---|
| 19 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
Stack
<- top
| Outcome |
|---|
| 35 |
| 19 |
| Stack |
|---|
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
Stack
<- top
| Outcome |
|---|
| 35 |
| 19 |
| Stack |
|---|
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
| push 7 |
Stack
<- top
| Outcome |
|---|
| 35 |
| 19 |
| Stack |
|---|
| 7 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
| push 7 |
Stack
<- top
| Outcome |
|---|
| 35 |
| 19 |
| Stack |
|---|
| 7 |
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
| push 7 |
| pop |
Stack
<- top
| Outcome |
|---|
| 35 |
| 19 |
| 7 |
| Stack |
|---|
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
| push 7 |
| pop |
Stack
<- top
| Outcome |
|---|
| 35 |
| 19 |
| 7 |
| Stack |
|---|
| 1 |
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
| push 7 |
| pop |
| pop |
Stack
<- top
| Outcome |
|---|
| 35 |
| 19 |
| 7 |
| 1 |
| Stack |
|---|
| Operation |
|---|
| push 1 |
| push 19 |
| push 35 |
| pop |
| pop |
| push 7 |
| pop |
| pop |
Stack
<- top
Use Array
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
push 4
top = -1
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 4 |
top = 0
push 7
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 4 | 7 |
top = 1
Use Array
pop, outcome = 7
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 4 |
top = 0
push 17, push 39
| 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 4 | 17 | 39 |
top = 2
push 25, pop, pop, push 14 pop
What are the outcomes , top, and remaining value in array ?
STL : standard template library
#include <stack>
std::stack<int> steak;
steak.push(10);
steak.push(18);
std::cout << steak.top() << '\n';
// return the top value of stack. No pop out.
steak.pop();
// only pop out the top one of stack, no return;
std::cout << steak.top() << '\n';
Please share your screen
Homework
Use stack
Queue
(佇列)
Queue Properties
- first in first out (FIFO)
- like lining up
- pop operation : pop out the oldest element in queue
- some structure : single direction, cycle linked list
Queue Operations
- push : put an element into queue
- pop : take an element out of queu
Queue Implementation
Same
- Array
- Linked list
Implement in array
- use a variable "front" to record the position in front of the first element.
- use a variable "rear" to record the position of the last element
- if front == rear -> queue is empty
- push : rear + 1
- pop : front + 1
| Outcome |
|---|
| Queue |
|---|
| Operation |
|---|
Queue
<- front = rear
| Outcome |
|---|
| Queue |
|---|
| Operation |
|---|
| push 'a' |
Queue
<- front = rear
| Outcome |
|---|
| Queue |
|---|
| a |
| Operation |
|---|
| push 'a' |
Queue
<- front
<- rear
| Outcome |
|---|
| Queue |
|---|
| a |
| Operation |
|---|
| push 'a' |
| push 't' |
Queue
<- front
<- rear
| Outcome |
|---|
| Queue |
|---|
| t |
| a |
| Operation |
|---|
| push 'a' |
| push 't' |
Queue
<- front
<- rear
| Outcome |
|---|
| Queue |
|---|
| t |
| a |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| Queue |
|---|
| t |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| Queue |
|---|
| t |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| Queue |
|---|
| e |
| t |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| Queue |
|---|
| e |
| t |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| Queue |
|---|
| k |
| e |
| t |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| Queue |
|---|
| k |
| e |
| t |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| t |
| Queue |
|---|
| k |
| e |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| t |
| Queue |
|---|
| k |
| e |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
| pop |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| t |
| e |
| Queue |
|---|
| k |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
| pop |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| t |
| e |
| Queue |
|---|
| k |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
| pop |
| pop |
Queue
<- front
<- rear
| Outcome |
|---|
| a |
| t |
| e |
| k |
| Queue |
|---|
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
| pop |
| pop |
Queue
<- front =rear
Now Stack is empty !!
| Outcome |
|---|
| a |
| t |
| e |
| k |
| Queue |
|---|
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
| pop |
| pop |
| push 'm' |
Queue
<- front =rear
Now Stack is empty !!
| Outcome |
|---|
| a |
| t |
| e |
| k |
| Queue |
|---|
| m |
| Operation |
|---|
| push 'a' |
| push 't' |
| pop |
| push 'e' |
| push 'k' |
| pop |
| pop |
| pop |
| push 'm' |
Queue
<- front
Now Stack is empty !!
<- rear
But array will running out ?
| 0 | 1 | ... | 21473646 | 21473657 |
|---|---|---|---|---|
| k |
^------------------------unused-----------^
front
rear
The problem : if an element is popped out,
that position can't be used anymore.
Solution 1
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| k | a | e |
front
rear
when rear is at the end, move(shift) all element to the begin.
pushing an 'r'
Solution 1
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| k | a | e | r |
front
rear
When rear is at the end, move(shift) all element to the begin.
shift then push an 'r'
Solution 2 : use circular queue
We just push then element as usual
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| r | k | a | e |
front
rear
pushing an 'r'
Solution 2 : use circular queue
What should be aware of ?
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| r | k | l | k | a | e |
front
rear
- When rear = front ? is it empty or full
Sacrifice a place and note that when
rear == front -> empty
rear == front -1 -> full
Some cheat
Actually, in some problem, the size of input is not so big.
We can just allocate an array that large enough.
Solution 3 : Linked List
Later we will mention
Time complexity
push |
pop |
|
|---|---|---|
stack |
O(1) |
O(1) |
queue |
O(1) |
O(1) |
#include <queue>
std::queue<int> que;
que.push(1);
std::cout << que.front() << '\n';
// return the value of first element
// (the next one to be pop),
// not performing pop
que.push(2);
std::cout << que.front() << '\n';
que.pop();
// pop out the firsst element, no return
std::cout << que.front() << '\n';What are the outputs ?
Homework UVa-540
Use linked list
Linked List
(鏈結串列)
Real life Question
There are N trains, each one has M carriages
Now you have some work to do
connect a-th train to b-th train
and the station master ask you how is the final train like


Real life Question
We just simply connect the train


Now, how to implement in program ?
We try array
An 1D array represents a train
| 0 | 1 | 2 | 3 | 4 | ... | |
|---|---|---|---|---|---|---|
| train 1 | 1 | 3 | ||||
| train 2 | 5 | 7 | ||||
| train 3 | 9 | 11 |
How long should an array be ?
N trains, M carriages
Largest possible train is N*M
So your array should be N*M long...
Connect the train
| 0 | 1 | 2 | 3 | 4 | ... | |
|---|---|---|---|---|---|---|
| train 1 | 1 | 3 | ||||
| train 2 | 5 | 7 | 9 | 11 | ||
| train 3 |
for (int i = 0; i < len_b; i++){
train_a[len_a + i] = train_b[i];
}
len_a += len_b;Problems
- Waste lots of space
- Most of the space are empty
- Allocate N*M but only use M
- Waste of time
- Each operation needs O(N)
- Array is not good...
Linked List
Basic Elements
Node : (data + pointer) (like carriage)
link lots of nodes together
use a pointer "head" point to the first node
the last node point to null


Properties of Linked List
- Every element only take care of its next element
- We only take care of the start (head)
- Classification : single linked list, doubly, circular
- No random access
Operations of Linked List
- Insert : insert an element between two elements or at the head or at the end.
- Delete : delete an element
Implementation
- Define a struct / class "Node" as the node of linked list, contain data the pointer to the next node.
- At the outside we only save the head as the start point.
struct Node{
int _data;
Node * _next;
}
int main(){
Node* node = new Node();
}Pros of Linked List
- Better usage of memory
- insert and delete fast
- (record how to delete an element in array)
Insert

void insert(Node *A, Node* B){
A->_next = B;
}Delete
void delete(Node *A){
Node * tode = A->next;
A->next = A->next->next;
delete tode; // free memory
}
Is there some problem about the code ?
Delete
void delete(Node *A){
Node * tode = A->next;
if(A->next != nullptr){
A->next = A->next->next;
delete tode; // free memory
}else{
A->next = nullptr;
}
}
Stack & Queue
Use linked list implement stack
- push : insert a node in front of head
- pop : delete the node head point to
Use linked list implement queue
- push : insert a node at the end of last node
- pop : delete the node head point to
Implement Stack
class Stack{
private:
struct Node{
Node *_next;
int _data;
}
Node * head
public:
void push(int val){
Node * newNode = new Node(val);
newNode->next = head;
head = newNode;
}
void pop(int val){
Node * tode = head;
head = head->next;
delete head;
}
};Implement Queue
class Stack{
private:
struct Node{
Node *_next;
int _data;
}
Node * head;
Node * end;
public:
void push(int val){
Node * newNode = new Node(val);
end->next = newNode;
end = newNode;
}
void pop(int val){
Node * tode = head;
head = head->next;
delete head;
}
};Of course there are lots of implementing Detail need to be cover

Time Complexity
| random access | push front |
push back |
pop front |
pop back |
|
|---|---|---|---|---|---|
| Array | yes | O(n) | O(1) | O(n) | O(1) |
| Linked List | No | O(1) | O(1) | O(1) | O(1) |
Some classic Problems
give you a string of parentheses, determine if it is legal
"{([])([]{{}[]})}" => legal
"({([][]))} => illegal
Thinking 1
Count how many left parenthesis and right parenthesis ?
How about this ?
{ [ ( ] ) } ?
Thinking 2
Use stack !!
push in when encounter left one
pop out when match right
Problem 2
The maximum Rectangle in a Bar Graph

Challenge Problem 2
The maximum Rectangle in a Bar Graph

Try to implement Stack & Queue by yourself
And get AC of previous problems use your own stack & queue
Homework
Remember to send me the AC screen shot !
Problems tutorial
UVa 514- Rails
UVa 514- Rails
We stimulate the stack directly
And try to produce the order it wants
So
1. if the top is equal to the current wanting order, pop out
2. if the top is not equal, we can't pop.
So we put another new train into stack
Pseudo Code
up_coming = 1
push up_coming into stack
up_coming = up_coming + 1
want = 0
while up_coming <= N or stack isn't empty
if(order[want] equal to top of stack)
pop out stack
else
push up_coming into stack
up_coming = up_coming+1
How about the invalid case ?
If the order is valid
then all element in stack will eventually popped out due to matching.
If the order is invalid
eventually there must some place the stack start to unmatch
and never match again.
So in all element pushed into stack and still not matching
It must be invalid
Pseudo Code
up_coming = 1
push up_coming into stack
up_coming = up_coming + 1
want = 0
while up_coming <= N or stack isn't empty
if(order[want] equal to top of stack)
pop out stack
else
push up_coming into stack
up_coming = up_coming+1
if(up_coming == N+1 and the top of stack != order[want])
failed
break
UVa 540
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| a | x |
|---|
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| a | x | y |
|---|
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| a | b | x | y |
|---|
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| b | x | y |
|---|
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| b | x | y | r |
|---|
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| b | c | x | y | r |
|---|
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
We think as a group queue
| b | c |
|---|
| x | y |
|---|
| r |
|---|
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
We think as a group queue
| c |
|---|
| x | y |
|---|
| r |
|---|
when popping... pop the element from the top queue of group queue
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
We think as a group queue
| x | y |
|---|
| r |
|---|
when popping... pop the element from the top queue of group queue
when popping... pop the top queue of group queue
if the top queue is empty
UVa 540
Here is the assumption
If two person who both in the same group is in the queue, the must be contiguous.
| groups |
|---|
| a, b, c |
| x, y, z |
| r, v |
We think as a group queue
| x | y |
|---|
| r | v |
|---|
when pushing... check if the group it belongs is in group queue
if yes, push the corresponding queue
if no, push a new group into group queue and push element into that new queue
| a |
|---|
Parentheses matching
if left
put into stack
if right
check if it's match with top
if not
error
if matched
pop
Additional Question
Additional Question
Given an array of integer
ask about the first number on the right of number that greater than this number.
ex. 3 2 1 6 3 7 5 4 2 1 8 9
6 6 6 7 7 8 8 8 8 8 9 -1
Formal input description
the first line is an integer N, N <= 10^7
2nd line contains N integers
3rd line is an integer Q, Q<=10^7
and following Q lines
each line have one integer x, 0<=x<=N-1, represent the index
for each x, output the first element greater than x-th element on the right of x-th element
input:
8
3 2 5 7 4 3 9 1
5
3
2
5
1
4
output:
7
5
9
5
9
int seq[10006];
int ans[10006];
int main(){
cin >> N;
for(int i = 0; i < N; i++){
cin >> seq[i];
}
int Q;
cin >> Q;
int index;
for(int i = 0; i < Q; i++){
cin >> index;
for(int j = index; j < N; j++){
if(seq[j] > seq[index-1]){
cout << seq[j] << endl;
}
if(j == N-1){
cout << -1 << endl;
}
}
}
}What is the time complexity ??
How about we store all answer first?
int seq[10006];
int ans[10006];
int main(){
cin >> N;
for(int i = 0; i < N; i++){
cin >> seq[i];
}
for(int i = 0; i < N; i++){
for(int j = i + 1; j < N; j++){
if(seq[j] > seq[i]){
ans[j] = seq[i];
break;
}
if(j == N-1)
ans[j] = -1;
}
}
int Q;
cin >> Q;
int index;
for(int i = 0; i < Q; i++){
cin >> index;
cout << ans[index-1] << endl;
}
}What is the time complexity ??
Note
For i-th element
any element after it(j > i) but small than i-th element (seq[j] < seq[i])
can't be the answer of any element in front of i-th element
So we can... skip them!
And only record those who is possible be the anwer.
int seq[10006];
int ans[10006];
int main(){
cin >> N;
stack<int> S;
for(int i = 0; i < N; i++){
cin >> seq[i];
}
for(int i = N-1; i < N; i++){
while(!S.empty() && S.top() <= seq[i]){
S.pop();
}
if(S.empty())
ans[i] = -1;
else
ans[i] = S.top();
S.push(seq[i]);
}
int Q;
cin >> Q;
int index;
for(int i = 0; i < Q; i++){
cin >> index;
cout << ans[index-1] << endl;
}
}What is the time complexity ?? How many times does stack pop() operate ?
int seq[10006];
int ans[10006];
int main(){
cin >> N;
stack<int> S;
for(int i = 0; i < N; i++){
cin >> seq[i];
}
for(int i = N-1; i < N; i++){
while(!S.empty() && S.top() <= seq[i]){
S.pop();
}
if(S.empty())
ans[i] = -1;
else
ans[i] = S.top();
S.push(seq[i]);
}
int Q;
cin >> Q;
int index;
for(int i = 0; i < Q; i++){
cin >> index;
cout << ans[index-1] << endl;
}
}Every element only enter stack and pop out stack once
int seq[10006];
int ans[10006];
int main(){
cin >> N;
stack<int> S;
for(int i = 0; i < N; i++){
cin >> seq[i];
}
for(int i = N-1; i < N; i++){
while(!S.empty() && S.top() <= seq[i]){
S.pop();
}
if(S.empty())
ans[i] = -1;
else
ans[i] = S.top();
S.push(seq[i]);
}
int Q;
cin >> Q;
int index;
for(int i = 0; i < Q; i++){
cin >> index;
cout << ans[index-1] << endl;
}
}We can say that it is still O(n)
Stack & Queue
By tunchin kao
Stack & Queue
- 75