0% found this document useful (0 votes)
20 views

CSCI1933 Lecture10

Uploaded by

Michael Zhang
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

CSCI1933 Lecture10

Uploaded by

Michael Zhang
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 131

Csci 1933: Introduction to

Algorithms and Data Structures


Spring 2022
Announcements

• Lab 9 milestones due tomorrow (4/1)

• Midterm 2 is 1 week from today!


(Thursday, 4/7)
Midterm 2
• Thursday, April 7, 6:30-8:30pm
• Closed book, closed computer
• You are allowed 1 page (8.5” x 11”)
(2 sides) of handwritten notes

• Time limit: 2 hrs

• Example midterm + list of topics is posted


on Canvas
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


Brief review of key concepts covered last time
Array vs. linked list “List”
implementations
Array: fixed size, each position is directly addressable

Linked list:
• List is organized by keeping track of start (or end) only
• Each element of the list knows about the next element in the list
Comparison of array and linked list List
implementations

• Which is better?
– Space?
• Array List: wastes memory for each unfilled
slot in the array
• Linked List: only create one node per element,
BUT requires memory overhead of links
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Time complexity?
• getEntry (int position)
• Array List: ?
• Linked List: ?

Exercise: what is the worst-case time


complexity?
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Time complexity?
• getEntry (int position)
• Array List: O(1) (doesn’t depend on the size of the
array)
• Linked List: requires traversal of all preceding elements
(worst-case: last element, complexity ~ O(N))
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Time complexity?
• remove(int position)
• Array List: ?
• Linked List: ?

Exercise: what is the worst-case time


complexity?
Comparison of array and linked list List
implementations
• Which is better?
Assume N elements– what’s the number of operations in the worst case?

– Speed?
• remove(int position)
• Array List: needs reshuffling (worst case: first
element, complexity ~ O(N))
• Linked List: simply “rewire” links in constant time,
but we still need to find this element (worst case:
last element, complexity ~O(N))
Summary of array-based List implementation

• Advantages?
• Retrieving an entry is fast
• Adding an entry at the end of the list is fast
• Arrays are a natural way of thinking about lists of elements
(easy to program?)
• Disadvantages?
• Adding or removing an entry that is between other
entries requires shifting elements in the array (potentially
slow)
• Increasing the size of the array or vector requires
copying elements (potentially slow)
Summary of Pros and Cons of a linked list
implementation
• The linked list can grow as large as necessary
• Can add and remove nodes without shifting existing
entries
But …
• Must traverse a chain to determine where to make
addition/deletion
• Retrieving an entry requires traversal
– As opposed to direct access in an array
• Requires more memory for links
– But does not waste memory for oversized array
Exception example
public class FileReader {
public FileReader() {
}

public String readSequenceFromFile(String filename) {


//Getting input from a text file
String result = "";
try {
File f = new File(filename);
Scanner fileInput = new Scanner(f);

while (fileInput.hasNext()) {
result = result + fileInput.nextLine();
}
} catch(FileNotFoundException e) {
System.out.println("Sorry, can't find file!");
System.out.println(e.getMessage());
System.exit(1);
}

return result;
}
}

Main:
FileReader seqFile = new FileReader();

String sequence = seqFile.readSequenceFromFile(“yeast_chr16_genomesequence.txt");


System.out.println(sequence);
Another option: pass the exception upward
public String readSequenceFromFileVer2(String filename)
throws FileNotFoundException {
//Getting input from a text file
String result = "";
File f = new File(filename);
Scanner fileInput = new Scanner(f);

while (fileInput.hasNext()) {
result = result + fileInput.nextLine();
}

return result;
}

Now main needs to look like this:


try {
sequence =
seqFile.readSequenceFromFileVer2(“yeast_chr16_genomesequence.txt");
System.out.println(sequence);
} catch(FileNotFoundException e) {
System.out.println("Sorry, can't find file!");
System.out.println(e.getMessage());
System.exit(1);
}

The exception must be caught at some point!


Iterator interface
• An Iterator is an object that enables you to traverse
through a collection and to remove elements from the
collection selectively, if desired. You get an Iterator for a
collection by calling its iterator() method. The following
is the Iterator interface.

public interface Iterator<E> {


boolean hasNext();
E next();
void remove(); //optional
}

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Iterator.html
Array-Based Implementation

The array of list entries and nextIndex (a) just before the call to
next; (b) just after the call to next but before the call to remove;
(c) after the call to remove
Carrano and Henry, Data Structures and Abstractions with Java.
How would we implement an iterator?
• Could be implemented in a separate class,
pass a referece to the data structure on which
we want to iterate See Textbook Ch. 13
for an example of this

• Could be implemented in an inner class

• Could be implemented as part of the ADT


itself (e.g. add methods that provide this
functionality)
Behavior of a Stack ADT
• Last in, first out (LIFO)
(not first-in, first-out)

• Note: cannot access elements that aren’t at the top


• Like a packed elevator loading/unloading
“pop”
“push”
“pop”
“push”
“push”
“push”

Carrano and Henry, Data Structures and Abstractions with Java.


Stack specifications
• Data:
– Collection of objects in reverse chronological
order, all having the same type
• Operations:
push(newEntry) Pushes newEntry onto top of stack
pop() Removes element from the top and returns it
peek() Returns element at the top (doesn’t modify stack)
isEmpty() Checks if stack is empty
clear() Clears the stack
Stack exercise: reversing a string

• Write code that uses a stack to reverse a string


– Operations: push, pop, isEmpty
public static String reverseString(String str) {
Stack<Character> st = new Stack<Character>();

char[] chars = str.toCharArray();


String rev = "";

for(char c:chars) {
st.push(c);
}

while(!st.isEmpty()) { rev += st.pop(); }


return rev;
}
New material
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


Stack exercise: checking an expression for
proper use of brackets/parentheses

• Write pseudocode that uses a stack to check a string


(e.g. Java code) for proper use of brackets ( any of (, [,
{ )
– Brackets must be properly matched with each
other (-) {-} [-]
– Brackets must be balanced (i.e. no open blocks)
Example inputs:
while(n > 0) { while(n > 0) {
myStack.push(n); myStack.push(n;
n--; n--;
} }
Pseudocode for bracket checker

Create an empty stack

Traverse the string with the expression to be checked


- If the current character is a starting bracket (‘(‘ or ‘{‘ or ‘[‘),
then push it to stack.

- If the current character is a closing bracket (‘)’ or ‘}’ or ‘]’),


then pop from stack, check if the current char matches what was
popped, if they don’t matcherror!

After complete traversal, if there are any starting brackets left in the stack–> not
balanced
Check our solution on our example
Create an empty stack

Traverse the string with the expression to be checked


- If the current character is a starting bracket (‘(‘ or ‘{‘ or ‘[‘),
then push it to stack.

- If the current character is a closing bracket (‘)’ or ‘}’ or ‘]’),


then pop from stack, check if the current char matches what was popped, if they don’t
matcherror!

After complete traversal, if there are any starting brackets left in the stack–> not balanced

while(n > 0) { while(n > 0) {


myStack.push(n); myStack.push(n;
n--; n--;
} }
Formalizing Stack ADT specs
public interface StackInterface<T>
{
/** Task: Adds a new entry to the top of the stack.
* @param newEntry an object to be added to the stack */
public void push(T newEntry);

/** Task: Removes and returns the stack’s top entry.


* @return either the object at the top of the stack or, if the
* stack is empty before the operation, null */
public T pop();

/** Task: Retrieves the stack’s top entry.


* @return either the object at the top of the stack or null if
* the stack is empty */
public T peek();

/** Task: Detects whether the stack is empty.


* @return true if the stack is empty */
public boolean isEmpty();

/** Task: Removes all entries from the stack */


public void clear();
} // end StackInterface
Now, let’s think about a Stack
implementation
Note: we’ve already experimented with the ADT before even talking
about how it was implemented

push(newEntry) Let’s try:


pop()
peek() • linked lists
isEmpty() • arrays
clear()
Stack implementation
• Let’s sketch a solution using:
• Linked lists
• Arrays
• No code yet– just rough idea of structure
A Linked Stack implementation
When using a chain of linked nodes to
implement a stack
The first node should reference the stack's top

Carrano and Henry, Data Structures and Abstractions with Java.


An Array-Based Stack Implementation

An array that implements a stack; its first location references


the bottom of the stack

Carrano and Henry, Data Structures and Abstractions with Java.


Now, let’s write some code
Stack ADT interface
push(newEntry) Pushes newEntry onto top of stack
pop() Removes element from the top and returns it
peek() Returns element at the top (doesn’t modify stack)
isEmpty() Checks if stack is empty
clear() Clears the stack
public class LinkedStack<T> implements StackInterface<T> {
...

(Slightly) updated Node class


private class Node {
private T data; // Entry in list
private Node next; // Link to next node
private Node(T dataPortion) {
(using getter/setter methods)
data = dataPortion;
next = null;
} // end constructor
private Node(T dataPortion, Node nextNode) {
data = dataPortion;
next = nextNode;
} // end constructor
private T getData()
{
return data;
} // end getData

private Node getNextNode()


private void setData(T newData) {
return next;
{ data = newData;} // end setData } // end getNextNode
}
private void setNextNode(Node nextNode)
{
next = nextNode;
} // end setNextNode
} // end Node
} //end LinkedStack
LinkedStack class implementation
The “easy” methods:

public boolean isEmpty()


{
return topNode == null;
} // end isEmpty

public void clear()


{
topNode = null;
} // end clear
LinkedStack class implementation

public void push(T newEntry) Pushes newEntry onto top of


stack

public T pop() Removes element from the top


and returns it
Returns element at the top
public T peek() (doesn’t modify stack)

Remember the process:


(1) What are the different cases? (before: empty list, middle of list, …)
(2) How do we detect the cases? (condition)
(3) How do we handle the cases? (logic of update)
Linked Stack implementation: logic
for “push”

(a) A new node that references the top of the stack; (b) the
new node is now at the top of the stack.
Carrano and Henry, Data Structures and Abstractions with Java.
Linked Stack implementation: logic
for “pop”

The stack (a) before the first node in the chain is


deleted
Carrano and Henry, Data Structures and Abstractions with Java.
Data member:
public void push(T newEntry) private Node topNode;
{ (Node has getData, setData,
getNextNode, and setNextNode
} methods)

Use java.util.EmptyStackException
public T peek()
{

}
public T pop()
{

}
public void push(T newEntry) Data member:
{ private Node topNode;
topNode = new Node(newEntry, topNode); (Node has getData, setData,
getNextNode, and setNextNode
}
methods)
Use java.util.EmptyStackException

public T peek()
{

}
public T pop()
{

}
public void push(T newEntry) Data member:
{ private Node topNode;
topNode = new Node(newEntry, topNode); (Node has getData, setData,
getNextNode, and setNextNode
}
methods)

public T peek()
{
if (isEmpty())
throw new EmptyStackException();
else
return topNode.getData();
}
public T pop()
{

}
public void push(T newEntry) Data member:
{ private Node topNode;
topNode = new Node(newEntry, topNode); (Node has getData, setData,
getNextNode, and setNextNode
}
methods)
Use java.util.EmptyStackException

public T peek()
{
if (isEmpty())
throw new EmptyStackException();
else
return topNode.getData();
}
public T pop()
{
T top = peek();

topNode = topNode.getNextNode();

return top;
}
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


Now: Array-Based Stack
Implementation

An array that implements a stack; its first location references


the bottom of the stack

Carrano and Henry, Data Structures and Abstractions with Java.


A skeleton for the ArrayStack class

(see ArrayStack.java)

...
ArrayStack class implementation
The “easy” methods:
public boolean isEmpty()
{
return topIndex < 0;
} // end isEmpty

public void clear()


{
checkIntegrity();

while (topIndex > -1)


{
stack[topIndex] = null;
topIndex--;
}

}
ArrayStack class implementation

public void push(T newEntry) Pushes newEntry onto top of


stack

public T pop() Removes element from the top


and returns it
Returns element at the top
public T peek() (doesn’t modify stack)

Remember the process:


(1) What are the different cases? (before: empty list, middle of list, …)
(2) How do we detect the cases? (condition)
(3) How do we handle the cases? (logic of update)
Array Stack implementation: logic for “push”
4

4
4

Carrano and Henry, Data Structures and Abstractions with Java.


Array Stack implementation: logic
for “pop”

Another array-based stack after top removed by (a)


decrementing topIndex;
Carrano and Henry, Data Structures and Abstractions with Java.
Array Stack implementation: logic
for “pop”

Another array-based stack after top removed by (b)


setting stack[topIndex]=null and then
decrementing topIndex
Carrano and Henry, Data Structures and Abstractions with Java.
public void push(T newEntry)
{ Data members:
checkIntegrity(); private T[] stack;
ensureCapacity(); private int topIndex;

??

} // end push

(like ArrayList, ensureCapacity() method doubles the array when it’s full)
public T peek()
{
checkIntegrity();
??

public T pop()
{
checkIntegrity(); }
??

}
public void push(T newEntry)
{ Data members:
checkIntegrity(); private T[] stack;
ensureCapacity(); private int topIndex;
stack[topIndex + 1] = newEntry;
topIndex++;

} // end push

(assume you have access to ensureCapacity() method


which will double the array when it’s full) public T peek()
{
checkIntegrity();
if (isEmpty())
throw new EmptyStackException();
public T pop() else
{ return stack[topIndex];
checkIntegrity(); }
if (isEmpty())
throw new EmptyStackException();
else
{
T top = stack[topIndex];
stack[topIndex] = null;
topIndex--;
return top;
}
}
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


Comparison of linked vs. array-based
stack
Linked Stack
- advantages?
- disadvantages?

Array Stack
- advantages?
-disadvantages?
Exercise: what is the time complexity
of various stack operations?

public void push(T newEntry)

public T pop()

public T peek()

(1) Linked list implementation?


(2) Array implementation?
Exercise: what is the time complexity
of various stack operations?

public void push(T newEntry) Array: O(N) (if we have to


double array size)
LList: O(1)
public T pop() Array: O(1)
LList: O(1)

public T peek() Array: O(1)


LList: O(1)

(1) Linked list implementation?


(2) Array implementation?
public void push(T newEntry) Data member:
{ private Node topNode;
topNode = new Node(newEntry, topNode); (Node has getData, setData,
getNextNode, and setNextNode
}
methods)
Use java.util.EmptyStackException

public T peek()
Linked list implementation {
if (isEmpty())
throw new EmptyStackException();
else
return topNode.getData();
}
public T pop()
{
T top = peek();

topNode = topNode.getNextNode();

return top;
}
public void push(T newEntry)
{ Data members:
checkIntegrity(); private T[] stack;
ensureCapacity(); private int topIndex;
stack[topIndex + 1] = newEntry;
topIndex++;

} // end push

Array implementation public T peek()


{
checkIntegrity();
if (isEmpty())
throw new EmptyStackException();
public T pop() else
{ return stack[topIndex];
checkIntegrity(); }
if (isEmpty())
throw new EmptyStackException();
else
{
T top = stack[topIndex];
stack[topIndex] = null;
topIndex--;
return top;
}
}
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


The queue abstract data type
Behavior of the Queue ADT
A Queue organizes entries according to order of entry
• Exhibits first-in, first-out behavior (FIFO)
• Contrast to stack which is last-in, first-out (LIFO)
All additions are at the back of the queue
Front of queue has items that were added first (e.g. ready for
serving/processing)

Carrano and Henry, Data Structures and Abstractions with Java.


Queues in everyday life

Carrano and Henry, Data Structures and Abstractions with Java.


Queue specifications
Data:
Collection of objects in chronological order having
the same type
Operations:
enqueue(newEntry) Adds newEntry to the back of the queue
dequeue() Removes and returns the entry at the front of the queue
getFront() Returns entry at the front (doesn’t modify queue) (like peek)
Checks if queue is empty
isEmpty()
Clears the queue
clear()
Experimenting with a simple queue of
strings
Op: enqueue “Jim”

Op: enqueue “Jess”

Op: enqueue “Jill”

Op: enqueue “Jane”

Carrano and Henry, Data Structures and Abstractions with Java.


Experimenting with a simple queue of
strings
Op: enqueue “Joe”

Op: dequeue

Op: enqueue “Jerry”

Op: dequeue

Carrano and Henry, Data Structures and Abstractions with Java.


Exercise: a simple queue of Strings

QueueInterface<String> q = new LinkedQueue<String>();


q.enqueue(“A”);
q.enqueue(“B”);
q.enqueue(“C”);
q.enqueue(“D”);
q.enqueue(q.dequeue());
System.out.println(q.getFront());
System.out.println(q.dequeue());
System.out.println(q.dequeue());

Exercise: draw the queue at each step, and write the output of the
print statements
Why are queues important?
One important example: CPU job scheduling
Scheduler

Job Queue
Jobs

J0
J1
CPUs/Cores
J2
.
.
.

Typically uses a scheduling algorithm more complex than first-


come, first-served (FIFO), but this is the basic data structure
behind CPU scheduling
Another “real-world” application
of queues
Discrete event simulation
• Customer service modeling (optimizing
process to reduce wait time, how many web
servers do we need?, etc.)
• Network simulations (e.g. routing protocol
evaluation)
• Infectious disease/response modeling
• Stock market investment strategies
• Traffic modeling, etc
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


Implementation of a Queue ADT
Note: we’ve already talked about how to use a queue to
solve a problem without even discussing implementation
 abstraction!

Now, we’ll discuss implementation:


• Queue
• Linked list
• Array-based
• Deque
• Doubly-linked list
Formal specification of the Queue
interface
public interface QueueInterface<T>
{
/** Task: Adds a new entry to the back of the queue.
* @param newEntry an object to be added */
public void enqueue(T newEntry);

/** Task: Removes and returns the entry at the front of the queue.
* @return either the object at the front of the queue or, if the
* queue is empty before the operation, null */
public T dequeue();

/** Task: Retrieves the entry at the front of the queue.


* @return either the object at the front of the queue or, if the
* queue is empty, null */
public T getFront();

/** Task: Detects whether the queue is empty.


* @return true if the queue is empty, or false otherwise */
public boolean isEmpty();

/** Task: Removes all entries from the queue. */


public void clear();
} // end QueueInterface
First: a linked implementation of a
queue ADT

How can we use a linked list structure to


implement a queue?

No code yet, what’s the basic idea?


A Linked Implementation of a Queue

A linked list with a tail reference!

Carrano and Henry, Data Structures and Abstractions with Java.


A skeleton for the LinkedQueue class
public class LinkedQueue<T> implements QueueInterface<T> {
private Node firstNode; // references node at front of queue
private Node lastNode; // references node at back of queue

public LinkedQueue()
{
firstNode = null;
lastNode = null;
} // end default constructor

// < Implementations of the queue operations go here. >


// . . .

private class Node


{
private T data; // entry in queue
private Node next; // link to next node

// < Constructors and the methods getData, setData, getNextNode, and


setNextNode
// are here. >
// . . .

} // end Node
} // end LinkedQueue
LinkedQueue class implementation

public void enqueue(T newEntry); Adds newEntry to the back of the queue
public T dequeue(); Removes and returns the entry at the front of the queue

public T getFront(); Returns entry at the front (doesn’t modify queue)


public boolean isEmpty(); Checks if queue is empty
public void clear();
Clears the queue
Do these on your own

Remember the process:


(1) What are the different cases? (before: empty list, middle of list, …)
(2) How do we detect the cases? (condition)
(3) How do we handle the cases? (logic of update)
LinkedQueue “enqueue” operation logic

Case 1: adding an element to an empty queue

(a) Before adding a new node to an empty queue (b) after


adding to it.

Carrano and Henry, Data Structures and Abstractions with Java.


LinkedQueue “enqueue” operation logic
Case 2: adding an element to an non-empty queue

(a) Before adding a new node to the end of the queue; (b) after adding it.

Carrano and Henry, Data Structures and Abstractions with Java.


public void enqueue(T newEntry) Data members:
{ private Node firstNode;
private Node lastNode;
(Node has getData, setData,
getNextNode, and setNextNode
methods)

} // end enqueue public T dequeue()


{

} // end dequeue
public void enqueue(T newEntry) Data members:
{ private Node firstNode;
Node newNode = new Node(newEntry, null); private Node lastNode;
(Node has getData, setData,
getNextNode, and setNextNode
if (isEmpty()) methods)
firstNode = newNode;
else
lastNode.setNextNode(newNode);

lastNode = newNode;
} // end enqueue

public T dequeue()
{

} // end dequeue
LinkedQueue “dequeue” operation logic
Case 1: removal of the element leaves an empty queue

(a) A queue of one entry; (b) after removing the queue's front.

Carrano and Henry, Data Structures and Abstractions with Java.


LinkedQueue “dequeue” operation logic
Case 2: removal of the element leaves a non-empty queue

(a) A queue of more than one entry; (b) after removing the queue's
front.
Carrano and Henry, Data Structures and Abstractions with Java.
public void enqueue(T newEntry) Data members:
{ private Node firstNode;
Node newNode = new Node(newEntry, null); private Node lastNode;
(Node has getData, setData,
getNextNode, and setNextNode
if (isEmpty()) methods)
firstNode = newNode;
else
lastNode.setNextNode(newNode);

lastNode = newNode;
} // end enqueue

public T dequeue()
{

} // end dequeue
public void enqueue(T newEntry) Data members:
{ private Node firstNode;
Node newNode = new Node(newEntry, null); private Node lastNode;
(Node has getData, setData,
getNextNode, and setNextNode
if (isEmpty()) methods)
firstNode = newNode;
else
lastNode.setNextNode(newNode);

lastNode = newNode;
} // end enqueue

public T dequeue()
{
T front = getFront(); //throws except. if empty

firstNode = firstNode.getNextNode();

if (firstNode == null)
lastNode = null;

return front;

} // end dequeue
public void enqueue(T newEntry) Data members:
{ private Node firstNode;
Node newNode = new Node(newEntry, null); private Node lastNode;
(Node has getData, setData,
getNextNode, and setNextNode
if (isEmpty()) methods)
firstNode = newNode;
else
lastNode.setNextNode(newNode);

lastNode = newNode;
} // end enqueue

public T dequeue()
{
T front = getFront(); //throws except. if empty
Pop quiz:
firstNode = firstNode.getNextNode();
What’s the time complexity of these
operations? if (firstNode == null)
lastNode = null;

return front;

} // end dequeue
Now: Array-based implementation
of queue

How can we use an array to


implement a queue?

No code yet, what’s the basic idea?


What are the challenges of
representing a queue with an array?
What are the challenges of
representing a queue with an array?
What are the challenges of
representing a queue with an array?

This implementation would be much simpler to deal with if we just


shuffled all elements to the front of the array– why is this a bad idea?
The solution: use a circular array!
When queue reaches end of array
Add subsequent entries to beginning
Array behaves as though it were circular
First location follows last one
Use modulo arithmetic on indices
backIndex = (backIndex + 1) % queue.length

Carrano and Henry, Data Structures and Abstractions with Java.


Array-Based Implementation of a Queue: a “circular array”

An array that represents a queue without shifting its entries:


(a) initially; (b) after removing the front twice;

Carrano and Henry, Data Structures and Abstractions with Java.


Array-Based Implementation of a Queue: a “circular array”

An array that represents a queue without shifting its entries:


(c) after several more additions & removals; (d) after two
additions that wrap around to the beginning of the array

Carrano and Henry, Data Structures and Abstractions with Java.


Question: how will we detect when it’s
full?

Carrano and Henry, Data Structures and Abstractions with Java.


Question: how will we detect
when it’s empty?

Carrano and Henry, Data Structures and Abstractions with Java.


Question: how will we detect
when it’s empty/full?

Note: with circular array:


How can we fix
frontIndex == backIndex + 1
this?
both when queue is empty and when full
Carrano and Henry, Data Structures and Abstractions with Java.
Solution: A Circular Array with
One Unused Location
A seven-location
circular array that
contains at most six
entries of a queue

Full condition:
frontIndex ==
(backIndex + 2)% length

Allows us to distinguish
between empty and full queue

Carrano and Henry, Data Structures and Abstractions with Java.


A Circular Array with
One Unused Location

A seven-location
circular array that
contains at most six
entries of a queue.

Empty condition:
frontIndex ==
(backIndex + 1)% length

Carrano and Henry, Data Structures and Abstractions with Java.


Array-based Queue implementation

public void enqueue(T newEntry); Adds newEntry to the back of the queue
public T dequeue(); Removes and returns the entry at the front of the queue

public T getFront(); Returns entry at the front (doesn’t modify queue)


public boolean isEmpty(); Checks if queue is empty
public void clear();
Clears the queue
A skeleton for the ArrayQueue class

// < Implementations of the queue operations go here. >


// . . .

} // end ArrayQueue
First, the easy ones
• isEmpty() ?
public boolean isEmpty()
{
checkIntegrity();
return frontIndex == ((backIndex + 1) % queue.length);
} // end isEmpty
Handling a full queue: ensureCapacity() method

Doubling the size of an array-based queue

Carrano and Henry, Data Structures and Abstractions with Java.


Handling a full queue: ensureCapacity() method
public void enqueue(T newEntry) Data members:
{ private T[] queue;
private int frontIndex;
private int backIndex

(use ensureCapacity()
method )

} // end enqueue

public T dequeue()
{

} // end dequeue
public void enqueue(T newEntry) Data members:
{ private T[] queue;
checkIntegrity(); private int frontIndex;
ensureCapacity(); private int backIndex
backIndex = (backIndex + 1) %queue.length;
//Index of location after current back of queue (use ensureCapacity()
queue[backIndex] = newEntry;
method )
} // end enqueue

public T dequeue()
{

} // end dequeue
Dequeue logic

An array-based queue: (a) initially; (b) after removing its


front by incrementing frontIndex;
Carrano and Henry, Data Structures and Abstractions with Java.
Dequeue logic

An array-based queue: (c) after removing its front by setting


queue[frontIndex] to null, then incrementing frontIndex.

Carrano and Henry, Data Structures and Abstractions with Java.


public void enqueue(T newEntry) Data members:
{ private T[] queue;
checkIntegrity(); private int frontIndex;
ensureCapacity(); private int backIndex
backIndex = (backIndex + 1) %queue.length;
//Index of location after current back of queue (use ensureCapacity()
queue[backIndex] = newEntry;
method )
} // end enqueue

public T dequeue()
{

} // end dequeue
public void enqueue(T newEntry) Data members:
{ private T[] queue;
checkIntegrity(); private int frontIndex;
ensureCapacity(); private int backIndex
backIndex = (backIndex + 1) %queue.length;
//Index of location after current back of queue • use ensureCapacity()
queue[backIndex] = newEntry; method
• Assume we’ve defined an
} // end enqueue emptyQueueException

public T dequeue()
{
checkIntegrity();
if (isEmpty())
throw new EmptyQueueException();
else
{
T front = queue[frontIndex];
queue[frontIndex] = null;
frontIndex = (frontIndex + 1) % queue.length;
return front;
} // end if
} // end dequeue
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


Variations of the Queue ADT
• Double ended queue: Deque (pronounced “deck”)
• Add, remove, or retrieve entries at both front and
back (e.g. model frustrated customers leaving, …)
• Combines and expands the operations of queue
and stack
• Priority queue
• Organize elements according to priorities
(e.g. a hospital ER, a CPU scheduler)
Specifications of the ADT Deque

Carrano and Henry, Data Structures and Abstractions with Java.


Possible Deque implementation

How could we use a linked


list to implement a deque?
Doubly linked implementation of a
deque
Priority Queue ADT

• Organizes objects according to priorities


(Contrast to regular queue in order of arrival)
• Priority can be specified by
• an integer (e.g. say 0 is highest priority, 20 is lowest)
• Another object (e.g. that implements Comparable
interface)

• Main difference from queue: enqueue operation must


maintain the priority of the elements (like a combination of
queue and sorted list)

Carrano and Henry, Data Structures and Abstractions with Java.


Possible implementation of a
Priority Queue ADT

Carrano and Henry, Data Structures and Abstractions with Java.


Queue summary
• You should know:
• What’s the behavior of a queue? Examples of
where that might be useful
• Implementations:
• Linked list/array-based
• Advantages/disadvantages of each
• Should have an idea of how to implement
variations of queue
Overview of today’s material
- Stacks
- More practice using stacks
- Linked list stack implementation
- Array-based stack implementation
- Analysis of time complexity of stack implementations

- Queues
- Queue functionality
- Linked list queue implementation
- Array-based queue implementation
- Variations on queues

- Start on Dictionary ADT


Dictionary abstract data type
Dictionary Abstract Data Type:
motivation
• Assume we’re hired by Facebook to rewrite the
system for storing/serving user accounts, info, etc.
• We have ~3 billion user accounts, what should we
use as the core data structure for managing them?
– List?
– Queue?
– Stack?
No! We need a way of efficiently accessing individual accounts
directly. Example: if we get a request to update account info
from some username, we should be able to quickly pull out that
account, make the update
Solution: the “Dictionary” ADT
(also called Map or associative array)

Contains entries that each have two parts


• A key word or search key
• A value associated with the key

“key-value” pair

Carrano and Henry, Data Structures and Abstractions with Java.


What we’ll discuss about Dictionaries
• How are they used? (practice using the ADT)
• How should we implement? (arrays, linked
lists, etc..)
• How do we find the key-value pair given a key
request? (need efficient search)
• “Hashing”, hashtable implementation of a
dictionary
Specifications for the ADT Dictionary

“key-value” pair

An instance of an ADT dictionary has pairs of search keys and


corresponding values

Carrano and Henry, Data Structures and Abstractions with Java.


Dictionary examples
Map (from  to)
• User id (Integer)  FacebookAccount
• Name (String)  Telephone number
• Word (String)  Definition
• User id (Integer)  List of Facebook accounts (e.g.
friends)

Note: key type and value types are flexible


Specifications for the ADT Dictionary
• Data
– Pairs of objects (key, value)
– Number of pairs in the collection
• Operations
• add(key,value) • getSize()
• remove(key) • isFull()
• getValue(key) • isEmpty()
• contains(key) • getKeyIterator()

Carrano and Henry, Data Structures and Abstractions with Java.


Formal definition of a Dictionary interface
/** A dictionary with distinct search keys. */
import java.util.Iterator;
public interface DictionaryInterface<K, V>
{
public V add(K key, V value);

public V remove(K key);

public V getValue(K key);

public boolean contains(K key);

public boolean isEmpty();

public boolean isFull();

public int getSize();


(See Carrano, Ch. 20
public void clear();
for more details.)
public Iterator<K> getKeyIterator();

public Iterator<K> getValueIterator();

} // end DictionaryInterface
Dictionary exercise
DictionaryInterface<Name,String> phoneBook = new ArrayDictionary<Name,String>();
phoneBook.add(new Name(“John”,”Doe”),”555-1234”);
phoneBook.add(new Name(“Jane”,”Doe”),”555-8888”);
phoneBook.add(new Name(“Bill”,”Smith”),”555-5566”);
phoneBook.add(new Name(“Average”,”Joe”),”555-1234”);

Name key = new Name(“John”,”Doe”);


if(phoneBook.contains(key)) {
System.out.println(phoneBook.getValue(key));
}
System.out.println(phoneBook.getValue(new Name(“Bill”,”Smith”)));
System.out.println(phoneBook.getValue(new Name(“Average”,”Joe”)));

phoneBook.add(key,”555-1111”);
System.out.println(phoneBook.getValue(new Name(“John”,”Doe”)));

phoneBook.remove(key);
if(phoneBook.contains(key)) {
System.out.println(phoneBook.getValue(key));
}
Dictionary exercise
DictionaryInterface<Name,String> phoneBook = new ArrayDictionary<Name,String>();
phoneBook.add(new Name(“John”,”Doe”),”555-1234”);
phoneBook.add(new Name(“Jane”,”Doe”),”555-8888”);
phoneBook.add(new Name(“Bill”,”Smith”),”555-5566”);
phoneBook.add(new Name(“Average”,”Joe”),”555-1234”);

Name key = new Name(“John”,”Doe”);


if(phoneBook.contains(key)) {
System.out.println(phoneBook.getValue(key));
}
System.out.println(phoneBook.getValue(new Name(“Bill”,”Smith”)));
System.out.println(phoneBook.getValue(new Name(“Average”,”Joe”)));

phoneBook.add(key,”555-1111”);
System.out.println(phoneBook.getValue(new Name(“John”,”Doe”)));

phoneBook.remove(key); Output:
if(phoneBook.contains(key)) {
System.out.println(phoneBook.getValue(key));
555-1234
} 555-5566
555-1234
555-1111
Dictionary exercise #2
• Assume you’re given a genome sequence in a
String
String sequence = “ATACGGAATTCCTATACGGGATTATACCCG…” )

• You need to count the number of occurrences


of all possible length-4 sequences
e.g. ATAC occurs 3 times
ATACGGAATTCCTATACGGGATTATACCCG…

• Write pseudo-code that uses a Dictionary to


do this
Dictionary exercise #2
Dictionary exercise #2
DictionaryInterface<String,Integer> patterns = new
ArrayDictionary<String, Integer>();

for(int i=0; i <= sequence.length-4; i++) {


currString = sequence.substring(i,i+4)

if(patterns.contains(currString))
patterns.add(currString,patterns.get(currString)+1);
else
patterns.add(currString,1);
}

//now just get all of the keys from the dictionary, ask for
//corresponding values one-by-one
Iterator<String> keys = patterns.getKeyIterator();
while(keys.hasNext()) {
String curr = keys.next();
System.out.println(curr+”:”+patterns.get(curr));
}
Midterm 2
• Thursday, April 7, 6:30-8:30pm
• Closed book, closed computer
• You are allowed 1 page (8.5” x 11”)
(2 sides) of handwritten notes

• Time limit: 2 hrs

• Example midterm + list of topics is posted


on Canvas

You might also like