0% found this document useful (0 votes)
22 views33 pages

Chapter 5

Chapter 5 covers the heap data structure, which is an efficient implementation of a priority queue allowing logarithmic time for insertions and removals. It discusses the properties of heaps, their representation as complete binary trees, and the implementation of priority queues using heaps in C++. The chapter also includes details on heap sort and bottom-up heap construction methods.

Uploaded by

igcasan.jc07
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)
22 views33 pages

Chapter 5

Chapter 5 covers the heap data structure, which is an efficient implementation of a priority queue allowing logarithmic time for insertions and removals. It discusses the properties of heaps, their representation as complete binary trees, and the implementation of priority queues using heaps in C++. The chapter also includes details on heap sort and bottom-up heap construction methods.

Uploaded by

igcasan.jc07
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/ 33

Chapter 5

C+ + HE A PS
Contents
I. Lesson 5.1 – Heap
• Heap Data Structure
• The Height of a Heap
• Complete Binary Tree ADT
• A Vector Representation of Complete Binary Tree

II. Lesson 5.2 – Priority Queue with a Heap


• Insertion
• Removal
• Down Heap Bubbling after a Removal
III. Lesson 5.3 – C++ Implementation
IV. Lesson 5.4 – Heap Sort
• Implementing Heap Sort in Place
• Bottom Up Heap Construction
Lesson 5.1 - Heap
• An efficient realization of a priority queue uses a data structure called
a heap. This data structure allows us to perform both insertions and
removals in logarithmic time, which is a significant improvement over
the list-based implementations discussed in previous lessons. The
fundamental way the heap achieves this improvement is to abandon
the idea of storing elements and keys in a list and take the approach
of storing elements and keys in a binary tree instead.
Heap Data Structure
• A heap (see Figure 5.1.1) is a binary tree T that stores a collection of
elements with their associated keys at its nodes and that satisfies two
additional properties: a relational property, defined in terms of the
way keys are stored in T, and a structural property, defined in terms of
the nodes of T itself. We assume that a total order relation on the keys
is given, for example, by a comparator.
• Figure 5.1.1 Example of a heap storing 13 elements. Each element is a
key-value pair of the form (k,v). The heap is ordered based on the key
value, k, of each element.
• The relational property of T, defined in terms of the way keys are
stored, is the following:
• Heap-Order Property: In a heap T, for every node v other than the root,
the key associated with v is greater than or equal to the key
associated with v’s parent.
• As a consequence of the heap-order property, the keys encountered
on a path from the root to an external node of T are in nondecreasing
order. Also, a minimum key is always stored at the root of T. This is
the most important key and is informally said to be “at the top of the
heap,” hence, the name “heap” for the data structure.
The Height of a Heap
• Let h denote the height of T. Another way of defining the last node of
T is that it is the node on level h such that all the other nodes of level
h are to the left of it. Insisting that T be complete also has an
important consequence as shown in Proposition 5.1.1.
• Proposition 5.1.1 A heap T storing n entries has height
h = ⌊log n⌋.
• Justification: From the fact that T is complete, we know that there are
2i nodes in level, i for 0 ≤ i ≤ h − 1, and level h has at least 1 node. Thus,
the number of nodes of T is at least
(1+2+4+···+2h-1) +1 = (2h −1) +1
= 2h
• Level h has at most 2h nodes, and thus the number of nodes of T is at
most
(1+2+4+···+2h-1) +2h = 2h+1 −1.
• Since the number of nodes is equal to the number n of entries, we obtain
2h ≤ n
and
n ≤ 2h+1 −1.
• Thus, by taking logarithms of both sides of these two inequalities, we see
that
h ≤ log n
and
log(n+1)−1 ≤ h.
• Since h is an integer, the two inequalities above imply that
h = ⌊log n⌋.
Complete Binary Tree ADT
• As an abstract data type, a complete binary tree T supports all the
functions of the binary tree ADT, plus the following two functions:
• add(e): Add to T and return a new external node v storing element e, such that
the resulting tree is a complete binary tree with last node v.
• remove(): Remove the last node of T and return its element.
• By using only these update operations, the resulting tree is
guaranteed to be a complete binary. As shown in Figure 5.1.2, there
are essentially two cases for the effect of an add (and remove is
similar).
• Figure 5.1.2 Examples of operations add and remove on a complete
binary tree, where w denotes the node inserted by add or deleted by
remove. The trees shown in (b) and (d) are the results of performing add
operations on the trees in (a) and (c), respectively. Likewise, the trees
shown in (a) and (c) are the results of performing remove operations on
the trees in (b) and (d), respectively.
A Vector Representation of Complete
Binary tree
• The vector-based binary tree representation is especially suitable for
a complete binary tree T. We recall that in this implementation, the
nodes of T are stored in a vector A such that node v in T is the element
of A with index equal to the level number f(v) defined as follows:
• If v is the root of T, then f(v) = 1
• If v is the left child of node u, then f(v) = 2 f(u)
• If v is the right child of node u, then f(v) = 2 f(u) +1
• With this implementation, the nodes of T have contiguous indices in
the range [1,n] and the last node of T is always at index n, where n is
the number of nodes of T. Figure 5.1.2 shows two examples
illustrating this property of the last node.
Lesson 5.2 – Priority Queue with a Heap
• Our heap-based representation for a priority queue P consists of the
following (see Figure 5.2.1):
• heap: A complete binary tree T whose nodes store the elements of the queue and
whose keys satisfy the heap-order property. We assume the binary tree T is
implemented using a vector, as described in Section 8.3.2. For each node v of T,
we denote the associated key by k(v).
• comp: A comparator that defines the total order relation among the keys.
Figure 5.2.1: Illustration of the heap-based
implementation of a priority queue.
Insertion
• Let us consider how to perform insert on a priority queue implemented with
a heap T. To store a new element e in T, we add a new node z to T with
operation add, so that this new node becomes the last node of T, and then
store e in this node.
• After this action, the tree T is complete, but it may violate the heap-order
property. Hence, unless node z is the root of T (that is, the priority queue
was empty before the insertion), we compare key k(z) with the key k(u)
stored at the parent u of z. If k(z) ≥ k(u), the heap-order property is satisfied
and the algorithm terminates. If instead k(z) < k(u), then we need to restore
the heap-order property, which can be locally achieved by swapping the
entries stored at z and u. (See Figures 5.2.2(c) and (d).) This swap causes the
new entry (k,e) to move up one level. Again, the heap-order property may
be violated, and we continue swapping, going up in T until no violation of
the heap-order property occurs. (See Figures 5.2.2(e) and (h).)
• Figure 5.2.2: Insertion of a new entry
with key 2 into the heap of Figure
5.2.1: (a) initial heap; (b) after
performing operation add; (c) and (d)
swap to locally restore the partial
order property; (e) and (f) another
swap; (g) and (h)final swap.
Removal
• The algorithm for
performing function
removeMin using heap T
is illustrated in Figure
5.2.3.
• Figure 5.2.3 : Removing the element with the smallest key from a heap:
(a) and (b) deletion of the last node, whose element is moved to the
root; (c) and (d) swap to locally restore the heap-order property; (e) and
(f) another swap; (g) and (h) final swap.
Down-Heap Bubbling after a Removal
• We are not necessarily done, however, for, even though T is now
complete, T may now violate the heap-order property. If T has only
one node (the root), then the heap-order property is trivially satisfied
and the algorithm terminates. Otherwise, we distinguish two cases,
where r denotes the root of T:
• If r has no right child, let s be the left child of r
• Otherwise (r has both children), let s be a child of r with the smaller key
Lesson 5.3 - C++ Implementation
• In Code below, we present the class definition. The public part of the
class is essentially the same as the interface, but, in order to keep the
code simple, we have ignored error checking. The class’s data
members consists of the complete tree, named T, and an instance of
the comparator object, named isLess. We have also provided a type
definition for a node position in the tree, called Position.
template <typename E, typename C>
class HeapPriorityQueue {
public:
int size() const; // number of elements
bool empty() const; // is the queue empty?
void insert(const E& e); // insert element
const E& min(); // minimum element
void removeMin(); // remove minimum
private:
VectorCompleteTree<E> T; // priority queue contents
C isLess; // less-than comparator
// shortcut for tree position
typedef typename VectorCompleteTree<E>::Position Position;
};
• In Code Fragment below, we present implementations of the simple
member functions size, empty, and min. The function min returns a
reference to the root’s element through the use of the “*” operator, which is
provided by the Position class of VectorCompleteTree.
template <typename E, typename C> // number of elements
int HeapPriorityQueue<E,C>::size() const
{ return T.size(); }
template <typename E, typename C> // is the queue empty?
bool HeapPriorityQueue<E,C>::empty() const
{ return size() == 0; }
template <typename E, typename C> // minimum element
const E& HeapPriorityQueue<E,C>::min()
{ return *(T.root()); } // return reference to root element
- An implementation of the function insert.
template <typename E, typename C> // insert element
void HeapPriorityQueue<E,C>::insert(const E& e) {
T.addLast(e); // add e to heap
Position v = T.last(); // e’s position
while (!T.isRoot(v)) { // up-heap bubbling
Position u = T.parent(v);
if (!isLess(*v, *u)) break; // if v in order, we’re done
T.swap(v, u); // . . .else swap with parent
v = u;
}
}
- A heap-based implementation of a priority
queue.
template <typename E, typename C> // remove minimum

void HeapPriorityQueue<E,C>::removeMin() {

if (size() == 1) // only one node?

T.removeLast(); // . . .remove it

else {

Position u = T.root(); // root position

T.swap(u, T.last()); // swap last with root

T.removeLast(); // . . .and remove last

while (T.hasLeft(u)) { // down-heap bubbling

Position v = T.left(u);
if (T.hasRight(u) && isLess(*(T.right(u)), *v))
v = T.right(u); // v is u’s smaller child
if (isLess(*v, *u)) { // is u out of order?
T.swap(u, v); // . . .then swap
u = v;
}
else break; // else we’re done
}}}
Implementing Heap-Sort In-Place
• This performance is accomplished by modifying the algorithm as
follows:
1. We use a reverse comparator, which corresponds to a heap where the largest
element is at the top. At any time during the execution of the algorithm, we
use the left portion of L, up to a certain rank i−1, to store the elements in the
heap, and the right portion of L, from rank i to n−1 to store the elements in the
list. Thus, the first i elements of L (at ranks 0,...,i−1) provide the vector
representation of the heap (with modified level numbers starting at 0 instead
of 1), that is, the element at rank k is greater than or equal to its “children” at
ranks 2k+1 and 2k+2.
2. In the first phase of the algorithm, we start with an empty heap and
move the boundary between the heap and the list from left to right,
one step at a time. In step i (i = 1,...,n), we expand the heap by
adding the element at rank i−1 and perform up-heap bubbling.
3. In the second phase of the algorithm, we start with an empty list
and move the boundary between the heap and the list from right to
left, one step at a time. At step i (i = 1,...,n), we remove a maximum
element from the heap and store it at rank n−i.
• Figure 5.4.1 In-place heap-sort.
Parts (a) through (e) show the
addition of elements to the heap;
(f) through (j) show the removal
of successive elements. The
portions of the array that are used
for the heap structure are shown
in blue.
Bottom-Up Heap Construction
• Heap class instead of filling a heap using a series of n insert
operations. For simplicity, we describe this bottom-up heap
construction assuming the number n of keys is an integer of the type
n = 2h − 1. That is, the heap is a complete binary tree with every level
being full, so the heap has height h = log(n+1).
• Viewed nonrecursively, bottom-up heap construction consists of the
following h = log(n+1) steps:
1. In the first step (see Figure 5.4.2(a)), we construct (n+1)/2
elementary heaps storing one entry each.
2. In the second step (see Figure 5.4.2(b)–(c)), we form (n+ 1)/4 heaps,
each storing three entries, by joining pairs of elementary heaps and
adding a new entry. The new entry is placed at the root and may
have to be swapped with the entry stored at a child to preserve the
heap-order property.
3. In the third step (see Figure 5.4.2(d)–(e)), we form (n + 1)/8 heaps,
each storing 7 entries, by joining pairs of 3-entry heaps (constructed
in the previous step) and adding a new entry. The new entry is
placed initially at the root, but may have to move down with a
down-heap bubbling to preserve the heap-order property.
• Figure 5.4.2: Bottom-up
construction of a heap with 15
entries: (a) we begin by
constructing one-entry heaps on
the bottom level; (b) and (c) we
combine these heaps into three-
entry heaps; (d) and (e) seven-
entry heaps; (f) and (g) we create
the final heap. The paths of the
down-heap bubblings are
highlighted in blue. For simplicity,
we only show the key within each
node instead of the entire entry.

You might also like