0% found this document useful (0 votes)
35 views106 pages

ADS Unit 5

Unit 5 of the Advanced Data Structures course covers heaps and priority queues, detailing their properties, operations, and various implementations including binary heaps, leftist heaps, and advanced hashing techniques. It explains the structure and heap-order properties of binary heaps, how to perform insertions and deletions efficiently, and introduces other heap types such as d-heaps and Fibonacci heaps. The unit also discusses practical applications of heaps in scheduling, graph algorithms, and the selection problem.

Uploaded by

samarth.cs22
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)
35 views106 pages

ADS Unit 5

Unit 5 of the Advanced Data Structures course covers heaps and priority queues, detailing their properties, operations, and various implementations including binary heaps, leftist heaps, and advanced hashing techniques. It explains the structure and heap-order properties of binary heaps, how to perform insertions and deletions efficiently, and introduces other heap types such as d-heaps and Fibonacci heaps. The unit also discusses practical applications of heaps in scheduling, graph algorithms, and the selection problem.

Uploaded by

samarth.cs22
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/ 106

Advanced Data Structures

23CS6PEADS – Unit 5
Prof. SNEHA S BAGALKOT
Assistant Professor, Dept. of CSE, BMSCE
UNIT – 5: Heaps
▪Priority Queues: Model, Simple implementation,
▪Binary Heap: structure property, heap-order property, other operations,
▪d-heaps,
▪Leftist heaps: property, operations,
▪Skew heaps.
▪Advanced Hashing: Perfect Hashing, Cuckoo Hashing,
▪Hopscotch Hashing, Universal Hashing.
Priority Queues (Heaps)
Motivation
■ Queues are a standard mechanism for ordering tasks on a
first-come, first-served basis
■ However, some tasks may be more important or timely
than others (higher priority)
■ Priority queues
■ Store tasks using a partial ordering based on priority
■ Ensure highest priority task at head of queue
■ Heaps are the underlying data structure of priority queues
Priority Queues: Specification
■ Main operations
■ insert (i.e., enqueue)
■ Dynamic insert
■ specification of a priority level (0-high, 1,2.. Low)
■ deleteMin (i.e., dequeue)
■ Finds the current minimum element (read: “highest priority”) in the
queue, deletes it from the queue, and returns it

■ Performance goal is for operations to be “fast”


Using priority queues
4
10
19
3
5
13 8
1 22
1
insert()

deleteMin()
Dequeues the next element
2
with the highest priority
Can we build a data structure better suited to store and retrieve priorities?

Simple Implementations
■ Unordered linked list 5 2 10 … 3

■ O(1) insert
■ O(n) deleteMin
… 10
■ Ordered linked list 2 3 5

■ O(n) insert
■ O(1) deleteMin
2 3 5 … 10
■ Ordered array
■ O(lg n + n) insert
■ O(n) deleteMin
■ Balanced BST
■ O(log2n) insert and deleteMin
Binary Heap
A priority queue data structure
Binary Heap

■ A binary heap is a binary tree with two


properties
■ Structure property
■ Heap-order property
Structure Property

■ A binary heap is a complete binary tree


■ Each level (except possibly the bottom most level)
is completely filled
■ The bottom most level may be partially filled
(from left to right)

■ Height of a complete binary tree with N


elements is log2 N
 
Structure property

Binary Heap Example


N=10

Every level
(except last)
saturated

Array representation:
Heap-order Property
■ Heap-order property (for a “MinHeap”)
■ For every node X, key(parent(X)) ≤ key(X)

■ Except root node, which has no parent


 Thus minimum key always at root
■ Alternatively, for a “MaxHeap”, always keep the
maximum key at the root

■ Insert and deleteMin must maintain


heap-order property
Heap Order Property
Minimum
  element

   

   

■ Duplicates are allowed


■ No order implied for elements which do not
share ancestor-descendant relationship
Implementing Complete Binary Trees as Arrays

■ Given element at position i in the array


■ Left child(i) = at position 2i
■ Right child(i) = at position 2i + 1
■ Parent(i) = at position i /

2

i
2i
2i + 1
i/2
Just finds the Min
without deleting it
insert
deleteMin

Note: a general delete()


function is not as important
Stores the heap as for heaps
a vector but could be implemented

Fix heap after


deleteMin
Heap Insert

■ Insert new element into the heap at the


next available slot (“hole”)
■ According to maintaining a complete binary
tree
■ Then, “percolate” the element up the
heap while heap-order property not
satisfied
Percolating Up

Heap Insert: Example

Insert 14:

hole
14
Percolating Up

Heap Insert: Example


(1)
Insert 14: 14 vs. 31

14

hole
14
Percolating Up

Heap Insert: Example


(1)
Insert 14: 14 vs. 31

14

hole
14
(2)
14 vs. 21

14
Percolating Up

Heap Insert: Example


(1)
Insert 14: 14 vs. 31

hole
14
(2)
14 vs. 21
Heap order prop
14 (3)
14 vs. 13 Structure prop

Path of percolation up
Heap Insert: Implementation
// assume array implementation
void insert( const Comparable &x) {
?
}
Heap Insert: Implementation

O(log N) time
Heap DeleteMin

■ Minimum element is always at the root


■ Heap decreases by one in size
■ Move last element into hole at root
■ Percolate down while
heap-order property not satisfied
Percolating down…

Heap DeleteMin:
Example

Make this
position
empty
Percolating down…

Heap DeleteMin: Example


Copy 31 temporarily
here and move it down

Make this
position Is 31 > min(14,16)?
•Yes - swap 31 with min(14,16)
empty
Percolating down…

Heap DeleteMin:
Example

31

Is 31 > min(19,21)?
•Yes - swap 31 with min(19,21)
Percolating down…

Heap DeleteMin: Example

31

31

Is 31 > min(19,21)? Is 31 > min(65,26)?


•Yes - swap 31 with min(19,21) •Yes - swap 31 with min(65,26)

Percolating down…
Percolating down…

Heap DeleteMin: Example

31

Percolating down…
Percolating down…

Heap DeleteMin: Example

31

Heap order prop


Structure prop
Heap DeleteMin: Implementation

O(log N) time
Heap DeleteMin: Implementation

Percolate
down

Left child

Right child

Pick child to
swap with
Other Heap Operations
■ decreaseKey(p,v)
■ Lowers the current value of item p to new priority value v
■ Need to percolate up
■ E.g., promote a job
■ increaseKey(p,v)
■ Increases the current value of item p to new priority value v
■ Need to percolate down
■ remove(p)
■ E.g., demote a job Run-times for all three functions?
■ First, decreaseKey(p,-∞)
O(lg n)
■ Then, deleteMin
■ E.g., abort/cancel a job
Improving Heap Insert Time
■ What if all N elements are all available
upfront?

■ To build a heap with N elements:


■ Default method takes O(N lg N) time
■ We will now see a new method called buildHeap()
that will take O(N) time - i.e., optimal
Building a Heap
■ Construct heap from initial set of N items
■ Solution 1
■ Perform N inserts
■ O(N log2 N) worst-case
■ Solution 2 (use buildHeap())
■ Randomly populate initial heap with structure
property
■ Perform a percolate-down from each internal node
(H[size/2] to H[1])
■ To take care of heap order property
BuildHeap Example
Input: { 150, 80, 40, 10, 70, 110, 30, 120, 140, 60, 50, 130, 100, 20, 90 }

Leaves are all


valid heaps
(implicitly)

So, let us look at each


•Arbitrarily assign elements to heap nodes internal node,
• Structure property satisfied from bottom to top,
• Heap order property violated and fix if necessary
• Leaves are all valid heaps (implicit)
BuildHeap Example
Swap
with left
Nothing child
to do

• Randomly initialized heap


• Structure property satisfied
• Heap order property violated
• Leaves are all valid heaps
BuildHeap Example Swap
with right
Nothing child
to do

Dotted lines show path of percolating down


Swap with
right child
BuildHeap Example & then with 60

Nothing
to do

Dotted lines show path of percolating down


BuildHeap Example

Swap path

Final Heap

Dotted lines show path of percolating down


BuildHeap Implementation

Start with
lowest,
rightmost
internal node
BuildHeap() : Run-time Analysis
■ Run-time = ?
■ O(sum of the heights of all the internal nodes)
because we may have to percolate all the way
down to fix every internal node in the worst-case
■ Theorem 6.1 HOW?

■ For a perfect binary tree of height h, the sum


of heights of all nodes is 2h+1 – 1 – (h + 1)
■ Since h=lg N, then sum of heights is O(N)
■ Will be slightly better in practice

Implication: Each insertion costs O(1) amortized


time
Binary Heap Operations
Worst-case Analysis
Height of heap is log2 N
 

■ insert: O(lg N) for each insert


■ In practice, expect less
■ buildHeap insert: O(N) for N inserts
■ deleteMin: O(lg N)
■ decreaseKey: O(lg N)
■ increaseKey: O(lg N)
■ remove: O(lg N)
Applications

■ Operating system scheduling


■ Process jobs by priority
■ Graph algorithms
■ Find shortest path
■ Event simulation
■ Instead of checking for events at each time
click, look up next event to happen
An Application:
The Selection Problem

■ Given a list of n elements, find the kth


smallest element

■ Algorithm 1:
■ Sort the list =>O(n log n)
■ Pick the kth element => O(1)
■ A better algorithm:
■ Use a binary heap (minheap)
Selection using a MinHeap

 Input: n elements
 Algorithm:
1. buildHeap(n) ==> O(n)
2. Perform k deleteMin() operations ==> O(k log
n)
3. Report the kth deleteMin output ==> O(1)
Total run-time = O(n + k log n)

If k = O(n/log n) then the run-time becomes O(n)


Other Types of Heaps
■ Binomial Heaps

■ d-Heaps
■ Generalization of binary heaps (ie., 2-Heaps)

■ Leftist Heaps
■ Supports merging of two heaps in o(m+n) time (ie., sub-
linear)
■ Skew Heaps
■ O(log n) amortized run-time

■ Fibonacci Heaps
Run-time Per Operation

Insert DeleteMin Merge (=H1+H2)

Binary heap ■ O(log n) worst-case O(log n) O(n)


■ O(1) amortized
for buildHeap
Leftist Heap O(log n) O(log n) O(log n)

Skew Heap O(log n) O(log n) O(log n)

Binomial ■ O(log n) worst case O(log n) O(log n)


Heap ■ O(1) amortized
for sequence of n
inserts
Fibonacci Heap O(1) O(log n) O(1)
Priority Queues in STL
■ Uses Binary
#include
heap <priority_queue> int
main ()
{

■ Default
Methodsis MaxHeap priority_queue<int>
Q; Q.push (10);
■ Push, top, pop, cout << Q.top
empty, clear (); Q.pop ();
}
Calls DeleteMax()

For MinHeap: declare priority_queue as:


priority_queue<int, vector<int>, greater<int>> Q;
Summary

■ Priority queues maintain the minimum


or maximum element of a set
■ Support O(log N) operations worst-case
■ insert, deleteMin, merge
■ Many applications in support of other
algorithms
Facts about Heaps
Observations:
• Finding a child/parent index is a multiply/divide by two

• Operations jump widely through the heap

• Each percolate step looks at only two new nodes

• Inserts are at least as common as deleteMins

Realities:
• Division/multiplication by powers of two are equally fast

• Looking at only two new pieces of data: bad for cache!

• With huge data sets, disk accesses dominate


Cycles to access:

CPU

Cache

Memory

Disk
A Solution: d-Heaps
• Each node has d children
• Still representable by array 1
• Good choices for d:
• (choose a power of two for 3 7 2
efficiency)
• fit one set of children in a 1 1 1
4 8 5 6 9
cache line 2 1 0
• fit one set of children on a 1 1 1 1
1 3 7 2 4 8 5 6 9
memory page/disk block 2 2 1 0
One More Operation
• Merge two heaps

• Add the items from one into another?


• O(n log n)

• Start over and build it from scratch?


• O(n)
Leftist Heaps
• Review of Min Heaps
• Introduction of Left-ist Heaps
• Merge Operation
• Heap Operations
Review of Heaps
Min Binary Heap
• A min binary heap is a…
– Complete binary tree
– Neither child is smaller than the value in the parent
– Both children are at least
as large as the parent
• In other words,
smaller items go
above larger ones
Min Binary Heap Performance

• Performance
– (n is the number of elements in the heap)

• construction O( n )
• findMin() O( 1 )
• insert() O( lg n )
• deleteMin() O( lg n )
Problem
• Suppose you’re using more than one heap
– Multiple emergency rooms, etc.
• What if you need to merge them?
– One is too small, etc.
• Merging regular heaps is O(m+n)
Introduction to Leftist
Heaps
Leftist Heaps
Idea:
Focus all heap maintenance work in one small part of the heap

Leftist heaps:
1. Most nodes are on the left
2. All the merging work is done on the right
Definition: Null Path Length
null path length (npl) of a node x = the number of nodes between x
and a null in its subtree
OR
npl(x) = min distance to a descendant with 0 or 1 children

• npl(null) = -1 ?
• npl(leaf) = 0
• npl(single-child node) = 0 ? ?

Equivalent definitions: 0 1 ? 0

1. npl(x) is the height of largest


complete subtree rooted at x 0 0 0
2. npl(x) = 1 + min{npl(left(x)), npl(right(x))}
62
Leftist Heap Properties
• Heap-order property
• parent’s priority value is ≤ to childrens’ priority values
• result: minimum element is at the root

• Leftist property
• For every node x, npl(left(x)) ≥ npl(right(x))
• result: tree is at least as “heavy” on the left as the right
Are These Leftist?

2 2 0

1 1 1 1 0

0 1 0 0 1 0 0 0 1

0 0 0 0 0 0 0 0

0
Every subtree of a leftist
0
tree is leftist!
0
64
Leftist Heap Concepts
• Structurally, a leftist heap is a min tree where each
node is marked with a rank value.
• Uses a Binary Tree (BT)
• Merging heaps is much easier and faster
– May use already established links to merge with a new
node
– Rather than copying pieces of an array
Leftist Heap Concepts
• Values STILL obey a heap order (partial order)
• Uses a null path length to maintain the structure
(covered in detail later)
– The null path of a node’s left child is >=
null path of the right child
• At every node, the shortest path to a non-full node is
along the rightmost path
Leftist Heap Example
• A leftist heap, then, is a
purposefully unbalanced 2
binary tree (leaning to the
left, hence the name) that 3 7
keeps its smallest value at
9 8 10 15
the top and has an
inexpensive merge 8
operation
Leftist Heap Performance

• Leftist Heaps support:


– findMin() = O(1)
– deleteMin() = O(log n)
– insert() = O(log n)
– construct = O(n)
– merge() = O(log n)
Null Path Length (npl)
• Length of shortest path from current node to a node
without exactly 2 children
– value is stored IN the node itself
• leafs
– npl = 0
• nodes with only 1 child
– npl = 0
Null Path Length (npl) Calculation
To calculate the npl for each node,
we look to see how many nodes
we need to traverse to get to an
2 open node

3 7
9 8 10 15
8
Null Path Length (npl) Calculation
Leaves -> npl = 0
One
2 child -> npl = 0
Others -> npl = 1 + min(left, right)
2

2
1 1

3 7
0 0 0 0

9 8 10 15
0

8
Leftist Node
• The leftist heap node should keep track of:
– links (left and right)
– element (data)
– npl
Leftist Node Code
Looks like a binary
private:
struct LeftistNode tree node except the
{
Comparable element;
npl being stored.
LeftistNode *left;
LeftistNode *right;
int npl;

LeftistNode( const Comparable & theElement, LeftistNode *lt = NULL,


LeftistNode *rt = NULL, int np = 0 )
: element( theElement ), left( lt ), right( rt ), npl( np ) { }
};

LeftistNode *root;
Building a Leftist Heap
Building a Leftist Heap
• Value of node STILL matters
– Lowest value will be root, so still a min Heap
• Data entered is random

• Uses CURRENT npl of a node to determine where the


next node will be placed
Leftist Heap Algorithm
• Add new node to right-side of tree, in order
• If new node is to be inserted as a parent (parent < children)
– make new node parent
– link children to it
– link grandparent down to new node (now new parent)
• If leaf, attach to right of parent
• If no left sibling, push to left (hence left-ist)
– why?? (answer in a second)
• Else left node is present, leave at right child
• Update all ancestors’ npls
• Check each time that all nodes left npl > right npls
– if not, swap children or node where this condition exists
Merging Leftist Heaps
Merging Leftist Heaps
• In the code, adding a single node is treated as
merging a heap (just one node) with an established
heap’s root
– And work from that root as we just went over
Merging Leftist Heaps
• The heaps we are about to merge must be LEFTIST
heaps
• At the end we will get a heap that is both
– a min-heap
– leftist
Merging Leftist Heaps
• The Merge procedure takes two leftist trees, A and B,
and returns a leftist tree that contains the union of
the elements of A and B. In a program, a leftist tree is
represented by a pointer to its root.
Merging Leftist Heaps Example
2
1 0
1 1
5 22
7 0
0 0 1 0
75
10 15 20 25
0 0

50 99

Where should we
attempt to merge?
Merging Leftist Heaps Example

7 22

75
20 25

50 99

In the right sub-tree


Merging Leftist Heaps Example

22

75
25

All the way down to


the right most node
Merging Leftist Heaps Example

22
75 25

Important: We don’t “split”


As there are two a heap, so 22 must be
nodes in the right the parent in this merge
subtree, swap.
Merging Leftist Heaps Example

22

75 25

Merge two subtrees


Merging Leftist Heaps Example

20 22
50 99 75 25

Next level of the tree


Merging Leftist Heaps Example
1
1 2

5 7

10 15 20 22

50 99 75 25

Right side of the tree


has a npl of 2 so we
need to swap
Merging Leftist Heaps Example
2
1
2 1

7 5

20 22 10 15
50 99 75 25

Now the highest npl


is on the left.
Merging Leftist Heaps
– Compare the roots. Smaller root becomes new root of
subheap
– “Hang up” the left child of the new root
– Recursively merge the right subheap of the new root with
the other heap.
– Update the npl
– Verify a leftist heap! (left npl >= right npl)
• if not, swap troubled node with sibling
Merging Leftist Heaps Code
/**
* Merge rhs into the priority queue.
* rhs becomes empty. rhs must be different from this.
*/
void merge( LeftistHeap & rhs )
{
if( this == &rhs ) // Avoid aliasing problems
return;

root = merge( root, rhs.root );


rhs.root = NULL;
}
Merging Leftist Heaps Code
/**
* Internal method to merge two roots.
* Deals with deviant cases and calls recursive merge1.
*/
LeftistNode * merge( LeftistNode *h1, LeftistNode *h2 )
{
if( h1 == NULL )
return h2;
if( h2 == NULL )
return h1;
if( h1->element < h2->element )
return merge1( h1, h2 );
else
return merge1( h2, h1 );
}
Merging Leftist Heaps Code
/**
* Internal method to merge two roots.
* Assumes trees are not empty, & h1's root contains smallest item.
*/
LeftistNode * merge1( LeftistNode *h1, LeftistNode *h2 )
{
if( h1->left == NULL ) // Single node
h1->left = h2; // Other fields in h1 already accurate
else
{
h1->right = merge( h1->right, h2 );
if( h1->left->npl < h1->right->npl )
swapChildren( h1 );
h1->npl = h1->right->npl + 1;
}
return h1;
}
Deleting from Leftist
Heap
Deleting from Leftist Heap
• Simple to just remove a node (since at top)
– this will make two trees
• Merge the two trees like we just did
Deleting from Leftist Heap
We remove the root.
2
1
3
1

8 10
0 0 0 0

14 23 21 17
0

26
Deleting from Leftist Heap
Then we do a merge
2
and because min is in
1
3 left subtree, we
1

8 recursively merge
10
0 0 0 0 right into left
14 23 21 17
0

26
Deleting from Leftist Heap
Then we do a merge
2
and because min is in
3 left subtree, we
1 1

8 recursively merge
10
0 0 0 0 right into left
14 23 21 17
0

26
Deleting from Leftist Heap
1
After Merge
8
1 0

10 14
1 0

17 26
0 0

21 23
Leftist Heaps
• Merge with two trees of size n
– O(log n), we are not creating a totally new tree!!
– some was used as the LEFT side!
• Inserting into a left-ist heap
– O(log n)
– same as before with a regular heap
• deleteMin with heap size n
– O(log n)
– remove and return root (minimum value)
– merge left and right subtrees
Skew Heaps
Problems with leftist heaps
• extra storage for npl
• extra complexity/logic to maintain and check npl
• right side is “often” heavy and requires a switch
Solution: skew heaps
• “blindly” adjusting version of leftist heaps
• merge always switches children when fixing right path
• amortized time for: merge, insert, deleteMin = O(log n)
• however, worst case time for all three = O(n)
Merging Two Skew Heaps
merge
T1
a a
merge
L R R L
a<b
1 1 1
1
T2 b b

L R L R
2 2 2 2

Only one step per iteration, with children always switched


Example
merge
5 3 3
merge
1 1 7 5 7
0 2 5
1 merge 1 1
1 1 1
3 4 0 4
0 2 2
8
7 8 8
3
1
4
5 7
1 1
8
0 4
1
2
Skew Heap Code
void merge(heap1, heap2) {
case {
heap1 == NULL: return heap2;
heap2 == NULL: return heap1;
heap1.findMin() < heap2.findMin():
temp = heap1.right;
heap1.right = heap1.left;
heap1.left = merge(heap2, temp);
return heap1;
otherwise:
return merge(heap2, heap1);
}
}
Runtime Analysis:
Worst-case and Amortized
• No worst case guarantee on right path length!
• All operations rely on merge

⇒ worst case complexity of all ops =


• Probably won’t get to amortized analysis in this
course, but see Chapter 11 if curious.
• Result: M merges take time M log n

⇒ amortized complexity of all ops =


Comparing Heaps
• Binary Heaps • Leftist Heaps

• d-Heaps • Skew Heaps


THANK
YOU

You might also like