Return the max element,and reorganize the heap to maintain heap property
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (1)
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (2)
Maintaining heap property:
Subtrees rooted at left[i] and right[i] are already heaps.
But, A[i] may violate the heap property (i.e., may be smaller than its children)
Idea: Float down the value at A[i] in the heap so that subtree rooted at i becomes a heap.
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (2)
HEAPIFY(A, i, n)
largest = i
if2i <= n and A[2i] > A[i] then
largest = 2i;
endif
if2i+1 <= n and A[2i+1] > A[largest] then
largest = 2i+1;
endif
if largest != i then
exchange A[i] with A[largest];
HEAPIFY(A, largest, n);
endif
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (3)
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (4)
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (5)
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (6)
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (7)
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (8)
CE100 Algorithms and Programming II
Intuitive Analysis of HEAPIFY
Consider HEAPIFY(A,i,n)
let h(i) be the height of node i
at most h(i) recursion levels
Constant work at each level: Θ(1)
Therefore T(i)=O(h(i))
Heap is almost-complete binary tree
h(n)=O(lgn)
Thus T(n)=O(lgn)
CE100 Algorithms and Programming II
Formal Analysis of HEAPIFY
What is the recurrence?
Depends on the size of the subtree on which recursive call is made
In the next, we try to compute an upper bound for this subtree.
CE100 Algorithms and Programming II
Reminder: Binary trees
For a complete binary tree:
# of nodes at depth d: 2d
# of nodes with depths less than d: 2d−1
CE100 Algorithms and Programming II
Formal Analysis of HEAPIFY (1)
Worst case occurs when last row of the subtree Si rooted at node i is half full
T(n)≤T(∣SL(i)∣)+Θ(1)
SL(i) and SR(i) are complete binary trees of heights h(i)−1 and h(i)−2, respectively
In the absence of tail recursion, iterative version is in general more efficient because of the pop/push operations to/from stack at each level of recursion.
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (1)
Recursive
HEAPIFY(A, i, n)
largest = i
if2i <= n and A[2i] > A[i] then
largest = 2iif2i+1 <= n and A[2i+1] > A[largest] then
largest = 2i+1if largest != i then
exchange A[i] with A[largest]
HEAPIFY(A, largest, n)
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (2)
Iterative
HEAPIFY(A, i, n)
j = i
while(true) do
largest = j
if2j <= n and A[2j] > A[j] then
largest = 2j
if2j+1 <= n and A[2j+1] > A[largest] then
largest = 2j+1if largest != j then
exchange A[j] with A[largest]
j = largest
elsereturn
CE100 Algorithms and Programming II
Heap Operations: HEAPIFY (3)
CE100 Algorithms and Programming II
Heap Operations: Building Heap
Given an arbitrary array, how to build a heap from scratch?
Basic idea: Call HEAPIFY on each node bottom up
Start from the leaves (which trivially satisfy the heap property)
Process nodes in bottom up order.
When HEAPIFY is called on node i, the subtrees connected to the left and right subtrees already satisfy the heap property.
CE100 Algorithms and Programming II
Storage of the leaves (Lemma)
Lemma: The last ⌈2n⌉ nodes of a heap are all leaves.
CE100 Algorithms and Programming II
Storage of the leaves (Proof of Lemma) (1)
Lemma: last ⌈n/2⌉ nodes of a heap are all leaves
Proof :
m=2d−1: # nodes at level d−1
f: # nodes at level d (last level)
# of nodes with depth d−1 : m
# of nodes with depth <d−1 : m−1
# of nodes with depth d : f
Total# of nodes :n=f+2m−1
CE100 Algorithms and Programming II
Storage of the leaves (Proof of Lemma) (2)
Total# of nodes : f=n−2m+1
# of leaves: =f+m−⌈f/2⌉=m+⌊f/2⌋=m+⌊(n−2m+1)/2⌋=⌊(n+1)/2⌋=⌈n/2⌉
Proof is Completed
CE100 Algorithms and Programming II
Heap Operations: Building Heap
BUILD-HEAP (A, n)
for i = ceil(n/2) downto 1 do
HEAPIFY(A, i, n)
Reminder: The last ⌈n/2⌉ nodes of a heap are all leaves, which trivially satisfy the heap property
CE100 Algorithms and Programming II
Build-Heap Example (Step-1)
CE100 Algorithms and Programming II
Build-Heap Example (Step-2)
CE100 Algorithms and Programming II
Build-Heap Example (Step-3)
CE100 Algorithms and Programming II
Build-Heap Example (Step-4)
CE100 Algorithms and Programming II
Build-Heap Example (Step-5)
CE100 Algorithms and Programming II
Build-Heap Example (Step-6)
CE100 Algorithms and Programming II
Build-Heap Example (Step-7)
CE100 Algorithms and Programming II
Build-Heap Example (Step-8)
CE100 Algorithms and Programming II
Build-Heap Example (Step-9)
CE100 Algorithms and Programming II
Build-Heap: Runtime Analysis
Simple analysis:
O(n) calls to HEAPIFY, each of which takes O(lgn) time
O(nlgn)⟹ loose bound
In general, a good approach:
Start by proving an easy bound
Then, try to tighten it
Is there a tighter bound?
CE100 Algorithms and Programming II
Build-Heap: Tighter Running Time Analysis
If the heap is complete binary tree then hℓ=d–ℓ
Otherwise, nodes at a given level do not all have the same height, But we have d–ℓ–1≤hℓ≤d–ℓ
CE100 Algorithms and Programming II
Build-Heap: Tighter Running Time Analysis
Assume that all nodes at level ℓ=d–1 are processed
T(n)∴T(n)Let T(n) but =ℓ=0∑d−1nℓO(hℓ)=O(ℓ=0∑d−1nℓhℓ){nℓ=2ℓ=# of nodes at level ℓhℓ=height of nodes at level ℓ=O(ℓ=0∑d−12ℓ(d−ℓ))h=d−ℓ⟹ℓ=d−h change of variables=O(h=1∑dh2d−h)=O(h=1∑dh2h2d)=O(2dh=1∑dh(1/2)h)2d=Θ(n)⟹O(nh=1∑dh(1/2)h)
Heapsort is a very good algorithm but, a good implementation of quicksort always beats heapsort in practice
However, heap data structure has many popular applications, and it can be efficiently used for implementing priority queues
CE100 Algorithms and Programming II
Data structures for Dynamic Sets
Consider sets of records having key and satellite data
CE100 Algorithms and Programming II
Operations on Dynamic Sets
Queries: Simply return info;
MAX(S)/MIN(S): (Query) return x∈S with the largest/smallestkey
SEARCH(S,k): (Query) return x∈S with key[x]=k
SUCCESSOR(S,x)/PREDECESSOR(S,x): (Query) return y∈S which is the next larger/smaller element after x
Modifying operations: Change the set
INSERT(S,x): (Modifying) S←S∪{x}
DELETE(S,x): (Modifying) S←S−{x}
EXTRACT-MAX(S)/EXTRACT-MIN(S): (Modifying) return and delete x∈S with the largest/smallest key
Different data structures support/optimize different operations
CE100 Algorithms and Programming II
Priority Queues (PQ)
Supports
INSERT
MAX/MIN
EXTRACT-MAX/EXTRACT-MIN
CE100 Algorithms and Programming II
Priority Queues (PQ)
One application: Schedule jobs on a shared resource
PQ keeps track of jobs and their relative priorities
When a job is finished or interrupted, highest priority job is selected from those pending using EXTRACT-MAX
A new job can be added at any time using INSERT
CE100 Algorithms and Programming II
Priority Queues (PQ)
Another application: Event-driven simulation
Events to be simulated are the items in the PQ
Each event is associated with a time of occurrence which serves as a key
Simulation of an event can cause other events to be simulated in the future
Use EXTRACT-MIN at each step to choose the next event to simulate
As new events are produced insert them into the PQ using INSERT
CE100 Algorithms and Programming II
Implementation of Priority Queue
Sorted linked list: Simplest implementation
INSERT
O(n) time
Scan the list to find place and splice in the new item
EXTRACT-MAX
O(1) time
Take the first element
Fast extraction but slow insertion.
CE100 Algorithms and Programming II
Implementation of Priority Queue
Unsorted linked list: Simplest implementation
INSERT
O(1) time
Put the new item at front
EXTRACT-MAX
O(n) time
Scan the whole list
Fast insertion but slow extraction.
Sorted linked list is better on the average
Sorted list: on the average, scans n/2 element per insertion
Unsorted list: always scans n element at each extraction
CE100 Algorithms and Programming II
Heap Implementation of PQ
INSERT and EXTRACT-MAX are both O(lgn)
good compromise between fast insertion but slow extraction and vice versa
EXTRACT-MAX: already discussed HEAP-EXTRACT-MAX
INSERT: Insertion is like that of Insertion-Sort.
HEAP-INSERT(A, key, n)
n = n+1
i=n
while i>1 and A[floor(i/2)] < key do
A[i]=A[floor(i/2)]
i= floor(i/2)
A[i]=key
CE100 Algorithms and Programming II
Heap Implementation of PQ
Traverses O(lgn) nodes, as HEAPIFY does but makes fewer comparisons and assignments
HEAPIFY: compares parent with both children
HEAP−INSERT: with only one
CE100 Algorithms and Programming II
HEAP-INSERT Example (Step-1)
CE100 Algorithms and Programming II
HEAP-INSERT Example (Step-2)
CE100 Algorithms and Programming II
HEAP-INSERT Example (Step-3)
CE100 Algorithms and Programming II
HEAP-INSERT Example (Step-4)
CE100 Algorithms and Programming II
HEAP-INSERT Example (Step-5)
CE100 Algorithms and Programming II
Heap Increase Key
Key value of ith element of heap is increased from A[i] to key
HEAP-INCREASE-KEY(A, i, key)
if key < A[i] then
return error
while i > 1 and A[floor(i/2)] < key do
A[i] = A[floor(i/2)]
i = floor(i/2)
A[i] = key
CE100 Algorithms and Programming II
HEAP-INCREASE-KEY Example (Step-1)
CE100 Algorithms and Programming II
HEAP-INCREASE-KEY Example (Step-2)
CE100 Algorithms and Programming II
HEAP-INCREASE-KEY Example (Step-3)
CE100 Algorithms and Programming II
HEAP-INCREASE-KEY Example (Step-4)
CE100 Algorithms and Programming II
HEAP-INCREASE-KEY Example (Step-5)
CE100 Algorithms and Programming II
Heap Implementation of Priority Queue (PQ)
CE100 Algorithms and Programming II
Summary: Max Heap
Heapify(A, i)
Works when both child subtrees of node i are heaps
"Floats down" node i to satisfy the heap property
Runtime: O(lgn)
Max(A, n)
Returns the max element of the heap (no modification)
Runtime: O(1)
Extract-Max(A, n)
Returns and removes the max element of the heap
Fills the gap in A[1] with A[n], then calls Heapify(A,1)
Runtime: O(lgn)
CE100 Algorithms and Programming II
Summary: Max Heap
Build-Heap(A, n)
Given an arbitrary array, builds a heap from scratch
Runtime: O(n)
Min(A, n)
How to return the min element in a max-heap?
Worst case runtime: O(n)
because ~half of the heap elements are leaf nodes
Instead, use a min-heap for efficient min operations
Search(A, x)
For an arbitrary x value, the worst-case runtime: O(n)
Use a sorted array instead for efficient search operations
CE100 Algorithms and Programming II
Summary: Max Heap
Increase-Key(A, i, x)
Increase the key of node i (from A[i] to x)
“Float up” x until heap property is satisfied
Runtime: O(lgn)
Decrease-Key(A, i, x)
Decrease the key of node i (from A[i] to x)
Call Heapify(A, i)
Runtime: O(lgn)
CE100 Algorithms and Programming II
Phone Operator Problem
A phone operator answering n phones
Each phone i has xi people waiting in line for their calls to be answered.
Phone operator needs to answer the phone with the largest number of people waiting in line.
New calls come continuously, and
some people hang up after waiting.
CE100 Algorithms and Programming II
Phone Operator Solution
Step 1: Define the following array:
A[i]: the ith element in heap
A[i].id: the index of the corresponding phone
A[i].key: # of people waiting in line for phone with index A[i].id
CE100 Algorithms and Programming II
Phone Operator Solution
Step 2:Build-Max-Heap(A,n)
Execution:
When the operator wants to answer a phone:
id=A[1].id
Decrease-Key(A,1,A[1].key−1)
answer phone with index id
When a new call comes in to phone i:
Increase-Key(A,i,A[i].key+1)
When a call drops from phone i:
Decrease-Key(A,i,A[i].key−1)
CE100 Algorithms and Programming II
Linked Lists
Like arrays, Linked List is a linear data structure.
Unlike arrays, linked list elements are not stored at a contiguous location; the elements are linked using pointers.
CE100 Algorithms and Programming II
Linked Lists - C Definition
C
// A linked list nodestructNode {int data;
structNode* next;
};
CE100 Algorithms and Programming II
Linked Lists - Cpp Definition
Cpp
classNode {public:
int data;
Node* next;
};
CE100 Algorithms and Programming II
Linked Lists - Java Definition
Java
classLinkedList{
Node head; // head of the list/* Linked list Node*/classNode{
int data;
Node next;
// Constructor to create a new node// Next is by default initialized// as null
Node(int d) { data = d; }
}
}
CE100 Algorithms and Programming II
Linked Lists - Csharp Definition
Csharp
classLinkedList {
// The first node(head) of the linked list// Will be an object of type Node (null by default)
Node head;
classNode {
int data;
Node next;
// Constructor to create a new node
Node(int d) { data = d; }
}
}
CE100 Algorithms and Programming II
Priority Queue using Linked List Methods
Implement Priority Queue using Linked Lists.
push(): This function is used to insert a new data into the queue.
pop(): This function removes the element with the highest priority from the queue.
peek()/top(): This function is used to get the highest priority element in the queue without removing it from the queue.
CE100 Algorithms and Programming II
Priority Queue using Linked List Algorithm
PUSH(HEAD, DATA, PRIORITY)
Create NEW.Data = DATA & NEW.Priority = PRIORITY
If HEAD.priority < NEW.Priority
NEW -> NEXT = HEAD
HEAD = NEW
Else
Set TEMP to head of the list
Endif
WHILE TEMP -> NEXT != NULL and TEMP -> NEXT ->PRIORITY > PRIORITY THEN
TEMP = TEMP -> NEXT
ENDWHILE
NEW -> NEXT = TEMP -> NEXT
TEMP -> NEXT = NEW
CE100 Algorithms and Programming II
Priority Queue using Linked List Algorithm
POP(HEAD)
//Set the head of the list to the next node in the list.
HEAD = HEAD -> NEXT.
Free the node at the head of the list
PEEK(HEAD):
Return HEAD -> DATA
CE100 Algorithms and Programming II
Priority Queue using Linked List Notes
LinkedList is already sorted.
Time Complexities and Comparison with Binary Heap
peek()
push()
pop()
Linked List
O(1)
O(n)
O(1)
Binary Heap
O(1)
O(lgn)
O(lgn)
CE100 Algorithms and Programming II
Sorting in Linear Time
CE100 Algorithms and Programming II
How Fast Can We Sort?
The algorithms we have seen so far:
Based on comparison of elements
We only care about the relative ordering between the elements (not the actual values)
The smallest worst-case runtime we have seen so far: O(nlgn)
Is O(nlgn) the best we can do?
Comparison sorts: Only use comparisons to determine the relative order of elements.
CE100 Algorithms and Programming II
Decision Trees for Comparison Sorts
Represent a sorting algorithm abstractly in terms of a decision tree
A binary tree that represents the comparisons between elements in the sorting algorithm
Control, data movement, and other aspects are ignored
One decision tree corresponds to one sorting algorithm and one value of n (input size)
Example: To sort 3 digit numbers, in the worst case:
S(d)=(1/9)(103−1)=111 sorting passes needed
P(d)=10d−1−1=99 intermediate card piles generated
MSD-first approach has more recursive calls and intermediate storage requirement
Expensive for a tabulating machine to sort punched cards
Overhead of recursive calls in a modern computer
CE100 Algorithms and Programming II
LSD-First Radix Sort
Least significant digit (LSD)-first radix sort seems to be a folk invention originated by machine operators.
It is the counter-intuitive, but the better algorithm.
Basic Algorithm:
Sort numbers on their LSD first (Stable Sorting Needed)
Combine the cards into a single deck in order
Continue this sorting process for the other digits
from the LSD to MSD
Requires only d sorting passes
No intermediate card pile generated
CE100 Algorithms and Programming II
LSD-first Radix Sort Example
CE100 Algorithms and Programming II
Correctness of Radix Sort (LSD-first)
Proof by induction:
Base case:d=1 is correct (trivial)
Inductive hyp: Assume the first d−1 digits are sorted correctly
Prove that all d digits are sorted correctly after sorting digit d
Two numbers that differ in digit d are correctly sorted (e.g. 355 and 657)
Two numbers equal in digit d are put in the same order as the input