Stacks & Queues

Download Report

Transcript Stacks & Queues

Data Structures Part 2
Stacks, Queues, Trees,
and Graphs
Briana B. Morrison
CSE 1302C
Spring 2010
Topics
• Stacks
• Queues
• Trees and Graphs
CSE 1302C
2
Classic Data Structures
• Now we'll examine some classic data
structures
• Classic linear data structures include
queues and stacks
• Classic nonlinear data structures include
trees and graphs
CSE 1302C
3
A Stack Using a Linked List
• A stack is a linear data structure that
organizes items in a last in, first out
(LIFO) manner.
• Items are added and removed from only
one end of a stack
• Analogies: cafeteria trays are typically
organized in a stack, a stack of bills to be
paid
• The tray at the top of the stack was put on
the stack last, and will be taken off the
stack first.
CSE 1302C
4
Stacks
• Stacks often are drawn vertically:
push
CSE 1302C
pop
5
Stacks
• Some stack operations:
– push - add an item to the top of the stack
– pop - remove an item from the top of the stack
– peek (or top) - retrieves the top item without
removing it
– empty - returns true if the stack is empty
• A stack can be represented by a singlylinked list
• A stack can be represented by an array,
but the new item should be placed in the
next available place in the array rather
than at the end
CSE 1302C
6
A Stack can be Implemented
using a Linked List
• In a stack implemented as a linked list:
– To push, we insert at the beginning of the linked
list.
– To pop, we delete the first item in the linked list.
Thus, deletion is not based on value; we always
delete the first item in the list.
CSE 1302C
7
PlayerStackLinkedList Methods
Return value
Method name and argument list
void
push( Player p )
inserts Player p at the top of the stack
Player
pop( )
returns and removes the first Player of the list.
If the list is empty, the method throws a
DataStructureException.
Player
peek( )
returns a copy of the first Player on the list
without deleting it. If the list is empty, the
method throws a DataStructureException.
CSE 1302C
8
A Stack Can be Implemented
using an Array
• If we know in advance the maximum number
of objects on the stack, we can represent the
stack using an array.
– This is easier to implement than a linked list.
• We add items to the stack starting at index 0.
• We maintain an index top, short for top of the
stack.
• The last element inserted is at index top.
CSE 1302C
9
Array Representing a Stack
• There are three items on the stack:
top
CSE 1302C
index
Player object
2
(8, Gino, Diablo )
1
( 7, Sarah, Mario )
0
( 2, Jin, Golf )
10
Stack after Inserting
Player (6, Steve, NFL )
• Now there are four items on the stack:
top
CSE 1302C
index
Player object
3
( 6, Steve, NFL )
2
(8, Gino, Diablo )
1
( 7, Sarah, Mario )
0
( 2, Jin, Golf )
11
Our Stack After Popping Once
• Now there are three items on the stack.
Player ( 6, Steve, NFL ) is not on the stack.
top
CSE 1302C
index
Player object
3
( 6, Steve, NFL )
2
(8, Gino, Diablo )
1
( 7, Sarah, Mario )
0
( 2, Jin, Golf )
12
Instance Variables for Stack
• We will have three instance variables:
– A constant STACK_SIZE, representing the
capacity of the stack.
– An array stack, storing the elements of the stack.
– An int top, representing the top of the stack.
public class ArrayStack
{
private static final int STACK_SIZE = 100;
private Player [] stack;
private int top;
….
}
CSE 1302C
13
Constructor for our Stack
• The constructor does two things:
– It instantiates the array, stack.
– It initializes top to -1 to reflect that the stack is
empty. If top were initialized to 0, then there would
be an element on the stack, at index 0.
public ArrayStack( )
{
stack = new Player[STACK_SIZE];
top = -1; // stack is empty
}
CSE 1302C
14
Utility Methods for our Stack
• We will have three utility methods:
– isEmpty, returning true if the stack is empty.
– isFull, returning true if the stack is full.
– toString, returning a String representation of
the stack.
public bool isEmpty( )
{
return ( top == -1 );
}
public bool isFull( )
{
return ( top == ( STACK_SIZE – 1 ) );
}
CSE 1302C
15
toString Method for our Stack
public String toString( )
{
String stackString = "";
for ( int i = top; i >= 0; i-- )
stackString += ( i + ": "
+ stack[i] + "\n" );
return stackString;
}
CSE 1302C
16
push Method for our Stack
public boolean push( Player p )
{
if ( !isFull( ) )
{
stack[++top] = p;
return true;
}
else
return false;
}
CSE 1302C
17
pop Method for our Stack
public Player pop
{
if ( !isEmpty( ) )
return ( stack[top--] );
else
throw new DSException
( "Stack empty: cannot pop" );
}
CSE 1302C
18
Common Error Trap
• Do not confuse the top of the stack with
the last index in the array. Array
elements with array indexes higher than
top are not on the stack.
CSE 1302C
19
Queues
• A queue is similar to a list but adds items only to
the rear of the list and removes them only from
the front
• It is called a FIFO data structure: First-In, FirstOut
• Analogy: a line of people at a bank teller’s
window
•enqueue
CSE 1302C
•dequeue
20
Queues
• We can define the operations for a queue
– enqueue - add an item to the rear of the queue
– dequeue (or serve) - remove an item from the
front of the queue
– empty - returns true if the queue is empty
• As with our linked list example, by storing
generic Object references, any object can be
stored in the queue
• Queues often are helpful in simulations or any
situation in which items get “backed up” while
awaiting processing
CSE 1302C
21
Queues
• A queue can be represented by a singlylinked list; it is most efficient if the
references point from the front toward
the rear of the queue
• A queue can be represented by an array,
using the remainder operator (%) to
“wrap around” when the end of the array
is reached and space is available at the
front of the array
CSE 1302C
22
A Queue can be Implemented
using a Linked List
• In a queue implemented as a linked list,
we enqueue by inserting at the end of
the linked list.
• In a stack implemented as a linked list,
we dequeue by deleting the first item in
the linked list. Again, deletion is not
based on value; it is based on position.
CSE 1302C
23
A Linked List Class
Implementing a Queue
• Because a queue inserts items at the
end of the list, we will add an instance
variable, tail, (a PlayerNode reference),
representing the last node in the list. In
this way, we do not have to traverse the
list every time we insert an item.
• We will need to update that reference
every time an item is inserted.
CSE 1302C
24
A Linked List Implementing a
Queue
• Here is an example of a queue of Player
objects represented by a linked list.
7
Sarah
Mario
head
CSE 1302C
5
Ajay
Sonic
8
Gino
Diablo
2
Jin
Golf
null
tail
25
Return value
Method name and argument list
void
enqueue( Player p )
inserts Player p at the end of the list
Player
dequeue( )
returns and removes the first Player of the list.
If the list is empty, the method throws a
DataStructureException
Player
peek( )
returns a copy of the first Player on the list
without deleting it. If the list is empty, the method
throws a DataStructureException
CSE 1302C
26
Inserting in a (non-empty) Linked
List Representing a Queue
• Our original list:
7
Sarah
Mario
head
CSE 1302C
5
Ajay
Sonic
8
Gino
Diablo
2
Jin
Golf
null
tail
27
Inserting in a (non-empty) Linked
List Representing a Queue
• Step 1: Instantiate a new node:
PlayerNode pn = new PlayerNode( p );
7
Sarah
Mario
// here, p is Player( 6, Steve, NFL )
5
Ajay
Sonic
8
Gino
Diablo
2
Jin
Golf
head
null
tail
•6
•Steve
•NFL
null
pn
CSE 1302C
28
Inserting in a Linked List
Representing a Queue
• Step 2: Attach the new node at the end
of the list:
tail.setNext( pn );
7
Sarah
Mario
head
CSE 1302C
5
Ajay
Sonic
8
Gino
Diablo
2
Jin
Golf
6
Steve
NFL
null
tail
29
Inserting in a Linked List
Representing a Queue
• Step 3: Update tail:
tail = tail.getNext( );
7
Sarah
Mario
head
CSE 1302C
5
Ajay
Sonic
8
Gino
Diablo
2
Jin
Golf
6
Steve
NFL
null
tail
30
A Linked List Class
Implementing a Queue
• A queue has a front and a back, represented by
head and tail, respectively.
• Could they be inverted, i.e. could head
represent the back of the queue and tail
represent the front of the queue?
• This would be highly inefficient because when
we delete, we would need to traverse the list in
order to update tail.
• Indeed, we cannot go backward in the list from
tail in order to access the next-to-last node
(which becomes tail after the deletion).
CSE 1302C
31
Array Representation of
Queues
• We can also represent a queue using an array.
• The first (inefficient) idea is to represent the
queue with a standard array; two indexes, front
and back, represent the front and back of the
queue.
• To enqueue, we could increment back by 1 and
store the player at array index back.
• To dequeue, we could return the element at
index front and increment front by 1.
• The problem with this approach is that the
number of available elements in the array will
shrink over time.
CSE 1302C
32
Queue after Inserting First 5 Elements
• // Player( 5, Ajay, Sonic ) was enqueued first.
index
7
6
back
front
CSE 1302C
5
4
3
2
1
0
Player object
( 6, Steve, NFL )
(8, Gino, Diablo )
( 7, Sarah, Mario )
( 2, Jin, Golf )
( 5, Ajay, Sonic )
33
Queue after Dequeueing Once
• Element at index 0 is no longer usable.
index
7
6
back
front
CSE 1302C
Player object
5
4
3
2
( 7, Sarah, Mario )
1
( 2, Jin, Golf )
0
( 5, Ajay, Sonic )
( 6, Steve, NFL )
(8, Gino, Diablo )
34
Using a Circular Array
• The solution is to consider the array as a
circular array.
• After back reaches the last array index,
we start enqueueing again at index 0.
• If the array has size 8, the index "after" 7
is 0.
• The useful capacity of the array never
shrinks. If the array has size 8, the
useful capacity of the array is always 8.
CSE 1302C
35
An Empty Queue
CSE 1302C
36
Enqueueing One Element
CSE 1302C
37
Enqueueing a Second
Element
CSE 1302C
38
Enqueueing a Third Element
CSE 1302C
39
Enqueueing a Fourth Element
CSE 1302C
40
Dequeueing Once
CSE 1302C
41
Dequeueing Again
CSE 1302C
42
Full Queue
• In a queue implemented as a circular
array, how do we know when the queue
is full?
• When the queue is full, we have the
following relationship between front and
back:
( back + 1 – front ) % QUEUE_SIZE == 0
CSE 1302C
43
A Full Queue
CSE 1302C
44
Empty Queue
• When the queue is empty, we also have
the same relationship between front and
back!
( back + 1 – front ) % QUEUE_SIZE == 0
CSE 1302C
45
An Empty Queue
CSE 1302C
46
Queue Full or Empty?
• So when
( back + 1 – front ) % QUEUE_SIZE == 0
• Is the queue full or empty? We cannot
tell.
• There is an easy way to solve this
problem: Keep track of the number of
items in the queue.
CSE 1302C
47
Instance Variables for our Queue
• We will have five instance variables:
–
–
–
–
–
A constant representing the capacity of the queue.
An array, storing the elements of the queue.
An int, front, representing the front of the queue.
An int, back, representing the back of the queue.
An int, numberOfItems, storing the number of items in
the queue.
public class ArrayQueue
{
private static final int QUEUE_SIZE = 8;
private Player [] queue;
private int front;
private int back;
private int numberOfItems;
…
}
CSE 1302C
48
Constructor for our Queue
• The constructor does four things:
–
–
–
–
instantiates the array, queue.
initializes front to 0
initializes back to QUEUE_SIZE – 1
initializes numberOfItems to 0 to reflect that
the queue is empty.
public ArrayQueue( )
{
queue = new Player[QUEUE_SIZE];
front = 0;
back = QUEUE_SIZE - 1;
numberOfItems = 0;
}
CSE 1302C
49
Utility Methods for our Queue
• We will have three utility methods:
– isEmpty, returning true if the the queue is empty.
– isFull, returning true if the the queue is full.
– toString, returning a String representation of the queue.
public boolean isEmpty( )
{
return ( numberOfItems == 0 );
}
public boolean isFull( )
{
return ( numberOfItems == QUEUE_SIZE );
}
CSE 1302C
50
public String toString( )
{
String queueString = "";
if ( back >= front )
{
for ( int i = front; i <= back; i++ )
queueString += queue[i] + "\n";
}
else
{
for ( int i = front; i < QUEUE_SIZE; i++ )
queueString += queue[i] + "\n";
for ( int i = 0; i <= back; i++ )
queueString += queue[i] + "\n";
}
return queueString;
}
toString Method for our Queue
CSE 1302C
51
enqueue Method for our
Queue
public boolean enqueue( Player p )
{
if ( !isFull( ) )
{
queue[( back + 1 )% QUEUE_SIZE] = p;
back = ( back + 1 ) % QUEUE_SIZE;
numberOfItems++;
return true;
}
else
return false;
}
CSE 1302C
52
dequeue Method for our
Queue
public Player dequeue
throws DataStructureException
{
if ( !isEmpty( ) )
{
front = ( front + 1 ) % QUEUE_SIZE;
numberOfItems--;
return queue[( QUEUE_SIZE
+ front – 1 ) % QUEUE_SIZE];
}
else
throw new DataStructureException
( "Queue empty: cannot dequeue" );
}
CSE 1302C
53
Common Error
Trap
• Do not confuse array index 0 and
QUEUE_SIZE - 1 with front and back. In
a queue represented by a circular array,
the indexes 0 and QUEUE_SIZE - 1 are
irrelevant.
CSE 1302C
54
Implementing a Stack or a Queue
as an Array vs as a Linked List
Array Linked List
Easily expandable
No
Yes
Direct access to every item
Yes
No
Easy to code
Yes
No
CSE 1302C
55
Trees
• A tree is a non-linear data structure that
consists of a root node and potentially many
levels of additional nodes that form a hierarchy
• Nodes that have no children are called leaf
nodes
• Nodes except for the root and leaf nodes are
called internal nodes
• In a general tree, each node can have many
child nodes
CSE 1302C
56
Binary Trees
• In a binary tree, each node can have no more than
two child nodes
• A binary tree can be defined recursively. Either it is
empty (the base case) or it consists of a root and
two subtrees, each of which is a binary tree
• Trees are typically are represented using
references as dynamic links, though it is possible to
use fixed representations like arrays
• For binary trees, this requires storing only two links
per node to the left and right child
CSE 1302C
57
Tree Example - Starcraft
CSE 1302C
58
Dungeon Siege 2
CSE 1302C
59
Diablo 2
CSE 1302C
60
Fallout 3
CSE 1302C
61
Visiting Every Node
void PrintTree (Node current)
{ if (current != null)
{ Console.WriteLine(current.data)
PrintTree(current.left);
PrintTree(current.right);
}
}
• Of course we could order the 3 statements of
work in any order, visiting the nodes in a
different order.
• Not to be missed: http://oracleofbacon.org/
CSE 1302C
62
Graphs
• A graph is a non-linear structure
• Unlike a tree or binary tree, a graph
does not have a root
• Any node in a graph can be connected
to any other node by an edge
• Analogy: the highway system
connecting cities on a map
CSE 1302C
63
Digraphs
• In a directed graph or digraph, each
edge has a specific direction.
• Edges with direction sometimes are
called arcs
• Analogy: airline flights between airports
CSE 1302C
64
Representing Graphs
• Both graphs and digraphs can be
represented using dynamic links or
using arrays.
• As always, the representation should
facilitate the intended operations and
make them convenient to implement
CSE 1302C
65
Collection Classes
• The C# standard library contains several
classes that represent collections, often
referred to as the Generic Collection
• Their underlying implementation is
implied in the class names such as
ArrayList and LinkedList
CSE 1302C
66
Stacks
• The System.Collections.Generic;
package contains a Stack class
• Like ArrayList operations, the Stack
operations operate on Object
references
CSE 1302C
67
Questions?
CSE 1302C
68