Chapter 12 Heaps & HeapSort © John Urrutia 2014, All Rights Reserved1
Heaps – Versus – Priority Queues Priority queues implemented as sorted arrays Insertion – O(N) (slow) Deletion – O(1) (fast) Heaps implemented as an array Insertion – O(logN) (faster than PQs) Deletion – O(logN) (slower than PQs) © John Urrutia 2014, All Rights Reserved2
Heaps – Versus – Priority Queues Conceptually – Priority Queues are wrappers for Heaps or Arrays The methods are same Both are ADT’s © John Urrutia 2014, All Rights Reserved3
Introduction to Heaps A heap is a binary tree with conditions. Completeness All levels are full except the lowest All nodes on the lowest level are filled left to right with no gaps Heap Condition Each node’s key >= the keys of its children Heaps are weakly ordered binary trees Lacks the ability to traverse in order Every path from root to leaf are in descending order Each path is independent of every other. © John Urrutia 2014, All Rights Reserved4
Heap Nodes public Node { private int iData; public Node(int key) { iData = key; } public int getKey() { return iData; } public void setKey(int id) { iData = id; } } © John Urrutia 2014, All Rights Reserved5
Heap Array class Heap {private Node[] heapArray; private int maxSize = 256; private int currentSize = 0; public Heap(int mx) {maxSize = mx; currentSize = 0; heapArray = new Node[maxSize]; } © John Urrutia 2014, All Rights Reserved6
Heap © John Urrutia 2014, All Rights Reserved7
Heap Array Implementation © John Urrutia 2014, All Rights Reserved8
Introduction to Heaps Creating the array to hold the heap Given array index for a node X : The parent of X is – ( X -1)/2 The left Child of X is – 2 * X + 1 The right Child of X is – 2 * X + 2 © John Urrutia 2014, All Rights Reserved9
Introduction to Heaps Because Heaps are weakly ordered binary trees Searching for a key is slow O(N) Deleting for a key is slow O(N) Adding the minimum key is fast O(1) since it is always at the end leaf or end of the array. © John Urrutia 2014, All Rights Reserved10
Introduction to Heaps Because Heaps are weakly ordered binary trees Removing the maximum key is fast O(1) since it is always at the root or top of the array, but that violates the completeness of the heap Replace the root with the minimum key which is the last entry in the array is fast O(1) since it always at the end, but violates the heap condition The solution: Replace the root with the minimum key Percolate the root node down until it is in the right position © John Urrutia 2014, All Rights Reserved11
Heap – Remove Max Key © John Urrutia 2014, All Rights Reserved12
Heap – Remove code Deletes the root node (contains the maximum Key ) public Node remove() {Node root = heapArray[0]; heapArray[0] = heapArray[--currentSize]; trickleDown(0); return root; } © John Urrutia 2014, All Rights Reserved13
Heap – Remove code Deletes the root node (contains the maximum Key ) public void trickleDown(int index) { int largerChild; Node top = heapArray[index];// save root while (index < currentSize / 2// while node has at least 1 child {int leftChild = 2 * index + 1; int rightChild = leftChild + 1;// find larger child if (rightChild < currentSize &&// (rightChild exists?) heapArray[leftChild].getKey() < heapArray[rightChild].getKey()) largerChild = rightChild; else largerChild = leftChild; if (top.getKey() >= heapArray[largerChild].getKey()) break; heapArray[index] = heapArray[largerChild]; index = largerChild; } // end while heapArray[index] = top;// root to index } © John Urrutia 2014, All Rights Reserved14
Introduction to Heaps Inserting a non-minimum Node Searching or finding a node position is O(N) The solution: Place the node after the minimum key at the end of the array Percolate the node up until it is in the right position © John Urrutia 2014, All Rights Reserved15
Heap – Insert non-minimum © John Urrutia 2014, All Rights Reserved16
Introduction to Heaps Copy vs. Swap Swapping involves 3 steps for each node Copying involves 1 Step for each node except the last Copy A to Temp Copy B to A Copy C to B Copy D to C Copy temp to D Copy A to Temp Copy B to A Copy Temp to B Copy B to Temp Copy C to B Copy Temp to C Copy C to Temp Copy D to C Copy Temp to D © John Urrutia 2014, All Rights Reserved17
Heap – Insert non-minimum © John Urrutia 2014, All Rights Reserved18
Heap – Insert code Inserts the last node public Boolean insert(int key) { if (currentSize == maxSize) return false; Node newNode = new Node(key); heapArray[currentSize] = newNode; trickleUp(currentSize++); return true; } // end insert() © John Urrutia 2014, All Rights Reserved19
Heap – Insert code Inserts the last node public void trickleUp(int index) { int parent = (index - 1) / 2; Node bottom = heapArray[index]; while (index > 0 && heapArray[parent].getKey() < bottom.getKey()) { heapArray[index] = heapArray[parent]; // move it down index = parent; parent = (parent - 1) / 2; } // end while heapArray[index] = bottom; } // end trickleUp() © John Urrutia 2014, All Rights Reserved20
The Heapsort The structure of a heap unexpectedly lends itself to sorting unordered data. Recall in a heap the maximum key is always at the root Hence repeatedly removing the root will return the data in descending sequence. The steps: Insert each item into a heap O(logN) Remove each root item from heap O(logN) Each must be executed N times giving O(N*logN) the same as quicksort © John Urrutia 2014, All Rights Reserved21
The Heapsort Efficiency of O(N*logN) (the same as quicksort) is actually longer – more instructions in the loop. Two tricks to improve efficiency Load all array items randomly Trickle-down the root N/2 times © John Urrutia 2014, All Rights Reserved22
15 Element Random Array © John Urrutia 2014, All Rights Reserved [00] [01] [02] [03] [04] [05] [06] [07] [08] [09] [10] [11] [12] [13] [14] L0 L3 L2 L1 Heap Levels
Trickledown heapsort © John Urrutia 2014, All Rights Reserved L2 L1 L0
Heapsort Array © John Urrutia 2014, All Rights Reserved [00] [01] [02] [03] [04] [05] [06] [07] [08] [09] [10] [11] [12] [13] [14] L0 L3 L2 L1 Heap Levels
Heapsort – Create Heap & Load with random numbers public static void Main(String[] args) { int size, j; Console.Write("Enter number of items: "); size = int.Parse(Console.ReadLine()); Heap theHeap = new Heap(size); Random rnd = new Random(); for(j=0; j<size; j++) // fill array with { // random nodes int random = (int)rnd.Next(0,100); Node newNode = new Node(random); theHeap.insertAt(j, newNode); theHeap.incrementSize(); } © John Urrutia 2014, All Rights Reserved26
Heapsort – Applies the heap rule to the array for(j=size/2-1; j>=0; j--) // make random array into heap theHeap.trickleDown(j); for(j=size-1; j>=0; j--) // remove from heap and { // store at array end Node biggestNode = theHeap.remove(); theHeap.insertAt(j, biggestNode); } Console.Write("Sorted: "); for(int j=0; j<maxSize; j++) { Console.Write(heapArray[j].getKey() + " "); Console.WriteLine(""); } © John Urrutia 2014, All Rights Reserved27
Heapsort – Sorted Array © John Urrutia 2014, All Rights Reserved
Last Note on Heapsort Although heapsort is slightly less efficient than Quicksort, it makes up for this by being less sensitive to the initial data distribution. Quicksort can slow to O(N 2 ) whereas heapsort remains O(N*logN) regardless of distribution. © John Urrutia 2014, All Rights Reserved29
Summary In an ascending-priority queue the item with the largest key is said to have the highest priority. (It’s the smallest item in a descending queue.) A priority queue is an Abstract Data Type (ADT) that offers methods for insertion of data and removal of the largest (or smallest) item. A heap is an efficient implementation of an ADT priority queue. A heap offers removal of the largest item, and insertion, in O(N*logN) time. © John Urrutia 2014, All Rights Reserved30
Summary The largest item is always in the root. Heaps do not support ordered traversal of the data, locating an item with a specific key, or deletion. A heap is usually implemented as an array representing a complete binary tree. The root is at index 0 and the last item at index N-1. © John Urrutia 2014, All Rights Reserved31
Summary Each node has a key less than its parents and greater than its children. An item to be inserted is always placed in the first vacant cell of the array and then trickled up to its appropriate position. When an item is removed from the root, it’s replaced by the last item in the array, which is then trickled down to its appropriate position. The trickle-up and trickle-down processes can be thought of as a sequence of swaps, but are more efficiently implemented as a sequence of copies. © John Urrutia 2014, All Rights Reserved32
Summary The priority of an arbitrary item can be changed. First, its key is changed. Then, if the key was increased, the item is trickled up, but if the key was decreased, the item is trickled down. A heap can be based on a binary tree (not a search tree) that mirrors the heap structure; this is called a treeheap. Algorithms exist to find the last occupied node or the first free node in a treeheap. © John Urrutia 2014, All Rights Reserved33
Summary Heapsort is an efficient sorting procedure that requires O(N*logN) time. Conceptually, heapsort consists of making N insertions into a heap, followed by N removals. Heapsort can be made to run faster by applying the trickle-down algorithm directly to N/2 items in the unsorted array, rather than inserting N items. The same array can be used for the initial unordered data, for the heap array, and for the final sorted data. Thus, heapsort requires no extra memory. © John Urrutia 2014, All Rights Reserved34