Hi, I'm Gayle Laakmann McDowell, author of Cracking the Coding Interview. Today we'll talk about a topic that a lot of candidates
forget about, heaps. Heaps come in one of two forms, a min heap or max heap. We'll
just focus on min heaps today because a max heap is essentially the reverse. In a min
heap the elements are all smaller than their children so the root node will be
the very smallest element and then looking down the tree down the heap, the
elements get bigger and bigger and bigger. So that's the basics of what a heap is but
how do we actually create and maintain such a data structure? So let's start
with just insertion. So when we insert an element it always goes in the next empty
spot looking top to bottom left to right. So we go, first we insert an element here,
and then here and then here and then here and so on through the tree, through
the heap. So that's how insertion works. But then of course what happens if
that's not really where the element should go? What we can do is we can insert the
element there and then bubble it up until we get to the right spot. So we
take the inserted element, we compare it with its parent, if it's out of order,
swap them and then keep going up the tree in this process. Now what about
removing the minimum element? So we know the minimum element will always
be the root node and so that's easy to find but then if we want to remove it we
might have an empty spot. So what we do here is we remove the min element
there, so we take out the root and then we swap that value at the root with the
last element added. And then of course that element might not be in the right spot,
so we take the root element and bubble it down to the next spot so we compare
the root with its children, its left child and its right child, and then swap it
with the smaller of the two. And then we keep going down the tree until the heap
property is restored. So that's how a tree operates, let's think about
implement- that's how a heap operates, let's talk about implementation now. So
implementation is kind of interesting. You might have assumed that we'd
implement it a simple class node with a left node and a right node, and
certainly we could do it that way. But there's an even better way of
implementing it. Note that when we add elements to the
heap they're always getting added in a very particular spot. There aren't gonna
be any gaps in the heap so we have the zeroth element here and then the first
second third fourth etc and so that means that we can actually use an
array instead to store these values and that makes it very compact. And a simple
simple equation can map from an index to its left child its right child or to
its parent. And so we can still get to the left and right child but we don't
need to have this overhead of a node class. So now that we've covered the
basics of what a heap is let's turn to the actual code for this. We'll implement
min heap with a simple class that wraps this items array. This is going to be
an array of a fixed length but if it gets too big we'll increase the capacity.
Now I'm gonna get a little bit of a head start and cheat a little bit by just
adding a whole bunch of simple helper methods. So these are just simple
methods that get the left and right child of the parent index. Actually you
know check if they exist, or actually get the values themselves. So I'm
just getting a little bit of a head start here and I'll get another little
bit of a head start by adding in two extra methods here. One is a swap method that
swaps the values of two indices and another one is an insure extra capacity
method. Now what this does is it checks if the array is full and if so, it creates a new
array of double that size and it copies all the elements over. And this by the
way is the basics of how an arraylist operates. Now let's turn to the real code.
The first method I'll implement is a peek method and this first checks if the array is empty if so
returns an exception because there's nothing at the front. Otherwise it just returns
the first element in the array which will always be the minimum element, and
essentially the root of the heap. The next method we'll do is a pole method. Now what this does
is actually extract the minimum element and actually so actually removes it from
the array. So first we'll check if the arrays empty, if so throw an exception. Otherwise I need to actually get the
value so item is item of 0 then I need to take the very last element in the array
and move it into the very first element then I need to shrink my array. Or shrink essentiall the size of it. And
then I need to go and actually re-heapify. So I removed the root element so I
need to heapify down and I'll go fill this in, this method in shortly. So in this case if we remove the ten, the
minimum element, it's going to get deleted. Then the 17 is going to get
moved up to where the ten is, so seeing the array, that's like this, the 17 gets put in here. And then we go
and adjust the heap to shift elements down as needed. My next method is going to actually add
an element in here. So first thing I want to do is I wanna make sure there is
capacity, so I'll call my insure extra capacity method. Then I'm gonna add
my element into the very last spot so items of size equals this new item then
increase my size. And then I need to actually heapify up so I need to
fix the heap looking upwards. Swapping each element with its parent as
necessary, so in this case if we want to add an element say, 8, we'd add it at the
very last element and then we'd go and adjust our heap moving things up as
necessary. Now for the real fun. I need to actually
implement these heapify methods so heapify up is going to start with the
very last element added which is that size minus 1 and then it's going to walk
up as long as there's a parent item and as long as essentially I'm out of order.
So as long as my parent item is bigger than me then hey, things are out of order,
so swap my parent index, swap my value with my parent and then walk upwards. So let's walk through this on the 8
that was inserted. So what we do here is we'll compare 8 to this 15, it's out of
order so we'll need to swap those values. So 15 goes down here and 8 goes up here
or on the array it will look like this. Then we compare this 8 to the 10 and then
that's still out of order, and so we'll go and move the 10 down and swap the 8
up there and now we've returned to the root, to the heap properties. We have 8 at the top, 10 and 20 below it then 17 and 15 below that. Heapify down is a
little bit more complicated but it's still quite manageable. First we're going
to start off with our root element which is at index zero. And then we're going to
say well as long as I have children, keep walking down and trying to fix up my
heap. Now I only need to check if there's a
left child because if there's no left child then there's certainly no right
child. Then I'm gonna set this smaller child index equal to the smaller of the
left and the right child so I'm going to take it guess with, set it equal to the left
child, and then I'm gonna say hey if there's a right child, and my right child is even smaller than my
left child, small child index should equal my right child. Now what I'm going
to say, remember I'm looking downwards on the
heap, so now what I'm gonna say is hey, if items of index, if I'm smaller than the smaller of
my two children then everything's good, and everything's back in order here and
I can just exit. If that's not the case then our heap is
still out of order and then I need to swap my value with my smaller child and
then move down to my smaller child. I'll just actually move this out here. Alright so that's the basics of how
heapify down works. Let's walk through this on an example. I'll make this example
slightly larger so if we do an extract min such that 20, 10 gets removed then
we remove 10, we replace it with 25. I'll do it on the array too so you can see what's
going on there. Then we compare 25, the root, and replace it with the smaller of
its left and right child. So we swap the 25 and the 15, so 25 comes down here, 15
comes up there, and we can do it down here too. So 15 goes here 25 goes here
then we compare 25 to 17. It's still out of order since 25 is bigger than
17 so we do 17 comes up here we swap those and 25 goes down here. So now we
have a heap again that looks like 15, 17 20, and 25 and as you can see our min
heap property has been restored. So now that you understand what a heap is and
how it works, why don't you try out using a heap
on a new problem. Good luck.