You are on page 1of 47

Chapter 21

Heaps and Priority Queues


Bonus Problem
• Given a linked list, determine if it has a cycle in it.

21 - 2
• Given a linked list, determine if it has a cycle in it.

• Mark Visited Nodes:


– This solution requires modifications to basic linked list data
structure. Have a visited flag with each node. Traverse the linked
list and keep marking visited nodes. If you see a visited node again
then there is a loop. This solution works in O(n) but requires
additional information with each node.
– BFS? DFS?
21 - 3
Chapter Scope
• Heaps, conceptually
• Using heaps to solve problems
• Heap implementations
• Using heaps to implement priority queues

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 10


1. Heaps
• A heap is a complete binary tree in which each
element is less than or equal to both of its children.
• So a heap has both structural and ordering
constraints.
• As with binary search trees, there are many possible
heap configurations for a given set of elements.
• Our definition above is really a minheap.
• A similar definition could be made for a maxheap.

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 11


Minheap

Source: https://www.tutorialspoint.com/data_structures_algorithms/heap_data_structure.htm
21 - 12
Maxheap

Source: https://en.wikipedia.org/wiki/Heap_(data_structure)
21 - 13
• Two minheaps containing the same data:

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 14


Adding a New Element
• To add an element to the heap, add the element
as a leaf, keeping the tree complete.
• Then, move the element up toward the root,
exchanging positions with its parent, until the
relationship among the elements is appropriate.
• This will guarantee that the resulting tree will
conform to the heap criteria.

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 15


• The initial insertion point for a new element in a
heap:

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 16


• Inserting an element and moving it up the tree as
far as appropriate:

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 17


Source: http://algorithms.tutorialhorizon.com/binary-min-max-heap/
21 - 18
• [Q] How to find the insertion position, or the
parent of the insertion position?

21 - 19
– Can you find the path from the root to the parent of
the insertion position?
– Idea: Use of the number of nodes – numNodes
– Given numNodes, how to know whether the new
node will become the left child or the right child?
– Given id (i.e., position), how to get the id of the
parent node? 0

1 2

3 4 5 6

7 21 - 20
int position = numNodes; // new position
String s; 0

1 2
s = position + "";
while (position > 0) {
3 4 5 6
if (???)
position = position / 2;
7
else
??? 1:
0,1
s = position + "," + s;
5:
} 0,2,5
String positions[] = s.split(","); 6:
0,2,6
// Move from the root through positions[] 7:
0,1,3,7
...

21 - 21
+ addElement()
// When there is no node

if (numNodes == 0) {
root <- new node;
numNodes++;
return;
}

21 - 22
// Find the place where the new node goes to
// Actually the parent node

int position = numNodes;


1: 0
String s = position + "";
0,1
while (position > 0) { 5: 1 2
if (???) 0,2,5
position = ???; 6: 3 4 5 6
else 0,2,6
position = position / 2 - 1; 7:
s = position + "," + s; 0,1,3,7 7
} 8:
String positions[] = s.split(","); 0,1,3,8

parent = root; // position == 0


for (int i = 1; i < ???; i++) { // except the new position
if (Integer.parseInt(positions[i]) % 2 == 1)
parent = ???;
else
parent = ???; Complexity?
}
21 - 23
// Create the new node
// Attach the new node to its parent

nodeNew <- new node;


if (???) {
parent.setLeft(nodeNew);
nodeNew.setParent(parent);
}
else {
???
} Complexity?
numNodes++;

// Adjust the heap

node <- nodeNew;


while (node != root) {
if (node.getPriority() < node.getParent().getPriority())
swapChildParent(node, node.getParent());
else
break;
}
21 - 24
Removing the Min Element
• Remove the root (min) and reconstruct the heap.
• First, move the last leaf of the tree to be the new
root of the tree.
– [Q] How to find the last leaf?
• Then, move it down the tree as needed until the
relationships among the elements is appropriate.
• In particular, compare the element to the smaller
of its children and swap them if the child is
smaller.
Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 25
• The element to replace the root is the "last leaf"
in the tree:

Examples of last leaf

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 26


Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 27
Source: http://algorithms.tutorialhorizon.com/binary-min-max-heap/
21 - 28
+ removeMin()
// If there is nothing, then return

if (numNodes == 0)
return null;

// If there is only one, then remove the root and return its content

if (numNodes == 1) {
tmpRoot = root;
root = null;
numNodes = 0;
return ???
}

21 - 29
// Find the last node

NodePriorityQueue<T> node;
int position = numNodes-1;
1: 0
String s = position + "";
0,1
while (position > 0) { 5: 1 2
if (???) 0,2,5
position = position / 2; 6: 3 4 5 6
else 0,2,6
??? 7:
s = position + "," + s; 0,1,3,7 7
}
String positions[] = s.split(",");

node = root; // position == 0


for (int i = 1; i < positions.length; i++) {
if (???)
node = ???;
else
node = node.getRight();
}
21 - 30
// Cut off the last node

if (???)
node.getParent().setLeft(null);
else
???

numNodes--;

// Keep the root node


tmpRoot = root;

// Make the last node as the root

root = node;
root.setParent(null);
root.setLeft(???);
???;

if (tmpRoot.getLeft() != null)
tmpRoot.getLeft().setParent(root);
???
21 - 31
// Adjust the heap

node = root;
while(true) {
if (node.getLeft() == null && node.getRight() == null) break;
else if (node.getLeft() != null && node.getRight() == null) {
if (node.getPriority() > node.getLeft()).getPriority()) swapChildParent(node.getLeft(), node);
else break;
}
else if (node.getLeft() == null && node.getRight() != null) {
if (node.getPriority() > node.getRight()).getPriority()) swapChildParent(node.getRight(), node);
else break;
}
else {
if (node.getLeft().getPriority() <= node.getRight().getPriority()) {
if (node.getPriority() > node.getLeft().getPriority()) swapChildParent(node.getLeft(), node);
else break;
}
else if (node.getLeft().getPriority() > node.getRight().getPriority()) {
if (node.getPriority() > node.getRight().getPriority()) swapChildParent(node.getRight(), node);
else break;
}
else break;
}
}

// Return the content of the root


return ??? 21 - 32
Operations on a heap

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 33


2. Priority Queues
• Recall that a FIFO queue removes elements in
the order in which they were added.
• A priority queue removes elements in priority
order, independent of the order in which they
were added.
• Priority queues are helpful in many scheduling
situations.
• A heap is a classic mechanism for implementing
priority queues.
Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 34
HeapADT.class
interface HeapADT<T>

+ addElement(T element): void


+ removeMin(): T
+ findMin(): T

19 - 35
NodeBinaryTree.class
NodeBinaryTree<T>
- int id
- T content
- NodeBinaryTree<T> parent, left, right
+ NodeBinaryTree(T content)
+ NodeBinaryTree(int id, T content)
+ getId(): int
+ getContent(): T
+ getParent(): NodeBinaryTree<T>
+ setParent(NodeBinaryTree<T> parent): void
+ getLeft(): NodeBinaryTree<T> parent
+ setLeft(NodeBinaryTree<T> left): void
+ getRight(): NodeBinaryTree<T> id,
+ setRight(NodeBinaryTree<T> right): void
cont
ent
left right

19 - 36
NodePriorityQueue.class
NodePriorityQueue<T> extends
NodeBinaryTree<T>
- int priority
+ NodePriorityQueue(T content)
+ getPriority(): int
+ setPriority(int priority): void

19 - 37
PriorityQueue.class
PriorityQueue<T>
- NodePriorityQueue<T> root;
- int numNodes;
+ PriorityQueue(T content)
+ addElement(int priority, T element): void
+ removeMin(): T
+ findMin(): T
+ getRoot(): NodePriorityQueue<T>
+ isEmpty(): boolean
+ size(): int
- swapChildParent(NodePriorityQueue<T> child,
NodePriorityQueue<T> parent): void

19 - 38
+ addElement()
// When there is no node

if (numNodes == 0) {
root <- new node;
numNodes++;
return;
}

21 - 39
// Find the place where the new node goes to
// Actually the parent node

int position = numNodes;


1: 0
String s = position + "";
0,1
while (position > 0) { 5: 1 2
if (???) 0,2,5
position = position / 2; 6: 3 4 5 6
else 0,2,6
position = ???; 7:
s = position + "," + s; 0,1,3,7 7
} 8:
String positions[] = s.split(","); 0,1,3,8

parent = root; // position == 0


for (int i = 1; i < ???; i++) { // except the new position
if (???)
parent = parent.getLeft();
else
parent = ???
}
21 - 40
// Create the new node
// Attach the new node to its parent

nodeNew <- new node;


if (???) {
???
}
else {
parent.setRight(nodeNew);
nodeNew.setParent(parent);
}
numNodes++;

// Adjust the heap

node <- nodeNew;


while (node != root) {
if (???)
swapChildParent(node, node.getParent());
else
break;
}
21 - 41
+ removeMin()
// If there is nothing, then return

if (numNodes == 0)
return null;

// If there is only one, then remove the root and return its content

if (numNodes == 1) {
tmpRoot = root;
root = null;
numNodes = 0;
return ???
}

21 - 42
// Find the last node

NodePriorityQueue<T> node;
int position = numNodes-1;
1: 0
String s = position + "";
0,1
while (position > 0) { 5: 1 2
if (???) 0,2,5
position = position / 2; 6: 3 4 5 6
else 0,2,6
??? 7:
s = position + "," + s; 0,1,3,7 7
}
String positions[] = s.split(",");

node = root; // position == 0


for (int i = 1; i < positions.length; i++) {
if (???)
node = ???;
else
node = node.getRight();
}
21 - 43
// Cut off the last node

if (???)
node.getParent().setLeft(null);
else
???

numNodes--;

// Keep the root node


tmpRoot = root;

// Make the last node as the root

root = node;
root.setParent(null);
root.setLeft(???);
???

if (tmpRoot.getLeft() != null)
tmpRoot.getLeft().setParent(root);
???
21 - 44
// Adjust the heap

node = root;
while(true) {
if (node.getLeft() == null && node.getRight() == null) break;
else if (node.getLeft() != null && node.getRight() == null) {
if (node.getPriority() > node.getLeft()).getPriority()) swapChildParent(node.getLeft(), node);
else break;
}
else if (node.getLeft() == null && node.getRight() != null) {
if (node.getPriority() > node.getRight()).getPriority()) swapChildParent(node.getRight(), node);
else break;
}
else {
if (node.getLeft().getPriority() <= node.getRight().getPriority()) {
if (node.getPriority() > node.getLeft().getPriority()) swapChildParent(node.getLeft(), node);
else break;
}
else if (node.getLeft().getPriority() > node.getRight().getPriority()) {
if (node.getPriority() > node.getRight().getPriority()) swapChildParent(node.getRight(), node);
else break;
}
else break;
}
}

// Return the content of the root


return ??? 21 - 45
PriorityQueueTest.class
// data.txt

// number of data
12
// values and priorities at the same time (strings)
45
30
60
82
22
27
35
40
51
75
55
87

21 - 46
queue = new PriorityQueue<String>();

count = 0;
while(count < numElements) {
line = bufferedReader.readLine();
line = line.trim();
if (line.length() == 0)
continue;
if (line.charAt(0) == '/' && line.charAt(1) == '/')
continue;

???(Integer.parseInt(line), line);

count++;
}

displayBFS(0);

21 - 47
static void remove()
{
if (queue.size() > 0)
{
String s = "Min";
for (int col = 0; col < s.length(); col++)
board.cellContent(2, col, "" + s.charAt(col));

board.cellContent(3, 0, "" + ???);


board.cellBackgroundColor(3, 0, Color.CYAN);

displayBFS(0);
}
}

21 - 48
Run Time (Big O Notation)
• Heap implemented using links:
– addElement:
O(log n)
– removeMin:
O(log n)

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 49


5. Heap Sort
• Given the ordering property of a heap, it is
natural to think of using a heap to sort a list of
numbers.
• A heap sort sorts a set of elements by
adding each one to a heap, then removing
them one at a time.
• The smallest element comes off the heap first, so
the sequence will be in ascending order.

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 50


Run Time (Big O Notation)
• HeapSort:
O(n log n)

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 51


Summary
• A minheap is a complete binary tree in which each node is less than or
equal to both the left child and the right child.
• A minheap stores its smallest element at the root of the binary tree,
and both children of the root of a minheap are also minheaps.
• The addElement method adds a given Comparable element to the
appropriate location in the heap, maintaining both the completeness
property and the ordering property of the heap.
• Because a heap is a complete tree, there is only one correct location for
the insertion of a new node, and that is either the next open position
from the left at level h or, if level h is full, the first position on the left at
level h + 1.
• Typically, in heap implementations, we keep track of the position of the
last node or, more precisely, the last leaf in the tree.
• To maintain the completeness of the tree, there is only one valid
element to replace the root, and that is the element stored in the last
leaf in the tree.

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 52


Summary
• Even though it is not a queue at all, a minheap provides an efficient
implementation of a priority queue.
• Because of the requirement that we be able to traverse up the tree
after an insertion, it is necessary for the nodes in a heap to store a
pointer to their parent.
• In an array implementation of a binary tree, the root of the tree is in
position 0, and for each node n, n’s left child is in position 2n + 1 and n’s
right child is in position 2(n + 1).
• The addElement operation for both the linked implementation and the
array implementation is O(log n).
• The removeMin operation for both the linked implementation and the
array implementation is O(log n).
• The heapsort method consists of adding each of the elements of the list
to a heap and then removing them one at a time.
• Heap sort is O(n long n).

Java Foundations, 4th Edition, Lewis/DePasquale/Chase 21 - 53

You might also like