The primary topics in this part of the specialization are: greedy algorithms (scheduling, minimum spanning trees, clustering, Huffman codes) and dynamic programming (knapsack, sequence alignment, optimal search trees).

Loading...

From the course by Stanford University

Greedy Algorithms, Minimum Spanning Trees, and Dynamic Programming

435 ratings

The primary topics in this part of the specialization are: greedy algorithms (scheduling, minimum spanning trees, clustering, Huffman codes) and dynamic programming (knapsack, sequence alignment, optimal search trees).

From the lesson

Week 3

Huffman codes; introduction to dynamic programming.

- Tim RoughgardenProfessor

Computer Science

So we clearly have something to be excited about.

Â There's clearly this opportunity to design binary prefix-free codes which

Â improve over the obvious fixed link solution.

Â So, we'd like to have in some sense, optimal algorithm for this problem and

Â for that, we of course need a crisp problem definition.

Â So, to do that it turns out to be useful to think of codes as binary trees.

Â So, this video will develop that connection concluding with the final

Â formal problem statement. So, the last video introduced us to this

Â very interesting computational problem, namely given characters from an alphabet

Â with frequencies, find the best binary prefix-free encoding,

Â find the code which minimizes the average number of bits needed to encode a

Â character. Crucial, the reasoning about this problem

Â is thinking of binary codes as binary trees. So to give you an idea about this

Â correspondence, let's just revisit three of the binary codes we saw in the

Â previous video and see what kind of trees they correspond to.

Â So let's just continue with the four symbol alphabet A B C D.

Â The obvious fixed length code where we encode A, B, C, D was 0, 0, 0, 1, 1, 0

Â and 1, 1 is just going to correspond to the complete binary tree with four

Â leaves. So let me label this complete binary tree

Â as follows. I'm going to label the leaves A through D from left to right, and I'm

Â going to label each edge of the tree with a 0 if it corresponds to a left-child

Â relationship and with a 1 if it corresponds to a right-child

Â relationship. And now what you see is there's a

Â correspondence between the bits along root to leaf paths and the fixed length

Â encoding. So for example for the symbol C, if we

Â follow the path from the root to the leaf labeled C, we first encounter a 1 because

Â it's a right-child, then we encounter a 0 because it's a left-child.

Â That gives us a 1 and a 0, that's the same as our encoding of the

Â symbol C in this fixed length encoding and the same of course is true for the

Â other three leaves. Next, when we first started playing

Â around with variable-length encodings to motivate the prefix-free property, we

Â studied a code where we replaced the double 0 for an A with a single 0 and the

Â double 1 for a D with a single 1. Now this code was not prefix-free,

Â but we can still represent it as a binary tree.

Â It's just not going to be a complete one. So I'm going to label the edges of this

Â tree the same way as before. Left-child edges will be given a label of

Â 0, right-child edges will be given a label

Â of 1. I'm going to label the left and right

Â children of the root A and D respectively and the two leaves will be given the

Â labels B and C. The reason I labeled the nodes in this

Â way is, because then we have the same kind of correspondence between the

Â encodings that we proposed for the various symbols and the bits that you see

Â along a path from the root to nodes with those symbols.

Â So for example, if you at the node labeled D, the path from the root only

Â has a single bit 1 and that coincides with the proposed encoding of the symbol

Â D. Now, remember, this code is not

Â prefix-free and so therefore, as we saw, it had ambiguity.

Â So if you're wondering what some encoded message means and you see a 0, you're not

Â sure that 0 might be representing the symbol A or alternatively it might be the

Â first half of an encoding of the symbol B.

Â So, this ambiguity is also noticeable in the tree.

Â And the property in the tree that tips you off to the ambiguity is that there

Â are symbols at internal nodes of the tree.

Â The symbols are not merely at the leaves as they were with the first tree with the

Â fixed length in coding, but there are also two internal nodes

Â that have symbols. So let's draw the tree for our final

Â example which, was the variable length but prefix-free code that we looked at in

Â the previous video. So this is going to correspond to a tree

Â which is not perfectly balanced, but it will have labels only at the leaves of

Â the tree. So, if you label the edges of this tree

Â the way we've been doing, all the left-child edges get a 0, all the

Â right-left edges get a 1, and we label the leaves of the tree from

Â A to D going from left to right. You'll see we have the same

Â correspondence as in the previous two trees.

Â the sequence of bits from the root to a leaf coincide with the proposed encoding

Â for it. So, for example, if you look at the leaf

Â labeled C, because you traverse a right-child, another right-child and a

Â left-child to get to it, that's the sequence 1, 1, 0 and that is precisely

Â the proposed encoding for the symbol C. So in general, any binary code can be

Â expressed as a tree in this way, with the left-child pointers being labeled with

Â 0's, the right child pointers being labeled with 1's,

Â and the various nodes being labeled the symbols of the given alphabets, and the

Â bits from the root down to the node labeled with the given symbol

Â corresponding to the proposed encoding for that symbol.

Â And what's cool about thinking about codes as trees is that the really

Â important prefix-free condition, which seems like a nuisance to check in the

Â abstract, shows up in a really clean way in these trees,

Â namely the prefix-free condition is the same as leaves being the only nodes that

Â have labels. No internal nodes are allowed to have a

Â label in a prefix-free code. The reason for this is that we've set it

Â up so that the encodings correspond to the bits along paths from the root to the

Â labeled node. So being a prefix of another corresponds

Â to one node being an ancestor of the other, and so, if all the labels are at

Â the leaves, then of course nobody is an ancestor of the other and we have no

Â prefixes. The other things that's really cool about

Â this tree representation of codes is, it becomes pictorially obvious how you do

Â the coding given this sequence of 0's and 1's from a prefix-free binary code,

Â namely, you start at the beginning and you start at the root of your tree,

Â whenever you see a 0 you go left, whenever you see a 1 you go right.

Â At some point you'll hit a leaf, that leaf will have some label and that's the

Â symbol that's being encoded, and after you hit a leaf, you just start all over

Â again back to the root. So for example, if you were using our

Â variable-length prefix-free code for the four letter alphabet, as in our running

Â example, and you were given the sequence of 0s and

Â 1s, 0, 1, 1, 0, 1, 1, 1. What would you do?

Â Well, you'd start at the root and you see a 0, so you follow the left-child

Â pointer, and you immediately get to a leaf.

Â It's labeled A, so you're going to output and A as the first symbol.

Â Now you start all over. You return to the root, now what do you see?

Â You see a 1, so you go right, you see another one, so you go right, and now you

Â see a 0, so you go left and that gets you to the leaf labeled C.

Â Now you start all over again. You see a 1, you go right, you see a 1,

Â you go right again, and then, finally you see yet one more 1 and you wind up at the

Â lead labelled D. So by repeated traversals through the

Â tree, you decode the sequence of 0s and 1s as a C, D.

Â There's never any ambiguity, because when you hit a label, you know you're going to

Â leave, there's no where to go. And every internal note, it's unlabeled,

Â you know to expect another bit, another traversal further down in the tree.

Â So a final important point about this correspondence is that the encoding

Â lengths of the symbols, the number of bits needed to encode the various

Â symbols, are just the depths of the corresponding leaves in the tree that

Â corresponds to the code. So for example, in our running example

Â the symbol A is the only one that needs only one bit to encode and it's also the

Â only leaf in level one of the tree. And similarly B needs two bits and shows

Â up in the next level, the C and the D which need three bits

Â show up in the third level. So this correspondence is, really just by

Â construction, so how do you encode a given symbol.

Â Well, it's just the bits on the path from the root, and that the number of such

Â bits is just the number of pointer traversals you need to get from the root

Â down to that leaf, and that's just the depth of that leaf in the tree.

Â So we're now in a great position to really have a crisp definition of the

Â problem. The input of course is just the

Â frequencies for a bunch different symbols i from some alphabet capital sigma.

Â I'm going to use P sub i as notation for the frequency of symbol i.

Â So we know what it is we want to optimize.

Â We want to minimize the expected number of bits needed to encode a symbol, where

Â the average of the expectation is taken over the provided frequencies of the

Â various symbols. Well, let's express this objective

Â function using our newfound correspondence with binary trees.

Â In particular, the fact that we can think about encoding lengths as depths of

Â leaves in trees. So, given a tree, T, which corresponds to

Â a prefix-free binary code. That is it should be a binary tree and

Â the leaves of this tree should be in one-to-one correspondence with the

Â symbols of sigma. We're going to define capital L(T) as the

Â average encoding length. It's an average in the sense that we sum

Â over all of the symbols of the alphabet, we weight each symbol by the frequency,

Â and remember, this is part of the input, so whether the provided frequency P

Â survived that symbol i. And then how many bits do we need to

Â encode that symbol i? Well, it's just the depth of the leaf

Â which is labelled i in the given tree, capital T.

Â So this is what we want to make as small as possible.

Â So, for instance, using the data from the previous video, the letters A, B, C, D

Â with frequencies 60, 25, 10, and 5%. Then if we use the complete binary tree,

Â that is the fixed length encoding, we just get two bits per character.

Â While if we use the lopsided tree optimized, so that each A only takes one

Â bit while suffering three bits for C and D, then the average encoding length drops

Â to 1.55, as we saw in the last video. So what then is the goal,

Â what's the responsibility of our algorithm?

Â Well, amongst all binary trees, which have leaves and correspondence to the

Â symbols of sigma, we want to compute the one which makes this average encoding

Â length as small as possible which minimizes our objective function capital

Â L. Turns out Huffman's greedy algorithm does

Â it. More details to come.

Â [SOUND]

Â Coursera provides universal access to the worldâ€™s best education,
partnering with top universities and organizations to offer courses online.