03 Stqude PDF
03 Stqude PDF
Data Structures
and Algorithms
1
Overview
EXAMPLES
ADT Stack
Implementation with Arrays
Implementation with Singly Linked List
ADT Queue
Implementation with Arrays
Implementation with Singly Linked List
POP
The Stacks
• A stack is a container for inserting and removing objects according to the principle, the last
entered element, first go out. (last-in-first-out, or LIFO)
• The objects can be inserted all together, but only the last element (the most recently
inserted) can be removed.
• Analogue: PEZ® dispenser
The Stack Abstract Data Type
• Main methods:
– push(o): Inserts object o onto top of stack
– pop(): Removes the top object of stack and returns it;
if the stack is empty, an error occurs
• Support methods:
– size(): Returns the number of objects in stack
– isEmpty(): Return a boolean indicating if stack is empty.
– top(): Return the top object of the stack, without
removing it; if the stack is empty, an error
occurs.
Applications of Stacks
• Direct applications
– Page-visited history in a Web browser
– Undo sequence in a text editor
– Chain of method calls in the Java Virtual
Machine
• Indirect applications
– Auxiliary data structure for algorithms
– Component of other data structures
Examples
How do we solve it ?
One possible sequence of operations
( ( 15 + 5) / ( 5 * 2))
( 20 / 10 )
2
Another one
( 20 / (( 2+3 ) * 2))
( 20 / ( 5 * 2))
( 20 / ) 10
2
With two Stacks
10
+
S1 S2
With two Stacks
POP S1 5
POP S2 +
5
POP S1 10
15
10
+
Evaluate: 10 + 5 = 15
S1 S2
PUSH S1 the result
With two Stacks
POP S1 5
POP S2 +
5
POP S1 15
20
15 +
Evaluate: 15 + 5 = 20
S1 S2
PUSH S1 the result
With two Stacks
POP S1 3
POP S2 +
3
5
2 POP S1 2
+
20 /
Evaluate 2+ 3 = 5
20 /
S1 S2
With two Stacks
POP S1 2
POP S2 *
2
POP S1 5
10
5 *
Evaluate: 5 * 2 = 10
20 /
S1 S2 PUSH S1 result
With two Stacks
10
10 /
20 / 20
S1 S2 20 / 10= 2
Examples
Infix Postfix
A + B A B +
(x – y)/(u + v)
(x – y) ( u+ v) /
xy- uv+ /
INFIX POSTFIX
a+b ab+
(x – y + z) xy–z+
(x – y – z)/(u + v) xy–z–uv+/
In general:
A operator B
A B operator
xy–z–uv+/
x: push(x)
y: push(y)
x
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y)
x
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x)
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x) push(t)
z: push(z)
t
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x) push(t)
z: push(z)
– : pop() (we get z)
t
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x) push(t)
z: push(z)
– : pop() (we get z)
pop() (we get t)
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x) push(t)
v z: push(z)
– : pop() (we get z)
u
pop() (we get t)
t – z = t’
t’ push(t’)
u: push(u)
v: push(v)
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x) push(t)
z: push(z)
– : pop() (we get z)
u
pop() (we get t)
t – z = t’
t’ push(t’)
u: push(u)
v: push(v)
+ : pop() (we get v)
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x) push(t)
z: push(z)
– : pop() (we get z)
pop() (we get t)
t – z = t’
t’ push(t’)
v: push(v)
+ : pop() (we get v)
pop() (we get u) u+v = t’’
xy–z–uv+/
x: push(x)
y: push(y)
– : pop() (we get y) x–y =t
pop() (we get x) push(t)
z: push(z)
– : pop() (we get z)
pop() (we get t)
t – z = t’
push(t’)
v: push(v)
+ : pop() (we get v)
pop() (we get u) u+v = t’’
Algorithm size():
return t +1
Algorithm isEmpty():
return (t < 0)
Algorithm top():
if isEmpty() then
ERROR
return S[t]
Algorithm push(obj):
if size() = N then
ERROR
t←t+1
S[t] ← obj Algorithm pop():
if isEmpty() then
ERROR
e ← S[t]
S[t] ← null
t ← t-1
return e
Performance and Limitations
Time
size() O(1)
• Performance isempty() O(1) Space: O(n)
top() O(1)
push(obj) O(1) n = size of
pop() O(1) the Array
size = 4
DYNAMIC STRUCTURE
PUSH: Add at the front
Algorithm push(obj):
n ← new Node n
n.item ← obj
n.next ← top
top ← n
size++
Algorithm pop():
if isEmpty() then
top ERROR
temp ← top.item
top ← top.next
size- -
return temp
temp
Performance
Time:
size() O(1)
isempty() O(1)
top() O(1)
push(obj) O(1)
pop() O(1) Space: Variable
The Queue
The Queue
first-in-first-out (FIFO)
•A queue is different from a stack in the way how the insertion and removal
work.
•The elements can be inserted all together, but only the element which stayed
longest time in the queue can be out.
•Elements are inserted at the rear (enqueued) and removed from the front
(dequeued)
Applications of Queues
• Direct applications
– Waiting lists, bureaucracy
– Access to shared resources (e.g., printer)
– Multiprogramming
• Indirect applications
– Auxiliary data structure for algorithms
– Component of other data structures
Fun Example: Palindromes
“eye” “madam”
r
r a d a r a
Q d
a
r S
The Queue Abstract Data Type
• Fundamental methods:
enqueue(o): Insert object o at the rear of the queue
dequeue(): Remove the object from the front of the queue and return it; an
error occurs if the queue is empty
• Support methods:
size(): Return the number of objects in the queue
isEmpty(): Return a boolean value that indicates whether the queue is empty
front(): Return, but do not remove, the front object in the queue; an error
occurs if the queue is empty
Implementing a Queue with an Array
0 1 2 3 4 5 6 7 8 9 10
• • • •
FRONT REAR
0 1 2 3 4 5 6 7 8 9 10
• • • •
FRONT REAR
0 1 2 3 4 5 6 7 8 9 10
• • •
n-1 0 REAR FRONT
• • 1
• •
2
• Remove: Front = (Front+1) mod n
n-1 0
1
2
0 1 2 3 4 5 6 7 8 9 10
• • • •
f r
Questions:
• • • • • • •
r f
(N - f + r) mod N
In the example:
(11 - 8 + 4) mod 11 = 7
Algorithm dequeue():
Algorithm size(): if isEmpty() then
return (N - f + r) mod N ERROR
temp ← Q[f]
Q[f] ← null
Algorithm isEmpty(): f ← (f + 1) mod N
return (f = r) return temp
Time:
Space: O(N)
size() O(1)
isempty() O(1)
front() O(1)
enqueue(o) O(1)
dequeue() O(1)
Implementing a Queue with a Singly
Linked List
Nodes connected in singly linked list
We keep a pointer to the head and one to the tail
The head of the list is the front of the queue, the tail of the list is the
rear of the queue.
Why not the opposite?
From the last lesson : Deletion
r
(Deleting the element after r)
h
NULL
Time:
size() O(1)
isempty() O(1)
front() O(1)
Space: Variable
enqueue(o) O(1)
dequeue() O(1)
If we know in advance a reasonable
upper bound for the number of
elements in the queue, then
ARRAYS
Otherwise
LISTS
A more general ADT:
Double-Ended Queues (Deque)
A double-ended queue, or deque, supports insertion and deletion from the front and
back.
Main methods:
insertFirst(e): Insert e at the beginning of deque.
insertLast(e): Insert e at end of deque
removeFirst(): Removes and returns first element
removeLast(): Removes and returns last element
Support methods:
first()
last()
size()
isEmpty()
Implementing Deques with Doubly Linked
Lists
header trailer
•The trailer node goes after the last element. It has a valid prev reference but
a null next reference.
header trailer
header trailer
e.next ← header.next
header.next ← e
e.prev ← header
e.next.prev ← e
removeFirst():
header trailer
header.next.next.prev ← header
header.next ← header.next.next
OR:
header.next ← header.next.next
header.next.prev ← header
Here’s a visualization
of the code for
removeLast().
With this implementation, all methods have constant execution time ( complexity
O(1))
Implementing Stacks and Queues with Deques
•setElement(Object e)
•setNext(Object newNext)
•setPrev(Object newPrev)
•getElement()
•getNext()
•getPrev()