Figure 1: A complete binary tree.

Similar documents
Figure 1: A complete binary tree.

Priority Queues. Binary Heaps

Data Structures. Giri Narasimhan Office: ECS 254A Phone: x-3748

CS350: Data Structures Heaps and Priority Queues

Priority Queues (Heaps)

Priority Queues and Binary Heaps. See Chapter 21 of the text, pages

Priority Queues and Binary Heaps. See Chapter 21 of the text, pages

CE 221 Data Structures and Algorithms

Priority Queues (Heaps)

Data Structures Lesson 9

CSCI2100B Data Structures Heaps

COMP : Trees. COMP20012 Trees 219

Implementations. Priority Queues. Heaps and Heap Order. The Insert Operation CS206 CS206

3. Priority Queues. ADT Stack : LIFO. ADT Queue : FIFO. ADT Priority Queue : pick the element with the lowest (or highest) priority.

CMSC 341 Priority Queues & Heaps. Based on slides from previous iterations of this course

CS 315 April 1. Goals: Heap (Chapter 6) continued review of Algorithms for Insert DeleteMin. algoritms for decrasekey increasekey Build-heap

Priority Queues Heaps Heapsort

Priority Queues Heaps Heapsort

Data Structures and Algorithms

Algorithms and Data Structures

Tree: non-recursive definition. Trees, Binary Search Trees, and Heaps. Tree: recursive definition. Tree: example.

CMSC 341 Lecture 14: Priority Queues, Heaps

! Tree: set of nodes and directed edges. ! Parent: source node of directed edge. ! Child: terminal node of directed edge

Priority Queues. e.g. jobs sent to a printer, Operating system job scheduler in a multi-user environment. Simulation environments

Heaps, Heap Sort, and Priority Queues.

Priority Queues. 1 Introduction. 2 Naïve Implementations. CSci 335 Software Design and Analysis III Chapter 6 Priority Queues. Prof.

! Tree: set of nodes and directed edges. ! Parent: source node of directed edge. ! Child: terminal node of directed edge

Binary Heaps. CSE 373 Data Structures Lecture 11

CSE373: Data Structures & Algorithms Lecture 9: Priority Queues and Binary Heaps. Nicki Dell Spring 2014

Readings. Priority Queue ADT. FindMin Problem. Priority Queues & Binary Heaps. List implementation of a Priority Queue

CSE 373: Data Structures and Algorithms

Binary Heaps. COL 106 Shweta Agrawal and Amit Kumar

Heap Model. specialized queue required heap (priority queue) provides at least

The priority is indicated by a number, the lower the number - the higher the priority.

CMSC 341. Binary Heaps. Priority Queues

CSE373: Data Structures & Algorithms Lecture 9: Priority Queues and Binary Heaps. Linda Shapiro Spring 2016

CS 240 Fall Mike Lam, Professor. Priority Queues and Heaps

Chapter 6 Heaps. Introduction. Heap Model. Heap Implementation

Priority Queues and Binary Heaps

Recall: Properties of B-Trees

Sorting and Searching

Sorting and Searching

CS 234. Module 8. November 15, CS 234 Module 8 ADT Priority Queue 1 / 22

UNIT III BALANCED SEARCH TREES AND INDEXING

CSE332: Data Abstractions Lecture 4: Priority Queues; Heaps. James Fogarty Winter 2012

The Heap Data Structure

Comparisons. Θ(n 2 ) Θ(n) Sorting Revisited. So far we talked about two algorithms to sort an array of numbers. What is the advantage of merge sort?

Topic: Heaps and priority queues

CSE 332, Spring 2010, Midterm Examination 30 April 2010

Comparisons. Heaps. Heaps. Heaps. Sorting Revisited. Heaps. So far we talked about two algorithms to sort an array of numbers

Algorithms, Spring 2014, CSE, OSU Lecture 2: Sorting

BM267 - Introduction to Data Structures

CSE 332: Data Structures & Parallelism Lecture 3: Priority Queues. Ruth Anderson Winter 2019

Today s Outline. The One Page Cheat Sheet. Simplifying Recurrences. Set Notation. Set Notation. Priority Queues. O( 2 n ) O( n 3 )

Properties of a heap (represented by an array A)

Heaps. Heapsort. [Reading: CLRS 6] Laura Toma, csci2000, Bowdoin College

CSE373: Data Structures & Algorithms Lecture 9: Priority Queues. Aaron Bauer Winter 2014

CMSC 341 Leftist Heaps

Priority queues. Priority queues. Priority queue operations

Programming II (CS300)

CSE 332 Autumn 2013: Midterm Exam (closed book, closed notes, no calculators)

Adam Blank Lecture 3 Winter 2017 CSE 332. Data Structures and Parallelism

Computer Science 210 Data Structures Siena College Fall Topic Notes: Priority Queues and Heaps

9. Heap : Priority Queue

AMORTIZED ANALYSIS. Announcements. CSE 332 Data Abstractions: Priority Queues, Heaps, and a Small Town Barber. Today.

CSE 214 Computer Science II Heaps and Priority Queues

quiz heapsort intuition overview Is an algorithm with a worst-case time complexity in O(n) data structures and algorithms lecture 3

CS2223: Algorithms Sorting Algorithms, Heap Sort, Linear-time sort, Median and Order Statistics

Binary Trees, Binary Search Trees

A data structure and associated algorithms, NOT GARBAGE COLLECTION

CS60020: Foundations of Algorithm Design and Machine Learning. Sourangshu Bhattacharya

Introduction to Algorithms 3 rd edition

Describe how to implement deque ADT using two stacks as the only instance variables. What are the running times of the methods

Data Structures in Java

Priority Queues and Heaps. Heaps of fun, for everyone!

CMSC 341 Lecture 15 Leftist Heaps

How much space does this routine use in the worst case for a given n? public static void use_space(int n) { int b; int [] A;

Sorting: Given a list A with n elements possessing a total order, return a list with the same elements in non-decreasing order.

Heaps. Heaps. A heap is a complete binary tree.

Data Structures and Algorithms Week 4

CS165: Priority Queues, Heaps

BINARY HEAP cs2420 Introduction to Algorithms and Data Structures Spring 2015

Overview of Presentation. Heapsort. Heap Properties. What is Heap? Building a Heap. Two Basic Procedure on Heap

TREES. Trees - Introduction

CMSC 341 Lecture 15 Leftist Heaps

Dictionaries. Priority Queues

Chapter 6 Heapsort 1

Abstract vs concrete data structures HEAPS AND PRIORITY QUEUES. Abstract vs concrete data structures. Concrete Data Types. Concrete data structures

CompSci 201 Tree Traversals & Heaps

Multi-way Search Trees! M-Way Search! M-Way Search Trees Representation!

Lec 17 April 8. Topics: binary Trees expression trees. (Chapter 5 of text)

Thus, it is reasonable to compare binary search trees and binary heaps as is shown in Table 1.

CSCI 136 Data Structures & Advanced Programming. Lecture 22 Fall 2018 Instructor: Bills

Data Structures and Algorithms for Engineers

Binary Heaps in Dynamic Arrays

COS 226 Fall2007 HW03 ( pts.) Due :00 p.m. Name:

Administration CSE 326: Data Structures

COMP Data Structures

Lecture 23: Priority Queues 10:00 AM, Mar 19, 2018

Data Structures and Algorithms Chapter 4

Transcription:

The Binary Heap A binary heap is a data structure that implements the abstract data type priority queue. That is, a binary heap stores a set of elements with a total order (that means that every two elements can be compared), and supports the following operations on this set: findmin returns the smallest element; deletemin() removes the smallest element from the set and returns it; insert(el) inserts a new element into the set; size returns the current size (number of elements) of the set. A complete binary tree is a binary tree in which every level is full, except possibly the bottom level, which is filled from left to right as in Fig. 1. For a given number of elements, the shape of the complete binary tree Figure 1: A complete binary tree. is prescribed completely by this description. A binary heap is a complete binary tree whose elements satisfy the heap-order property: no node contains an element less than its parent s element. Every subtree of a binary heap is also a binary heap, because every subtree is complete and satisfies the heap-order property. FindMin. We note that many different heaps are possible for the same data, as there are many different ways to satisfy the heap property. However, all possible heaps have one feature in common: A smallest element must be in the root node. This implies that the findmin operation is very easy it just returns the element from the root node. Insert. To insert an element into the binary heap, we first have to add a node to the tree. Because we need to maintain that the tree is complete, there is only one possible place where we can add the node: If the lowest level is not yet full, we need to add the next open position on this level. If the lowest level is full, we need to add a new node at the leftmost position on the next level, see Fig. 2 for both cases. Figure 2: Two cases of adding a node. 1

Of course, the new element may violate the heap-order property. We correct this by having the element bubble up the tree until the heap-order property is satisfied. More precisely, we compare the new element x with its parent; if x is less, we exchange x with its parent, then repeat the procedure with x and its new parent. Fig. shows the four stages during the insertion of the new element 2. 2 2 2 Figure : Adding element 2. When we finish, is the heap-order property satisfied? Yes, if the heap-order property was satisfied before the insertion. Let s look at a typical exchange of x with a parent p during the insertion operation. Since the heap-order property was satisfied before the insertion, we know that p s (where s is x s sibling, see Fig. ), p l, and p r (where l and r are x s children). We only swap if x < p, which implies that x < s; after the swap, x is the parent of s. After the swap, p is the parent of l and r. All other relationships in the subtree rooted at x are maintained, so after the swap, the tree rooted at x has the heap-order property. p x x s p s l r l r Figure : Maintaining the heap property during bubble-up. DeleteMin. The deletemin() operation starts by removing the entry at the root node and saving it for the return value. This leaves a gaping hole at the root. We fill the hole with the last entry in the tree (which we call x), so that the tree is still complete. It is unlikely that x is the minimum element. Fortunately, both subtrees rooted at the root s children are heaps, and thus the new mimimum element is one of these two children. We bubble x down the heap as 2

follows: if x has a child that is smaller, swap x with the child having the smaller element. Next, compare x with its new children; if x still violates the heap-order property, again swap x with the child with the smaller element. Continue until x is less than or equal to its children, or reaches a leaf. Fig. shows the stages in this process. Note that if in the original heap we replace by 10, then would not bubble down all the way to a leaf, but would remain on a higher level. Figure : Removing the minimum element. Array-based implementation. Of course a complete binary tree can be implemented as a linked data structure, with Node objects that store references to their parent and children. However, because the tree is complete, we can actually store it very compactly in an array. To do so, simply number the nodes of the tree from top to bottom, left to right, starting with one for the root, so that the nodes are numbered from 1 to n. We observe that the left child of node i has index 2i and the right child has index 2i + 1. The parent of node i has index i/2. We will simply store node i in slot i of an array, and we can move from a node to its parent or its children by doing simple arithmetic on the index. (We started numbering from 1 for convenience the numbers are nicer. Of course this means that we waste slot 0 of the array not a big problem, but it could be fixed by changing the numbering scheme slightly.) Implementation. We now give a complete implementation in Scala. Our Heap class can be constructed either by providing an array to be used, or by passing null (and the Heap class will create an array itself). It also takes a function object lessthan as an argument. This function object will be used to compare elements of type T, so that we can build heaps of objects that have no implicit ordering.

class Heap[T : ClassManifest](els: Array[T], val lessthan: (T,T) => Boolean) We use the doubling-technique for growing the array. Initially, we create an array of some default capacity, and set currentsize to zero. The methods size and findmin are very easy: def size: Int = currentsize def findmin: T = { if (currentsize == 0) throw new NoSuchElementException else A(1) The insert method first ensures there is enough space to add a node to the tree. For efficiency, we do not actually place x in the new node, but keep it empty (a hole ). Then we bubble the hole up in the tree until x is no longer smaller than the parent of the hole, and finally place x in the hole. def insert(x: T) { if (currentsize + 1 == A.length) doublearray() currentsize += 1 var hole = currentsize A(0) = x // Percolate up while (lessthan(x, A(hole/2))) { A(hole) = A(hole/2) hole /= 2 A(hole) = x Note that we use a little trick here: We put x into A(0). This allows us to skip a test for hole == 1 in the while-loop. Since the root has no parent, the loop should end there. However, since hole/2 == 0 for hole == 1, in the root we will compare x to A(0), that is to itself, so lessthan will return false and the loop will end automatically. Finally, the hardest operation is deletemin. It makes use of two internal methods. First, the method smallerchild(hole, inhole) checks whether one of the children of the node with index hole is smaller than the element inhole. If so, it returns the index of the smaller element, otherwise it returns zero: private def smallerchild(hole: Int, inhole: T): Int = { if (2 * hole <= currentsize) { var child = 2 * hole if (child!= currentsize && lessthan(a(child + 1), A(child))) child += 1 if (lessthan(a(child), inhole)) child else 0 else 0 The internal method percolatedown(i) bubbles down the element in node i:

private def percolatedown(i: Int) { val inhole = A(i) var hole = i var child = smallerchild(hole, inhole) while (child!= 0) { A(hole) = A(child) hole = child child = smallerchild(hole, inhole) A(hole) = inhole With these internal methods,deletemin() is rather easy: def deletemin(): T = { val minitem = findmin A(1) = A(currentSize) currentsize -= 1 percolatedown(1) minitem Analysis. Since the heap is always a complete binary tree, its height is O(log n) at any time, where n is the current size of the set. It follows that the operations deletemin and insert take time O(log n). The operations size and findmin take constant time. Now imagine we have n elements and we want to insert them into a binary heap. Calling insert n times would take total time O(n log n). Perhaps surprisingly, we can actually do better than this by creating an array for the n elements, throwing the elements into this array in some arbitrary order, and then running the following method: private def buildheap() { for (i <- currentsize / 2 to 1 by -1) percolatedown(i) The method works backward from the last internal node (non-leaf node) to the root node, in reverse order in the array or the level-order traversal. When we visit a node this way, we bubble its entry down the heap using percolatedown as in deletemin. We are making use of the fact that if the two subtrees of a node i are heaps, then after calling percolatedown(i) the subtree rooted at node i is a heap. By induction, this implies that when buildheap has completed, the entire tree is a binary heap. The running time of buildheap is somewhat tricky to analyze. Let h i denote the height of node i, that is, the length of a longest path from node i to a leaf. The running time of percolatedown(i) is clearly O(h i ), and so the running time of buildheap is O( n/2 i=1 h i ). How can we bound this sum? Here is a simple and elegant argument. For simplicity, let s assume that n = 2 h+1 1, so the tree has height h and is perfect all leaves are on level h. Clearly adding nodes on the bottom level can only increase the value of the sum. Now, for every node i there is a path P i of length h i from i to a leaf as follows: From i, go down to its right child. From there, always go down to the left child until you reach a leaf. It is easy to see that for two different nodes i and j, the paths P i and P j do not share any edge. It follows that the total number of edges of all the paths P i, for 1 i n, is at most the number of edges of the tree, which is n 1. So we have n i=1 h i n 1, and so the running time of buildheap is O(n).

Heap Sort Any priority queue can be used for sorting: def pqsort(a: Array[E]) { val Q = new PriorityQueue[E] for (el <- A) Q.insert(el) for (i <- 0 until A.length) A(i) = Q.deleteMin() The binary heap is particularly well suited to implement a sorting algorithm, because we can use the array containing the input data to implement the binary heap. We therefore obtain an in-place sorting algorithm, which sorts the data inside the array. Initially, we run buildheap to put the objects inside the array into heap order. We then remove them one by one using deletemin. Every time an element is removed from the heap, the heap needs one less array slot. We can use this slot to store the element that we just removed from the heap, and obtain the following algorithm: def heapsort(a: Array[Int]) { val heap = new Heap[Int](A, (x, y) => x < y) for (i <- A.length - 1 until 1 by -1) A(i) = heap.deletemin() Here is an example run: scala> val A = Array(0, 1, 2, 9,,, 1, 1, 89, ) A: Array[Int] = Array(0, 1, 2, 9,,, 1, 1, 89, ) scala> heapsort(a) scala> A res1: Array[Int] = Array(0, 89,,, 1, 1, 9,, 2, 1) The element in slot 0 of the array was not sorted, since our Heap implementation doesn t use this slot. This could be fixed by changing the indexing of the array. Also, the array is sorted backwards, because we have to fill it starting at the last index. This can be fixed by using a max-heap instead of a min-heap. In our implementation, all we need to do is to change the function object as follows: def heapsort(a: Array[Int]) { val heap = new Heap[Int](A, (x, y) => x > y) for (i <- A.length - 1 until 1 by -1) A(i) = heap.deletemin()