0% found this document useful (0 votes)
127 views67 pages

03 Stqude PDF

Uploaded by

Ray Jia
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
127 views67 pages

03 Stqude PDF

Uploaded by

Ray Jia
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 67

CSI2110

Data Structures
and Algorithms

1
Overview

• Abstract Data Types


• Stack
• Queue
• Deque
– double ended queue : pronounce “deck”
Abstract Data Types (ADTs)

• An Abstract Data Type is an abstraction of a data structure.

The ADT specifies:


– what can be stored in the ADT
– what operations can be done on/by the ADT

• For example, if we are going to model a bag of marbles as an ADT,


we could specify that:
– this ADT stores marbles
– this ADT supports putting in a marble and getting out a marble.
Abstract Data Types (ADTs)

- Specify precisely the operations that can be performed


- The implementation is HIDDEN and can easily change

EXAMPLES

Objects of type: Phone Book


Operations: find, add, remove …
Abstract Data Types (ADTs)

• There are lots of formalized and standard ADTs.

• In this course we are going to learn a lot of


different standard ADTs. (stacks, queues,
dictionary...)
Stacks, Queues, and Deques

ADT Stack
Implementation with Arrays
Implementation with Singly Linked List

ADT Queue
Implementation with Arrays
Implementation with Singly Linked List

ADT Double Ended Queues


Implementation with doubly Linked List
Stacks
PUSH

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

Evaluating an expression with two stacks

( ( (10+5) + 5) / ( (2+3) * 2))

How do we solve it ?
One possible sequence of operations

( ( ( 10+5 ) + 5) / (( 2+3 ) * 2))

( ( 15 + 5) / ( 5 * 2))

( 20 / 10 )

2
Another one

( ( ( 10+5 ) + 5) / (( 2+3 ) * 2))

( (15 + 5) / (( 2+3 ) * 2))

( 20 / (( 2+3 ) * 2))

( 20 / ( 5 * 2))

( 20 / ) 10

2
With two Stacks

One for the operands


One for the operators

( ( (10+5) + 5) / ( (2+3) * 2))

10
+

S1 S2
With two Stacks

One for the operands


One for the operators when find CLOSED parenthesis
( ( 15 + 5) / (( 2+3) * 2))

( ( (10+5) + 5) / ( (2+3) * 2))

POP S1 5

POP S2 +

5
POP S1 10
15
10
+

Evaluate: 10 + 5 = 15
S1 S2
PUSH S1 the result
With two Stacks

One for the operands


One for the operators CLOSED parenthesis
( 20 / (( 2+3) * 2))

( ( (10+5) + 5) / ( (2+3) * 2))

POP S1 5

POP S2 +

5
POP S1 15
20
15 +
Evaluate: 15 + 5 = 20
S1 S2
PUSH S1 the result
With two Stacks

One for the operands


One for the operators CLOSED parenthesis
( 20 / (( 2+3) * 2))

( ( (10+5) + 5) / ( (2+3) * 2))

POP S1 3

POP S2 +
3

5
2 POP S1 2
+
20 /
Evaluate 2+ 3 = 5

S1 S2 PUSH S1 the result


With two Stacks

One for the operands


One for the operators
( 20 / ( 5 * 2))

( ( (10+5) + 5) / ( (2+3) * 2))

20 /

S1 S2
With two Stacks

One for the operands


One for the operators CLOSED parenthesis
( 20 / ( 5 * 2))

( ( (10+5) + 5) / ( (2+3) * 2))

POP S1 2

POP S2 *
2
POP S1 5
10
5 *
Evaluate: 5 * 2 = 10
20 /

S1 S2 PUSH S1 result
With two Stacks

One for the operands


One for the operators CLOSED parenthesis
( 20 / 10 )

( ( (10+5) + 5) / ( (2+3) * 2))

10

10 /

20 / 20

S1 S2 20 / 10= 2
Examples

Checking for balanced parenthesis

{ [ (a+b) -c]/d} { [ a+b) -c]/d}


Example: Evaluation of arithmetic expressions
(Postfix notation)

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’’

/ : pop() (we get t’)


Result = t’/t’’
Implementing a Stack with an Array

The stack consists of an N-element array S and an integer


variable t, the index of the top element in array S.

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

• Limitations What does it mean


O(1) ?

STATIC STRUCTURE we will see the


formal definition
next lecture
Implementing a Stack with a Singly
Linked List

size = 4

-Singly linked list plus a variable containing the


current size of the list

DYNAMIC STRUCTURE
PUSH: Add at the front

POP: Take the first


node:
node.item
node.next top

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”

“radar” “madam i'm adam"


“Able was I ere I saw Elba”

Read the line into a stack and into a queue

Compare the outputs of the queue and the stack

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

Insert at the rear and remove from


front
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

• • •
n-1 0 REAR FRONT
• • 1
• •
2
• Remove: Front = (Front+1) mod n

Insert: Rear = (Rear+1) mod n


• Array in a circular fashion ( “wrapped around”)
• Size fixed at the beginning

•The queue consists of an N-element array Q and


two integer variables:
-f, index of the front element
-r, index of the element after the rear one

n-1 0
1

2
0 1 2 3 4 5 6 7 8 9 10

• • • •
f r
Questions:

What does f = r mean?

The queue is empty

How do we compute the number of elements in


the queue from f and r?
0 1 2 3 4 5 6 7 8 9 10

• • • • • • •

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

Algorithm front(): Algorithm enqueue(o):


if isEmpty() then if size = N - 1 then
ERROR ERROR
return Q[f] Q[r] ← o
Performance

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

First element (easy) h ← h.Next

Element after r (easy) r.Next ← r.Next.Next

• Use a pointer to the preceding element, or


• Exchange the contents of the element at r with
Element at r (difficult) the contents of the element following r, and delete
The element after r. **Very difficult if r points to the
last element! 54
Removing at the Head
Inserting at the Tail
Performance

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

Deletions at the tail of a singly linked list cannot be done efficiently

header trailer

To implement a deque, we use a doubly linked list


with special header and trailer nodes
•The header node goes before the first list element. It has a valid next link but
a null prev link.

•The trailer node goes after the last element. It has a valid prev reference but
a null next reference.

header trailer

NOTE: the header and trailer nodes


are sentinel or “dummy” nodes because
they do not store elements.
insertFirst(e):

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

Stacks with Deques:

Queues with Deques:


Java implementation of Doubly Linked List

A node of a doubly linked list has a next and a prev link.

The doubly linked list supports the following methods:

•setElement(Object e)
•setNext(Object newNext)
•setPrev(Object newPrev)
•getElement()
•getNext()
•getPrev()

You might also like