Lecture 13 | Programming Abstractions (Stanford)
-
0:00 - 0:10
-
0:10 - 0:11
-
0:11 - 0:14This presentation is delivered by the Stanford Center for Professional
-
0:14 - 0:24Development.
-
0:24 - 0:26Welcome to Friday. I keep telling you I'm gonna talk
-
0:26 - 0:29about linked list and then we don't ever get very far, but
-
0:29 - 0:33today really we are gonna talk about linked list and do some tracing and see some
-
0:33 - 0:36recursive work we can do with linked list and then
-
0:36 - 0:40I'll probably give you a little preview of the next topic, which is the introduction
-
0:40 - 0:44algorithm analysis in Big O toward the end. We won't get very far in that, but we will be talking
-
0:44 - 0:47about that all next week, which is Chapter 7 in its full glory. That
-
0:47 - 0:48will be
-
0:48 - 0:51pretty much everything we cover next week is coming out of Chapter 7, so it's all
-
0:51 - 0:53about algorithm and sorting and different
-
0:53 - 0:54algorithms.
-
0:54 - 0:58I will not be able to go - hang out with you today after class because I have an undergraduate
-
0:58 - 0:59counsel meeting.
-
0:59 - 1:00
-
1:00 - 1:03But it's a nice day so hopefully you'll have some more
-
1:03 - 1:06fun outdoor thing to do anyway.
-
1:06 - 1:09We will meet again next Friday. So
-
1:09 - 1:11put that on your calendar if you are
-
1:11 - 1:16the type who keeps a calendar. Okay.
-
1:16 - 1:20So actually I'm gonna not even really work in the things. I'm gonna go back to my
-
1:20 - 1:22editing and talk about kind of where we were at
-
1:22 - 1:25at the end of
-
1:25 - 1:27Wednesday's lecture. Was
-
1:27 - 1:29we were doing a little bit of
-
1:29 - 1:31coding with the linked list itself.
-
1:31 - 1:35So having defined that recursive structure that has the information from
-
1:35 - 1:37one entry plus a pointer to the next
-
1:37 - 1:40and then so far the little pieces we have is something that we will print an individual
-
1:40 - 1:41entry,
-
1:41 - 1:44something that will create a new entry out in the heap, filling in with data
-
1:44 - 1:47that was read from the console typed in by the user,
-
1:47 - 1:51and then the last bit of code that we were looking at was this idea of building the
-
1:51 - 1:52list
-
1:52 - 1:55by getting a new entry.
-
1:55 - 1:58So a pointer coming back from there that points to a new heap allocated
-
1:58 - 2:01structure that has the name and the address of someone
-
2:01 - 2:03and then attaching it to the
-
2:03 - 2:06front part of the list. So we talked about why that was
-
2:06 - 2:08the easiest thing to do and I'm gonna
-
2:08 - 2:11just re-draw this picture again because we're gonna need it
-
2:11 - 2:16as we go through and do stuff. Here's the main stack frame.
-
2:16 - 2:19It's got this pointer list, which
-
2:19 - 2:23is expected to point to an entry out in the heap. It starts pointing at null.
-
2:23 - 2:26We have this local variable down here, new one
-
2:26 - 2:29that is also a pointer to an entry
-
2:29 - 2:32and based on the result from get new entry, which will either return null to say
-
2:32 - 2:36there's no more entries or a new heap allocated thing if it gives us this new
-
2:36 - 2:38entry that says
-
2:38 - 2:43here's Jason and his phone number.
-
2:43 - 2:48That the lines there - the new ones next equals list so
-
2:48 - 2:52new ones next field, right? Gets assigned the value of list, which affectively just copies
-
2:52 - 2:54a null on top of a null
-
2:54 - 2:59and then sets list to point to the same place that new 1 does.
-
2:59 - 3:01So on the first iteration,
-
3:01 - 3:04Jason is the new front most cell on the list,
-
3:04 - 3:08has a null terminator in the next field, which says there's no further cells. So we
-
3:08 - 3:10have a singleton list of just one cell.
-
3:10 - 3:13Now the subsequent iteration
-
3:13 - 3:17we call get new entry returns us a new
-
3:17 - 3:23pointer to another cell out here on the list. This one's gonna be Joel.
-
3:23 - 3:27He starts off as his own singleton list and then here's the attach again.
-
3:27 - 3:29New ones
-
3:29 - 3:32next field gets the value of list,
-
3:32 - 3:35so that changes
-
3:35 - 3:38Joel's next to
-
3:38 - 3:41point to where list does now. So I have two different ways to get to Jason's cell
-
3:41 - 3:45now. Directly, it's the front most cell of the list still, but it's now following Joel.
-
3:45 - 3:47And then I update list
-
3:47 - 3:49to point to new one,
-
3:49 - 3:54so doing pointer assignment on this. Copying the pointers, making an alias,
-
3:54 - 3:55and now
-
3:55 - 3:59at the bottom of that loop, right? I now have list pointing to Joel, which points
-
3:59 - 4:02to Jason, which points to null. So my two entry list.
-
4:02 - 4:05Every subsequent cell that's created is
-
4:05 - 4:06prepended, right?
-
4:06 - 4:08Placed in the front most position of a list
-
4:08 - 4:11and then the remainder of the list trails behind it.
-
4:11 - 4:13So we should expect that if we
-
4:13 - 4:16put in the list A, B, C that if we were to go back and traverse it we'll
-
4:16 - 4:18discover it goes C, B, A. And
-
4:18 - 4:22so I was just about to show you that and then we ran out of time. So I'm gonna go ahead and
-
4:22 - 4:22finish that because I'm gonna
-
4:22 - 4:31write something that will print an entire linked list.
-
4:31 - 4:33It will take the list that we have and I'm gonna
-
4:33 - 4:35show you
-
4:35 - 4:39that.
-
4:39 - 4:42So the idea is to
-
4:42 - 4:44traverse a pointer
-
4:44 - 4:47down the list
-
4:47 - 4:49and print each one in
-
4:49 - 4:51turn. I'm gonna do that using a four loop. It
-
4:51 - 4:55may seem a little bit like an odd use of the four loop, but in fact what
-
4:55 - 4:59we're doing is really comparable to how you would do iteration down a link, an
-
4:59 - 5:00array,
-
5:00 - 5:03using kind of zero to n, you know, I++.
-
5:03 - 5:06We're doing the same thing, but instead of advancing an integer, which
-
5:06 - 5:10indexes into that, we're actually keeping track of a pointer, which moves down.
-
5:10 - 5:14So the initial state of that pointer as we assign it to be the value of the list,
-
5:14 - 5:17so we alias to the first cell of the list.
-
5:17 - 5:20While that pointer points this invalid cell not to null,
-
5:20 - 5:23so as long as there are still cells to process
-
5:23 - 5:25then we'll print to
-
5:25 - 5:28cell. Then we'll advance the kind of equivalent of the I++.
-
5:28 - 5:30Here's the Kerr equals Kerr next.
-
5:30 - 5:34So advancing - so starting from Kerr equals Joel, right? To Kerr equals Jason and then Kerr
-
5:34 - 5:38equals null, which will terminate that. So as long as our linked list is properly
-
5:38 - 5:40terminated, right? We should print all the cells
-
5:40 - 5:41from front to back
-
5:41 - 5:43using this one loop.
-
5:43 - 5:47And so if I change this down here to be print list instead of just print to the front
-
5:47 - 5:48most entry
-
5:48 - 5:56and then I run a little test on this.
-
5:56 - 5:58So I enter Jake
-
5:58 - 6:00and his phone number,
-
6:00 - 6:02and I enter
-
6:02 - 6:04Carl and his phone number, and then I
-
6:04 - 6:06enter Ilia and
-
6:06 - 6:07his phone number, and I
-
6:07 - 6:10see that's all I have. Then they come back out in the opposite order,
-
6:10 - 6:13right? That Ilia, Carl, Jake
-
6:13 - 6:17because of the way I was placing them in the front of the list, right? Kind of effectively reversed, right? Them
-
6:17 - 6:22from the order they were inserted. Do you have a question? Do people ever
-
6:22 - 6:22make blank lists so that you can traverse backwards
-
6:22 - 6:25through them?
-
6:25 - 6:28They certainly do. So the simplest form of the linked list, right? Has only these
-
6:28 - 6:33forward links, right? So each cell gets to the one that follows it in the list,
-
6:33 - 6:36but that is gonna create certain asymmetries in how you process that list.
-
6:36 - 6:38You're always gonna start at the front and move your way to the back. Well, what happens if you're
-
6:38 - 6:40at a cell and you'd like to back up, right?
-
6:40 - 6:42It doesn't have the information
-
6:42 - 6:46in the single chain to do that. So you can build lists that either
-
6:46 - 6:49link in the other direction or link in both directions, right? To where you
-
6:49 - 6:53can, from a particular cell, find who proceeded it and who followed it. It just makes
-
6:53 - 6:56more pointers, right? And more complication. We'll see reasons why that actually
-
6:56 - 6:59becomes valuable. At this stage it turns out that it would just be
-
6:59 - 7:02complication that we wouldn't really be taking advantage of, but
-
7:02 - 7:05in a week or two we're gonna get to some place where that turns out to be a very, very
-
7:05 - 7:08useful addition to the list because it turns out that we really will need to be
-
7:08 - 7:11able to kind of move easily in both directions and right now we're not too
-
7:11 - 7:12worried about
-
7:12 - 7:18any direction other than the front ways.
-
7:18 - 7:21So this idea of
-
7:21 - 7:23the four loop, right? Is
-
7:23 - 7:27just one of the ways I could have done this. I could do this with a Y loop,
-
7:27 - 7:28right? Other sort of forms of iteration.
-
7:28 - 7:31I could also
-
7:31 - 7:35capitalize on the recursive nature of the list, and this is partly why I've chosen to introduce
-
7:35 - 7:37this topic now, is because I really do want to stress that this idea that it's a
-
7:37 - 7:39recursive structure
-
7:39 - 7:42gives us a little bit of an insight into ways that operations on it
-
7:42 - 7:45might be able to take advantage of that recursive nature.
-
7:45 - 7:48So let me write this alternate print list, and I'll
-
7:48 - 7:52call it recursive print list,
-
7:52 - 7:55that is designed to use recursion to get the job done.
-
7:55 - 8:00So in terms of thinking about it recursively, you can think of, well, a linked list is
-
8:00 - 8:03the sequence of cells and iteration kind of thinks of the whole sequence at one
-
8:03 - 8:04time.
-
8:04 - 8:08Recursion tends to take the strategy of, well, I'm just gonna separate it into
-
8:08 - 8:12something small I can deal with right now and then some instance of the same
-
8:12 - 8:14problem, but in a slightly smaller simpler form.
-
8:14 - 8:18The easy way to do that with a linked list is imagine there's the front
-
8:18 - 8:20most cell.
-
8:20 - 8:23Which I could print by calling print entry, which prints a single entry.
-
8:23 - 8:26And then there is this recursive
-
8:26 - 8:29structure left behind, which is the remainder of the list and I can say, well,
-
8:29 - 8:32I can recursively print the list
-
8:32 - 8:34that follows.
-
8:34 - 8:36So print the front most cell,
-
8:36 - 8:40let recursion work its magic on what remains.
-
8:40 - 8:43Looks pretty good. Something really critical missing?
-
8:43 - 8:45Base case. Better have a base case here.
-
8:45 - 8:49And the simplest possible base case is list equals equals null.
-
8:49 - 8:53If list equals equals null then it won't have nothing to do, so I can just return or I
-
8:53 - 8:55can actually just do it like this. Say if list
-
8:55 - 8:57does not equal null, so it has some
-
8:57 - 8:59valid contents,
-
8:59 - 9:00something to look at,
-
9:00 - 9:03then we'll print the front most one and then let recursion take care of the
-
9:03 - 9:05rest. So
-
9:05 - 9:11I'll change my called print list to be a recursive print list. And I should
-
9:11 - 9:12see some [inaudible] results here.
-
9:12 - 9:15I say that
-
9:15 - 9:17Nathan is here, I
-
9:17 - 9:20say Jason is here, I
-
9:20 - 9:21Sara,
-
9:21 - 9:23Sara are you an H? I don't
-
9:23 - 9:24remember.
-
9:24 - 9:26Today it doesn't.
-
9:26 - 9:30Sara, Jason, Nathan coming out the other way. Okay.
-
9:30 - 9:33So I want to do something kind of funny with this recursive call.
-
9:33 - 9:33So it's
-
9:33 - 9:37not really in this case - both of these look equally simple to write. We're
-
9:37 - 9:40gonna start to look at some things where this actually might buy
-
9:40 - 9:43us something. For example, lets imagine that what I wanted to do was print the
-
9:43 - 9:47list in the other order. So I don't have the list
-
9:47 - 9:48that links backwards.
-
9:48 - 9:50So if I really did want to print them
-
9:50 - 9:52with the last most element first,
-
9:52 - 9:56the way that they were added at the console,
-
9:56 - 9:58and the way I'm building the list, right? Is putting them in the other order. So, well, could I just take
-
9:58 - 10:00the list and print it back to front?
-
10:00 - 10:03I mean, it's simple enough to do that on a vector, if you had one, to work from
-
10:03 - 10:06the way back. Could I do it with the linked list?
-
10:06 - 10:09In the iterate formulation it's gonna actually get pretty messy because I'm
-
10:09 - 10:12gonna have to walk my way all the way down to the end and then print the last one, and then I'm
-
10:12 - 10:15gonna have to walk my way down to the one that points to the last one and
-
10:15 - 10:18print it, and then I'm gonna have to walk my way down to the one that printed to the penultimate
-
10:18 - 10:19one and print it,
-
10:19 - 10:21but it does involve a lot of traversal and a lot of work.
-
10:21 - 10:24I can make the recursive print one do it
-
10:24 - 10:28with just one tiny change of the code.
-
10:28 - 10:30Take this line
-
10:30 - 10:34and put it there. So
-
10:34 - 10:37what I'm doing here is letting recursion do the work for me of
-
10:37 - 10:42saying, well, print everything that follows me in the list before you print this cell. So
-
10:42 - 10:46if the list is A, B, C it says when you get to the A node it says
-
10:46 - 10:49okay, please print the things that follow me before you get back to me. Well, recursion
-
10:49 - 10:52being applied to the B, C list says, well, B says, well, hold onto B, print everything
-
10:52 - 10:56that follows me before you print B, when C gets there it says, well, print everything that
-
10:56 - 10:59follows me, which turns out to be nothing, which causes it to come back and
-
10:59 - 11:02say, well, okay, I'm done with the part that followed C, why don't we print C,
-
11:02 - 11:03and then print B, and then print A.
-
11:03 - 11:09So if I do this and
-
11:09 - 11:10print it through I put
-
11:10 - 11:12in A,
-
11:12 - 11:16B, C.
-
11:16 - 11:18Then they get printed out in the order I inserted them.
-
11:18 - 11:23They happen to be stored internally as C, B, A, but then I just do a
-
11:23 - 11:25change-a-roo was printing
-
11:25 - 11:29to print from the back of the list to the front of the list in the other order.
-
11:29 - 11:32But just the magic of recursion, right? A very simple little change, right? In terms of
-
11:32 - 11:34doing the work before the recursive call
-
11:34 - 11:36versus after
-
11:36 - 11:39gave me exactly what I wanted without any real craziness
-
11:39 - 11:42inserted in the code. We'll do a couple
-
11:42 - 11:44of other little things with you
-
11:44 - 11:46and
-
11:46 - 11:49I'm gonna do them recursively just
-
11:49 - 11:50for practice.
-
11:50 - 11:53
-
11:53 - 11:57If I wanted to count them, I wanted to know how many cells
-
11:57 - 12:02are in my list, then thinking about
-
12:02 - 12:03it recursively
-
12:03 - 12:06is a matter of saying, well, there's a cell in the front
-
12:06 - 12:06
-
12:06 - 12:10and then there's some count of the cells that follow it. If I add those together,
-
12:10 - 12:12that tells me how long this list is.
-
12:12 - 12:13
-
12:13 - 12:16Having a base case there that says when I get to the completely empty list where the list
-
12:16 - 12:17is null
-
12:17 - 12:20then there are no more cells to count that returns my zero. So it will work its way all the way down
-
12:20 - 12:22to the bottom,
-
12:22 - 12:25find that trailing null that sentinels the end, and then kind of count on its way
-
12:25 - 12:28back out. Okay, there was one before that and then one before that and add those
-
12:28 - 12:29all up
-
12:29 - 12:33to tell me how many entries are in my address book. So I can do
-
12:33 - 12:36that here. I can say what is the count in
-
12:36 - 12:38my
-
12:38 - 12:43address book? And maybe I'll stop printing it because I'm - and so
-
12:43 - 12:46I can test it on a couple of things. Well, what if I put
-
12:46 - 12:50an empty cell in so I have a null? If I get
-
12:50 - 12:54one cell in there, right? Then I should have one and I can even do a couple more. A, B, C.
-
12:54 - 12:55Got
-
12:55 - 12:59three cells. I'll
-
12:59 - 13:00do
-
13:00 - 13:06another little one while I'm here.
-
13:06 - 13:08Is that when I'm done with the linked list,
-
13:08 - 13:11all those heap allocated cells, right?
-
13:11 - 13:14Are just out there clogging up my heap. So when I'm done with this list
-
13:14 - 13:16the appropriate thing to do is to deallocate it.
-
13:16 - 13:18I will note, actually, just to be clear though,
-
13:18 - 13:23that any memory that's allocated by main and kind of in the process of working the program that
-
13:23 - 13:27when you actually exit the program it automatically deallocated. So
-
13:27 - 13:29when you are completed with the program and you're exiting
-
13:29 - 13:33you can go around and be tidy and clean stuff up, but, in fact, there's not a lot of point
-
13:33 - 13:33to it.
-
13:33 - 13:36The more important reason, right? To deallocation would be during the
-
13:36 - 13:40running of the program as you're playing games or monitoring things or doing the
-
13:40 - 13:41data.
-
13:41 - 13:43If you are not deallocating - if the program, especially if it's
-
13:43 - 13:44long
-
13:44 - 13:45running,
-
13:45 - 13:49will eventually have problems related to its kind of gargantuan memory size if it's
-
13:49 - 13:52not being careful about releasing memory.
-
13:52 - 13:55When you're done deleting it manually or just letting the system take it down as
-
13:55 - 13:57part of the process
-
13:57 - 13:58there's not much
-
13:58 - 14:00advantage to.
-
14:00 - 14:03So if I'm gonna deallocate a list,
-
14:03 - 14:07if the list does not equal null there's something deallocate.
-
14:07 - 14:07I'm
-
14:07 - 14:11gonna do this wrong first and then we'll talk about why
-
14:11 - 14:15it's not what I want to do.
-
14:15 - 14:19That's good exercise remembering things. So I think, okay, well, what I need to do
-
14:19 - 14:22is delete the front most cell
-
14:22 - 14:26and then deallocate all those cells that follow it. So
-
14:26 - 14:29using recursion, right? To kind of divide the problem up.
-
14:29 - 14:32It's a matter of deleting the front cell and then saying, okay, whatever else needs to
-
14:32 - 14:35be done needs to be done to everything that remains. List dot next gives me a pointer to that
-
14:35 - 14:37smaller sub list to work on.
-
14:37 - 14:41As written, this does try to make the right delete calls,
-
14:41 - 14:44but it does something really dangerous in terms of use of free memory. Anybody want
-
14:44 - 14:46to help me out with that? After it
-
14:46 - 14:48deletes the first
-
14:48 - 14:50element it doesn't know where to find the rest of it.
-
14:50 - 14:51That's exactly right.
-
14:51 - 14:56So this one said delete list. So if I think of it in terms of a picture here
-
14:56 - 14:59coming into the call
-
14:59 - 15:01list to some pointer
-
15:01 - 15:05to these nodes
-
15:05 - 15:07that are out here, A, B, and C,
-
15:07 - 15:09followed by null and I
-
15:09 - 15:11said delete list.
-
15:11 - 15:14So delete list says follow list to find that piece of memory out there in
-
15:14 - 15:18the heap and mark this cell
-
15:18 - 15:19as deleted,
-
15:19 - 15:22no longer in use, ready to be reclaimed.
-
15:22 - 15:24The very next line
-
15:24 - 15:26says deallocate list arrow next.
-
15:26 - 15:30And so that is actually using list, right? To point back into this piece of freed
-
15:30 - 15:31memory
-
15:31 - 15:33and try to read this number out of here.
-
15:33 - 15:37It may work in some situations. It may work long enough that you almost
-
15:37 - 15:40think it's actually correct and then some day cause some problem,
-
15:40 - 15:45right? Just in a different circumstances where this didn't succeed by accident.
-
15:45 - 15:47That I'm digging into
-
15:47 - 15:51that piece of freed memory and trying to access a field out of it, right? Which is
-
15:51 - 15:54not a reliable thing to do. C++ will let me do it,
-
15:54 - 15:58it doesn't complain about this. Ether it will compile time or run time in an obvious way,
-
15:58 - 16:01but it's just, sort of, a little bit of ticking time bomb
-
16:01 - 16:04to have that kind of code that's there.
-
16:04 - 16:06So there's two different ways I could fix this.
-
16:06 - 16:08One way would be to, before
-
16:08 - 16:10I do the delete
-
16:10 - 16:14is to just hold onto the pointer that I'm gonna need.
-
16:14 - 16:21So pull it out of the memory before we're done here.
-
16:21 - 16:22So I read it in there.
-
16:22 - 16:26So the piece of memory that's behind it is still good.
-
16:26 - 16:29The delete actually just deleted that individual cell, so whatever is previously
-
16:29 - 16:32allocated with new, which was one entry structure,
-
16:32 - 16:34was what was deleted by that call.
-
16:34 - 16:36But what I was
-
16:36 - 16:38needing here was to keep track of something in
-
16:38 - 16:42that piece of memory before, right? I obliterated it,
-
16:42 - 16:44so that I can make a further use of it.
-
16:44 - 16:46The other alternative to how to fix this
-
16:46 - 16:48would be to just merely
-
16:48 - 16:53rearrange these two lines. Same kind of fix I did up above where
-
16:53 - 16:54go ahead and delete
-
16:54 - 16:58everything that follows so when I'm doing a list like this it would say, well,
-
16:58 - 17:02delete the D and C and only after all of that has been cleaned up
-
17:02 - 17:05come back and delete the one on the front. So it would actually delete from the rear
-
17:05 - 17:08forward. Work its way all the way down to the bottom, delete the last cell, then the next to
-
17:08 - 17:09last,
-
17:09 - 17:10and work its way out.
-
17:10 - 17:12Which would also be
-
17:12 - 17:13a completely
-
17:13 - 17:20correct way to solve this problem. Okay. Any questions
-
17:20 - 17:22on that one so far? Let me go
-
17:22 - 17:25back over here and see what
-
17:25 - 17:27I want to do with you next.
-
17:27 - 17:31So I talked about this, talked about these. Okay.
-
17:31 - 17:32Now,
-
17:32 - 17:34I'm gonna do something that's actually
-
17:34 - 17:36really pretty tricky
-
17:36 - 17:47that I want you guys to watch with me. All right.
-
17:47 - 17:51So this is the same code that we had for building the address book.
-
17:51 - 17:52
-
17:52 - 17:54The listhead, the new one, and so on.
-
17:54 - 17:57And what I did was, I just did a little bit of code factoring. Where I took the steps
-
17:57 - 18:01that were designed to splice that new cell onto the front of the list
-
18:01 - 18:04and I looped them into their own function called prepend
-
18:04 - 18:08that takes two pointers. The pointer to the new entry and the pointer to the current first
-
18:08 - 18:11cell of the list and it's designed to wire them
-
18:11 - 18:12up by putting it in the front.
-
18:12 - 18:15So it looks like the code that was here, just moved up here, and then the
-
18:15 - 18:19variable names change because the parameters have slightly different names.
-
18:19 - 18:22The code as I'm showing it right here is buggy.
-
18:22 - 18:24It's almost, but not quite, what we want
-
18:24 - 18:28and I want to do this very carefully. Kind of trace through what's happening here, so you
-
18:28 - 18:29can watch with me
-
18:29 - 18:32what's happening in this process. So
-
18:32 - 18:37the variable is actually called listhead and this - I guess let me go ahead and do this.
-
18:37 - 18:40Okay. So
-
18:40 - 18:43let's imagine that we have gone through a couple of alliterations and we've got a good linked
-
18:43 - 18:43list
-
18:43 - 18:44
-
18:44 - 18:46kind of in place, so I have something to work with her.
-
18:46 - 18:49So let's imagine that listhead
-
18:49 - 18:52points to a
-
18:52 - 18:53cell A to B
-
18:53 - 18:56and then its got two cells, let's say,
-
18:56 - 18:58and then it's empty.
-
18:58 - 19:00Let's say I get a new one
-
19:00 - 19:01
-
19:01 - 19:06and this ones gonna be a J, let's say. Okay.
-
19:06 - 19:09So that's the state, let's say, that I'm coming into here and hit the
-
19:09 - 19:09prepend
-
19:09 - 19:13and I'm ready to take this J cell and put it on the front so that I have J, A, B on
-
19:13 - 19:16my list. Okay. So let me
-
19:16 - 19:20do a little dotted line here that distinguishes my two stack
-
19:20 - 19:25rings. I'm gonna make this call to prepend
-
19:25 - 19:31and prepend has two variables, ENT and first,
-
19:31 - 19:33that were copied from
-
19:33 - 19:37the variables new one and listhead that came out of the build address book. Actually,
-
19:37 - 19:40it's not called main here. Let me
-
19:40 - 19:43call this build
-
19:43 - 19:47book. Okay.
-
19:47 - 19:50So I pass the value of new one as
-
19:50 - 19:51ENT.
-
19:51 - 19:53So what we get is a pointer
-
19:53 - 19:55to this same cell,
-
19:55 - 19:57a copy, and so this case, right?
-
19:57 - 20:00We copied the pointer, so whatever address was being held there is actually
-
20:00 - 20:03copied into here as this parameter.
-
20:03 - 20:04Similarly,
-
20:04 - 20:07listhead is copied into the second parameter, which is the pointer to the
-
20:07 - 20:12first cell. Okay.
-
20:12 - 20:15I want to do this in such a way that you can follow what's going on. So let's see
-
20:15 - 20:16if I can get this
-
20:16 - 20:19to work out. So it's pointing up there to first. Okay.
-
20:19 - 20:21So I've got
-
20:21 - 20:24two pointers to this cell A.
-
20:24 - 20:26One that came off the original listhead and one that came there from the copy in first.
-
20:26 - 20:29And then I've got two pointers to this J.
-
20:29 - 20:32One that came through the variable new one in the build an address book frame and
-
20:32 - 20:35one that was ENT in the prepend frame. Now, I'm gonna
-
20:35 - 20:37trace through the code of prepend.
-
20:37 - 20:39It says ent
-
20:39 - 20:41next field equals first. Okay.
-
20:41 - 20:43So ent's
-
20:43 - 20:44next field
-
20:44 - 20:48is right here.
-
20:48 - 20:53It gets the value of first. Well, first points to this cell. Okay.
-
20:53 - 20:56So we go ahead
-
20:56 - 20:59and make the next field of J point to that cell.
-
20:59 - 21:03So that looks pretty good. That first line worked out just fine. It changed
-
21:03 - 21:05the cell J
-
21:05 - 21:08to point to what was previously the front of the list. So it looks like now it's the
-
21:08 - 21:10first cell that's followed by those.
-
21:10 - 21:13And then the next line I need to do is I need to update the listhead
-
21:13 - 21:16to point to J.
-
21:16 - 21:17So it says first
-
21:17 - 21:19equals ENT.
-
21:19 - 21:20So first
-
21:20 - 21:29gets the value of ENT. Well this just does pointer assignment.
-
21:29 - 21:31
-
21:31 - 21:34Sorry, I erased where it used to point to.
-
21:34 - 21:36And then I make it point to there, too.
-
21:36 - 21:39So at the bottom of prepend,
-
21:39 - 21:43if I were to use first as the pointer to the initial cell of the list it looks good.
-
21:43 - 21:47It points to J, which points to A, which points to B, which points to null.
-
21:47 - 21:49Everything looks fine
-
21:49 - 21:50here,
-
21:50 - 21:51right? At the end of prepend.
-
21:51 - 21:53But when I get back here
-
21:53 - 21:55to come back around on this loop;
-
21:55 - 22:03where is listhead pointing? It's pointing to A.
-
22:03 - 22:09It's pointing to A. Did anything happen to listhead in the process of this? No.
-
22:09 - 22:12That listhead points where it always pointed, which was whatever cell, right? Was
-
22:12 - 22:14previously pointed to.
-
22:14 - 22:18This attempt to pass it into prepend and have prepend update it didn't
-
22:18 - 22:21stick.
-
22:21 - 22:22Prepend
-
22:22 - 22:24has two pointers
-
22:24 - 22:27that are copies of these pointers.
-
22:27 - 22:31So like other variables, ents, and strings and
-
22:31 - 22:32vectors and anything else we have,
-
22:32 - 22:36if we just pass the variable itself into a function call
-
22:36 - 22:41then that pass by value mechanism kicks in, which causes there to be two new
-
22:41 - 22:43variables. In this case, the ENT and the first variables,
-
22:43 - 22:47that are copies of the two variables listhead and new one
-
22:47 - 22:49that were present in build address book.
-
22:49 - 22:54And the changes I make down here, if I really try to change ENT or change first,
-
22:54 - 22:58so I try to make ENT point somewhere new or make first point somewhere new,
-
22:58 - 22:59don't stick.
-
22:59 - 23:03They change the copies, not the originals.
-
23:03 - 23:05This is tricky.
-
23:05 - 23:08This is very tricky because it's entering that the first line
-
23:08 - 23:10was actually okay.
-
23:10 - 23:14That what the first line tried to do actually did have a persistent affect and
-
23:14 - 23:15the affect we wanted,
-
23:15 - 23:18which is it followed the ENT pointer
-
23:18 - 23:21to this shared location and changed its next field. So
-
23:21 - 23:25dereferencing that pointer and mucking around with the struct itself
-
23:25 - 23:28did have a persistent affect. It wasn't another copy of the entry struck. There
-
23:28 - 23:33really is just this one entry struck that new one and ENT are both pointing
-
23:33 - 23:34to.
-
23:34 - 23:35So both of them, right?
-
23:35 - 23:39Are viewing the same piece of heap memory. Changes made out there at the
-
23:39 - 23:42structure, right? Are being perceived from both ends,
-
23:42 - 23:45but the pointers themselves - the fact that I had two different pointers that
-
23:45 - 23:48pointed to the same place, I changed one of my pointers,
-
23:48 - 23:51the one whose name is first, to
-
23:51 - 23:55point somewhere new. I didn't change listhead by that action. That listhead and
-
23:55 - 23:55first
-
23:55 - 23:59were just two aliases of the same location, but they had no further
-
23:59 - 24:04relationship that is implied by that parameter passing there. How do
-
24:04 - 24:07you feel about that? Question? And
-
24:07 - 24:09first and ent
-
24:09 - 24:11are gonna disappear now, right, afterwards? No. First and ent would go away,
-
24:11 - 24:15but that just means their pointers would go. So when prepend goes away,
-
24:15 - 24:18right? This space gets deallocated, so it's
-
24:18 - 24:20like this
-
24:20 - 24:23pointer goes away
-
24:23 - 24:26and all this space down here goes
-
24:26 - 24:30away. Then what we have is list still pointing to A and B and then new one,
-
24:30 - 24:33right? Is pointing to this J, which points to A, but, in fact, right?
-
24:33 - 24:36Is effectively gonna be orphaned by the next come around of the loop when we
-
24:36 - 24:37reassign new one.
-
24:37 - 24:39So that J didn't get prepended.
-
24:39 - 24:43It got half of its attachment done. The outgoing attachment from J got done,
-
24:43 - 24:45but the incoming one
-
24:45 - 24:48didn't stick.
-
24:48 - 24:51This is pretty tricky to think about because it really requires really kind of
-
24:51 - 24:53carefully analyzing what the code is doing
-
24:53 - 24:57and not letting this idea of the pointer confuse you from what you all
-
24:57 - 25:00ready know about variables. If I pass - if you see a function call
-
25:00 - 25:01where I say
-
25:01 - 25:03binky
-
25:03 - 25:05of
-
25:05 - 25:07A and B, where A and B are integer values,
-
25:07 - 25:10if these are not by reference coming into binky then you know that when they
-
25:10 - 25:13come back A and B are what they were before. If A was 10 and B was 20,
-
25:13 - 25:16they're still that. That the only way that binky can have some persistent affect on
-
25:16 - 25:20the values of A and B would be that they were being passed by reference.
-
25:20 - 25:22If I change this piece of code,
-
25:22 - 25:25and it's just one tiny change I'm gonna
-
25:25 - 25:31make here, to add an ampersand on that first,
-
25:31 - 25:38then I'm gonna get what I wanted. So I want
-
25:38 - 25:41to draw my reference a little bit differently to remind myself about
-
25:41 - 25:45what it is. When I call prepend passing new one it got passed normally. New one
-
25:45 - 25:49is still just an ordinary pointer. So now I have two pointers
-
25:49 - 25:52where ENT and new one both point to that J.
-
25:52 - 25:56This one currently doesn't yet point up there. It's gonna in a minute, but I'll go ahead
-
25:56 - 25:58and put it back to its original state.
-
25:58 - 25:59Now, first
-
25:59 - 26:03is gonna be an alias for listhead, so that first
-
26:03 - 26:09is not going to be a copy of what listhead is. It's actually gonna be a
-
26:09 - 26:11reference back to here.
-
26:11 - 26:15And a reference looks a lot like a pointer in the way that I draw it,
-
26:15 - 26:18but the difference is gonna be I'm gonna shade or, sort of, cross hatch this box
-
26:18 - 26:21to remind myself that
-
26:21 - 26:24first is attached a listhead and there's nothing you can do to change it.
-
26:24 - 26:27That first becomes a synonym for listhead.
-
26:27 - 26:31That in the context of the prepend function, any access to first is really
-
26:31 - 26:35just an access to listhead. So trying to read from it or write to it, you know, do you
-
26:35 - 26:37reference it, it all goes back to the original
-
26:37 - 26:40that this is just standing in for.
-
26:40 - 26:43That there actually is a relationship that's permanent from the
-
26:43 - 26:47time of that call that means that yeah, there really is now new variable first. First is
-
26:47 - 26:51actually just another name for an existing variable, this one of listhead.
-
26:51 - 26:55So when I got through the ENT it gets the value - ENT's next gets the value of first.
-
26:55 - 26:56Well,
-
26:56 - 26:57first's value really is
-
26:57 - 27:01what listhead is. So that means it points up to A,
-
27:01 - 27:02so that part
-
27:02 - 27:04works as we were hoping before.
-
27:04 - 27:08Then when I make the change to first equals ENT,
-
27:08 - 27:10first is a synonym for listhead
-
27:10 - 27:12and that made listhead
-
27:12 - 27:15stop pointing to A and
-
27:15 - 27:18start pointing straight to J.
-
27:18 - 27:22And so this is still attached here. Let's do that. Let
-
27:22 - 27:25me see if I can just erase this part and make it a little clearer what's going on.
-
27:25 - 27:28So new one's pointing to J now, ENT
-
27:28 - 27:31is pointing to J,
-
27:31 - 27:33and listhead is pointing to J,
-
27:33 - 27:34and then this is still
-
27:34 - 27:37the reference pointing back to there.
-
27:37 - 27:40So now when prepend goes away,
-
27:40 - 27:42this extra pointer
-
27:42 - 27:43is removed,
-
27:43 - 27:45this reference is removed,
-
27:45 - 27:47all this space
-
27:47 - 27:48is reclaimed here in the stack,
-
27:48 - 27:51but listhead now really points to J,
-
27:51 - 27:53which points to A, which points to B as before.
-
27:53 - 27:55So we wired in two pointers, right?
-
27:55 - 27:59One going out of the new cell into what was previously the first cell and then the
-
27:59 - 28:00first cell
-
28:00 - 28:04pointer now points to the new one rather than the original first cell.
-
28:04 - 28:07It was all a matter of this one little ampersand
-
28:07 - 28:09that makes the difference, right?
-
28:09 - 28:12Without that, right? Then we are only operating on a copy.
-
28:12 - 28:15We're changing our local copy of a pointer to point somewhere new;
-
28:15 - 28:17having no permanent affect
-
28:17 - 28:17
-
28:17 - 28:19on the actual state of it.
-
28:19 - 28:22So, actually, without that ampersand in there it turns out
-
28:22 - 28:26nothing ever gets added to the list. The listhead starts as null and stays null,
-
28:26 - 28:29but all these things will copy the value of listhead as a
-
28:29 - 28:33null, change it in the local context of the called function, but then listhead
-
28:33 - 28:36will stay null. So, in fact, if I just ran this a bunch of times and I threw in a bunch of
-
28:36 - 28:37things without the ampersand
-
28:37 - 28:41I would find that all my cells just get discarded. I'd end up with an
-
28:41 - 28:42empty list when I was done. All the orphaned out
-
28:42 - 28:45in the heap
-
28:45 - 28:49attached and not really recorded permanently.
-
28:49 - 28:52That's pretty tricky. Question? Why is the
-
28:52 - 28:55ampersand after this [inaudible]?
-
28:55 - 28:56Because it is the - the
-
28:56 - 29:00ampersand applies to the - think of it more as applying to the name and it's saying this
-
29:00 - 29:04name is a reference to something of that type. So on the left-hand side
-
29:04 - 29:05is the type.
-
29:05 - 29:09What type of thing is it? Is it a string of anti-vector events or whatever? And then the
-
29:09 - 29:13ampersand can go between the type and the name to say and it is a reference to an
-
29:13 - 29:17existing variable of that type as opposed to a copy of a variable of that type. So
-
29:17 - 29:19without the ampersand it's always a copy.
-
29:19 - 29:21With the ampersand, you're saying
-
29:21 - 29:25I'm introducing first as a synonym for an existing entry star variable somewhere
-
29:25 - 29:28else and that in the context of this function
-
29:28 - 29:31access to this named parameter really is reaching out
-
29:31 - 29:35to change a variable stored elsewhere.
-
29:35 - 29:41It's quite, quite tricky to kind of get your head around what's going on here.
-
29:41 - 29:44I'm gonna use this, actually, in running another piece of code, so I want to
-
29:44 - 29:46be sure that at this point everybody feels
-
29:46 - 29:54at least reasonably okay with what I just showed you. Question? What happens if we stop
-
29:54 - 29:58ampersand [inaudible]? Jordan, you want to invert them or something like that? Yes. It turns out that that won't work.
-
29:58 - 30:02Basically, it won't compile because in this case you can't take a pointer out to an
-
30:02 - 30:04entry reference. In fact, it just won't let you. So
-
30:04 - 30:07it doesn't really make sense is the truth.
-
30:07 - 30:08But think of it as like the - sometimes people
-
30:08 - 30:12actually will draw it with the ampersand attached even without the
-
30:12 - 30:15space onto the variable name. It's just a notation. A really good clue that this name,
-
30:15 - 30:18right? Is a reference to an existing variable and that its type is kind
-
30:18 - 30:19of
-
30:19 - 30:21over here. So type,
-
30:21 - 30:25name, and then name as a reference has that ampersand attached. Question? Is
-
30:25 - 30:27there a wrong side to passing both the pointers by
-
30:27 - 30:29reference? Nope,
-
30:29 - 30:32not really. If I pass it by reference, right?
-
30:32 - 30:35Then it - nothing would change about what really happens, right? It would still leach into
-
30:35 - 30:39the thing and copy it. There is - for variables that are large, sometimes we
-
30:39 - 30:42pass them by reference just to avoid the overhead of a copy. Since a pointer is pretty small, that
-
30:42 - 30:45making a copy versus taking a reference it turns out doesn't really save you anything and
-
30:45 - 30:48actually it makes a little bit more work
-
30:48 - 30:52to access it because it has to kind of go one level out to get it. But
-
30:52 - 30:54effectively no. In
-
30:54 - 30:56general though, I would say that
-
30:56 - 30:58passing things by reference,
-
30:58 - 31:01as a habit, is probably not one you want to assume for other kinds of variables.
-
31:01 - 31:02Just
-
31:02 - 31:05because that once you've passed it by reference you've opened up the access to where if it
-
31:05 - 31:08changes it it does persistent and if you didn't intend for that that could be kind of a mystical thing
-
31:08 - 31:09to try to track down. So I
-
31:09 - 31:11think you should be quite deliberate about -
-
31:11 - 31:14I plan on changing this and I want to be sure I see that persistent
-
31:14 - 31:22effect. That I need that pass by reference there. Okay.
-
31:22 - 31:26So let me go on to kind of solve a problem with the linked list that helps to motivate what a linked
-
31:26 - 31:30list is good for. Why would you use a linked list versus a
-
31:30 - 31:35vector or an array style access for something that was a collection?
-
31:35 - 31:39And so the built in array, which is what vector is built on, so they have the same
-
31:39 - 31:40characteristics in this respect.
-
31:40 - 31:42They store elements in contiguous memory.
-
31:42 - 31:44You allocate an array of ten elements.
-
31:44 - 31:48There's a block that is ten integers wide, let's say,
-
31:48 - 31:52where they were all sitting next to each other. In address 1,000 as one,
-
31:52 - 31:541,004 is the next, 1,008 and so on.
-
31:54 - 31:58What that gives you is fast direct access by index. You can ask for the third
-
31:58 - 32:02member, the seventh member, the 28th member, the 6 millionth member
-
32:02 - 32:03depending on how big it is, right?
-
32:03 - 32:05By, sort of, directly computing
-
32:05 - 32:07where it will be in memory. You know where it starts and you know how big each
-
32:07 - 32:11element is. Then you can say here's where I can find the 10th element.
-
32:11 - 32:15That's an advantage, right? To the array vector style of arrangement.
-
32:15 - 32:16However,
-
32:16 - 32:20the fact that it's in this big contiguous block is actually very bulky.
-
32:20 - 32:21It means that
-
32:21 - 32:26if you were to want to put a new element in the front of an array or vector that
-
32:26 - 32:27has 1,000 elements
-
32:27 - 32:30you have to move over the 1,000 elements to make space. If
-
32:30 - 32:33it's starting to address 1,000 and you have them all laid out and you want to put a new
-
32:33 - 32:37one in the front, everybody's gotta get picked up and moved over a slot to make
-
32:37 - 32:39space. So imagine you're all
-
32:39 - 32:40
-
32:40 - 32:43sitting across a lecture hall and I decided I wanted to put a new person there, everybody
-
32:43 - 32:45gets up and moves one chair to the left,
-
32:45 - 32:47but there's not a way to just stick a new chair
-
32:47 - 32:49on one end of it
-
32:49 - 32:51using the array style
-
32:51 - 32:52of layout.
-
32:52 - 32:55Same for removing, right? So any kind of access to where you want to take
-
32:55 - 32:59somebody out of the array and close over the gap or insert in the middle and the beginning and
-
32:59 - 32:59whatnot
-
32:59 - 33:02requires everybody else moving around in memory,
-
33:02 - 33:06which gets expensive. Especially for large things, right? That's a lot of work.
-
33:06 - 33:09It also can't easily grow and shrink.
-
33:09 - 33:12You allocate an array, your vector, to be a certain size
-
33:12 - 33:13
-
33:13 - 33:15underneath it. That's what vector's doing on your behalf.
-
33:15 - 33:19If you have ten elements and now you need to put in ten more
-
33:19 - 33:22what you need to do is go allocate a piece of memory that's twice as big, copy over the
-
33:22 - 33:23ten you have,
-
33:23 - 33:26and now have bigger space. If you need to shrink it down you'll have to make a
-
33:26 - 33:29smaller piece, copy it down. There's not a way to take a piece of memory and just kind
-
33:29 - 33:30of
-
33:30 - 33:33in place in memory where it is kind of extended or shrink it
-
33:33 - 33:35in the C++ language.
-
33:35 - 33:38So that the process of growing and shrinking, right? Requires this extra
-
33:38 - 33:41effort. So behind the scenes that's what vector is doing. When you keep adding to a
-
33:41 - 33:43vector, eventually it will fill to capacity. It
-
33:43 - 33:46will internally make more space and copy things over and you're
-
33:46 - 33:49paying that cost behind the scenes
-
33:49 - 33:54when you're doing a lot of additions and removals from a vector. The
-
33:54 - 33:57linked list, right? Uses this wiring them together using pointers,
-
33:57 - 33:59so it has a lot of flexibility
-
33:59 - 34:00in it that the array does not.
-
34:00 - 34:04Each element individually allocated. So that means you can pick and choose when and
-
34:04 - 34:07where you're ready to take some more space on and when you don't.
-
34:07 - 34:10So when you're ready to add a new person to the vector there's no worry
-
34:10 - 34:12about if there's a million elements there and now you don't have any
-
34:12 - 34:15space you have to copy them. It's like you don't - you can leave the other million elements alone.
-
34:15 - 34:18You just take the heap, ask for one new element,
-
34:18 - 34:20and then splice it in.
-
34:20 - 34:23So the only allocation of the allocation concerns the individual element you're
-
34:23 - 34:26trying to do something with. You want to take one out of the middle; you just need to delete
-
34:26 - 34:30that one and close around the gap by wiring the pointers around it.
-
34:30 - 34:33So all the insert and remove actions, right? Are
-
34:33 - 34:35only a matter of wiring pointers.
-
34:35 - 34:37Wiring around something you're taking out,
-
34:37 - 34:41attaching one to the end or into the middle is splicing a pointer in, and is splicing the pointer
-
34:41 - 34:45out. So basically you typically have two pointers you need to reassign
-
34:45 - 34:46to do that kind of adjustment.
-
34:46 - 34:49If the element has ten members, it has a million members, right? Same amount of work to
-
34:49 - 34:51put a cell in there.
-
34:51 - 34:52
-
34:52 - 34:57No dependency on how big it is, right? Causing those operations to bog down.
-
34:57 - 35:00The downside then is
-
35:00 - 35:02exactly the, sort of, opposite of where it came out in the array in the vector,
-
35:02 - 35:06which is you don't have direct access to the 10th element, to the 15th
-
35:06 - 35:09element, to the 260th element. If I want to see what that 260 of
-
35:09 - 35:13my linked list is I've got to start at the beginning and walk.
-
35:13 - 35:17I go next, next, next, next, next, next 260 times and then I will get
-
35:17 - 35:19to the 260th element.
-
35:19 - 35:20So I don't have
-
35:20 - 35:22that easy access to say
-
35:22 - 35:25right here at this spot because we don't know. They're all over the place
-
35:25 - 35:28in memory. Each linked list cell is allocated individually and the only way to get to
-
35:28 - 35:29them
-
35:29 - 35:32is to follow those links.
-
35:32 - 35:35Often that's not as bad a disadvantage as it sounds because
-
35:35 - 35:36typically, right?
-
35:36 - 35:38That you're doing things like walking down the array or the vector to look at each of
-
35:38 - 35:41the elements at the end you would also be walking down the linked list while you did it isn't
-
35:41 - 35:42really that bad.
-
35:42 - 35:45So in the case where you happen to be storing stuff in an index and you really want to
-
35:45 - 35:46reach back in there
-
35:46 - 35:50is where the linked list starts to be a bad call. Can you take it on, like,
-
35:50 - 35:52from the list and find something?
-
35:52 - 35:55Well, it can take - the thing is it - with a question with me like a long time. Like if I were
-
35:55 - 35:59looking through to see if there was an existence of a particular score in a
-
35:59 - 36:02vector of integers I have to look at them all from the beginning to the end.
-
36:02 - 36:05Now, the way I can access them is subzero, subone, subtwo, right?
-
36:05 - 36:09But if I'm walking down a linked list I'm doing the same sort of work. I have to look at each element
-
36:09 - 36:12but the way I get to them is by traversing these pointers.
-
36:12 - 36:15It might be that that's a little bit more expensive relative to the
-
36:15 - 36:18vector, but they're still gonna be about the same. If there's a million elements
-
36:18 - 36:20they're all gonna look at a million elements and whether it looked at them in contiguous memory
-
36:20 - 36:24or looked at them by jumping around it ends up being in the end kind
-
36:24 - 36:27of a very comparable amount of time spent doing those things.
-
36:27 - 36:31What would be tricky is if I knew I wanted to get to the 100th element.
-
36:31 - 36:34Like I wasn't interested in looking at the other 99 that preceded it. I really just wanted
-
36:34 - 36:37to go straight to the thing at slot 100.
-
36:37 - 36:39The array gives me that access immediately.
-
36:39 - 36:43Just doing a little calculation it says it's here. Go to this place in memory.
-
36:43 - 36:47And the linked list would require this walking of 100 steps to get there.
-
36:47 - 36:49And so if there are situations, right? Where one of these is
-
36:49 - 36:53just clearly the better answer because you know you're gonna do that operation a lot, right? You're
-
36:53 - 36:54gonna definitely prefer this.
-
36:54 - 36:58If you know you're gonna do a lot of inserting and rearranging within the list,
-
36:58 - 37:00the linked list may buy you
-
37:00 - 37:03the ease of flexibility of a kind of rewiring
-
37:03 - 37:10that does not require all this shuffling to move everything around. Question here? But if you were to
-
37:10 - 37:14know the size of the linked list? Typically a linked list won't limit the size unless you tell it, but that's actually true about an
-
37:14 - 37:15array too, right? Which is you
-
37:15 - 37:18- the vector happens to it on your behalf, but underneath it, right? That the
-
37:18 - 37:22array is tracking how many elements are in there, so would a linked list. So
-
37:22 - 37:25you could do a manual count when you needed, which would be expensive, or you could
-
37:25 - 37:27just track along with that
-
37:27 - 37:29outer most pointer. Well, how many elements have I put in there?
-
37:29 - 37:31And then update it as you add and remove. So
-
37:31 - 37:34you'd likely want to cache that if it was important to you to know that. If
-
37:34 - 37:38a lot of your operations depended on knowing that size you'd probably want to keep it stored
-
37:38 - 37:41somewhere. Over here?
-
37:41 - 37:42Why does
-
37:42 - 37:45the vector use arrays then instead of linked
-
37:45 - 37:46list?
-
37:46 - 37:49That is a great question. It's one that we actually will talk about kind of in about a week.
-
37:49 - 37:52It's like, well, why? So sometimes array - the vector is kind of taking the
-
37:52 - 37:56path of, well, it's just presenting you to the array in a slightly more convenient
-
37:56 - 37:56form.
-
37:56 - 37:58We will see situations where
-
37:58 - 38:01then the vector is just as bad as a choice as an array and then we'll
-
38:01 - 38:05see, well, why we might prefer to use a linked list and we will have - we will build linked
-
38:05 - 38:06lists instead basically.
-
38:06 - 38:10It has to make a choice and it turns out that for most usages
-
38:10 - 38:11the array
-
38:11 - 38:15is a pretty good match for a lot of ordinary tasks. The linked list happens to be a match
-
38:15 - 38:18for other tasks, right? And then we will build stuff out of that when
-
38:18 - 38:20that context comes up. Well, if you just, like,
-
38:20 - 38:22then you just, sort of, like
-
38:22 - 38:25in a vector class, like encapsulate all that and I - its final
-
38:25 - 38:29functionality would be the same. You certainly could. So you could totally build a vector class that
-
38:29 - 38:31actually was backed by a linked list and we will see how to do that,
-
38:31 - 38:34right? And then it would have different characteristics in terms of what
-
38:34 - 38:36operations were efficient and which ones were inefficient
-
38:36 - 38:39relative to do an array backed one. And
-
38:39 - 38:41over here was also. Yeah?
-
38:41 - 38:43Well, I, just to - for using linked
-
38:43 - 38:44lists, like,
-
38:44 - 38:48so first in, first out or first in, last out
-
38:48 - 38:48seems to make
-
38:48 - 38:51really good sense, but are there - am I
-
38:51 - 38:52like
-
38:52 - 38:55missing - You are way ahead of us, but, yeah, you're right on.
-
38:55 - 38:57The things like the stack and the Q, right?
-
38:57 - 39:00Seem like they're gonna be natural things that will work very, very well with
-
39:00 - 39:01a linked list.
-
39:01 - 39:04Things that required a lot of shuffling in the middle, right? It's a
-
39:04 - 39:08little unclear because you have to find the place in the middle, which is expensive,
-
39:08 - 39:11but then the insert is fast. The question is, well, which of these is actually gonna
-
39:11 - 39:13work out better? They both have
-
39:13 - 39:16some things they can do well and some things they can't do well. So it will have to have
-
39:16 - 39:19know maybe a little bit more about the context to be sure which ones seem
-
39:19 - 39:22like the best solution and maybe in the end it's just a coin toss, right?
-
39:22 - 39:25Some parts will be fast and some parts could be slow and anyway I can get the inverted form
-
39:25 - 39:26of that
-
39:26 - 39:28as an alternative that
-
39:28 - 39:32doesn't dominate in any clear sense. It's just like, well, they both have advantages
-
39:32 - 39:35and disadvantages. Question
-
39:35 - 39:36back here? Why
-
39:36 - 39:37was
-
39:37 - 39:38that infused
-
39:38 - 39:41to be based on a vector instead of a linked list?
-
39:41 - 39:44So they - I think your question is kind of like, yeah, they likely are built on linked lists.
-
39:44 - 39:48We're gonna see how we can do it both ways, right? We'll see how we can do it on array, we'll see how we can do it
-
39:48 - 39:50on a linked list, and then we'll talk about what those tradeoffs look like. Well, which one
-
39:50 - 39:54ends up being the better call
-
39:54 - 39:57when we're there? So that will be about a week. So don't worry too much about it now,
-
39:57 - 40:00but when we get there we'll definitely see kind of both variants and then we'll
-
40:00 - 40:06talk about them in great detail. Okay.
-
40:06 - 40:10So I'm gonna show you, just the last operation I want to show you on a linked list
-
40:10 - 40:12is doing an insert in sorted order and this
-
40:12 - 40:15is gonna require some pretty careful
-
40:15 - 40:17understanding of what's going on with the pointers and then we're also gonna
-
40:17 - 40:20see a recursive form of it that actually is a
-
40:20 - 40:22really clever
-
40:22 - 40:25and very elegant way to solve the same problem. So I'm gonna first do it
-
40:25 - 40:25iteratively
-
40:25 - 40:28just to kind of talk about. What's the mechanism for doing stuff iteratively on
-
40:28 - 40:32a linked list? It gets a little bit messy and so just be prepared for that.
-
40:32 - 40:36That I'm planning on taking my address book and building it up inserted order. So
-
40:36 - 40:40instead of doing a prepend where I just take each cell and put it on the front I'm actually assume
-
40:40 - 40:42that I'm gonna keep them all in order by name
-
40:42 - 40:45and whenever I get a new cell I want to put it in the right position relative to
-
40:45 - 40:48the other neighbors in the list that are all ready there.
-
40:48 - 40:51So this is one of those places where it seems like the linked list is actually gonna do very well. I have
-
40:51 - 40:53to search to find the spot.
-
40:53 - 40:55Okay? Well, you're gonna have to search to find the spot in a vector, too.
-
40:55 - 40:59Once I find the spot it should be very easy to just wire it in
-
40:59 - 41:02without shuffling and rearranging anything around. It should be a pointer
-
41:02 - 41:04in and a pointer out.
-
41:04 - 41:06So I'm gonna start this insert sorted.
-
41:06 - 41:08It's gonna take the
-
41:08 - 41:11head of the list, right? As a bi-reference parameter because there are
-
41:11 - 41:14situations, right? Where we're gonna be changing where the list points to when the cells in the
-
41:14 - 41:15first one
-
41:15 - 41:18and then the new cell that's coming in is the second parameter.
-
41:18 - 41:21So we're gonna search to find the place where it goes.
-
41:21 - 41:24So let's watch this go down it's
-
41:24 - 41:28loop. I do a four loop here that's like, well, Kerr starts this list while it's not null,
-
41:28 - 41:29advance by this,
-
41:29 - 41:34and if the cell that I'm trying to place, which in this case is the cell Rain,
-
41:34 - 41:36proceeds the one we're currently looking at,
-
41:36 - 41:38then this must be the place that goes in the list.
-
41:38 - 41:41So I look at Rain, I compare it to Cullaf
-
41:41 - 41:44and if Rain goes in front of Cullaf then this is where Rain should go in the list.
-
41:44 - 41:47Well, it doesn't actually proceed it,
-
41:47 - 41:48so I advance again. Then
-
41:48 - 41:51I look at Cullaf - Rain versus Lowery.
-
41:51 - 41:54Does Rain proceed Lowery? It does not. So I just keep going. So I'm gonna break out of
-
41:54 - 41:56the loop as soon as I get to
-
41:56 - 41:59the place I compare Rain to Matt.
-
41:59 - 42:00Doesn't come out.
-
42:00 - 42:03I compare Rain to Thomas.
-
42:03 - 42:07Now, this is the first time when new ones name came up as being less than
-
42:07 - 42:08Kerr's name.
-
42:08 - 42:13So that says, okay, well, Rain needs to go in front of Thomas.
-
42:13 - 42:15Okay. All is well and good
-
42:15 - 42:18almost.
-
42:18 - 42:20I have a pointer to Thomas.
-
42:20 - 42:23That's where my curve points to, right?
-
42:23 - 42:29And I want to put Rain kind of in the list right in front of Thomas. How do
-
42:29 - 42:38I get from Thomas to Matt? But it's
-
42:38 - 42:41not just enough to know Thomas, right? Because Thomas tells me like what's gonna follow
-
42:41 - 42:42Rain.
-
42:42 - 42:44So this is the cell where
-
42:44 - 42:47Rain's next is gonna point to where Thomas is because Rain is kind of gonna replace
-
42:47 - 42:51Thomas in the list and push Thomas one element down,
-
42:51 - 42:55but the situation is that I also need to know what proceeds Thomas. The
-
42:55 - 42:58cell that led into Thomas is the one whose next field needs to get reassigned
-
42:58 - 43:00to point to Rain.
-
43:00 - 43:01So the way the loop is going, right?
-
43:01 - 43:04It has to go kind of one too far
-
43:04 - 43:07to know that it was there because, like, if I look at Matt I can say, well, does Rain go
-
43:07 - 43:10after Matt? Yes, it does. Right? But that's not good enough to know that it goes
-
43:10 - 43:13right after Matt. The only way I can tell if it goes right after Matt is to say,
-
43:13 - 43:17well, if the cell that comes up next, right? Is behind Rain is that it goes in between
-
43:17 - 43:21these two.
-
43:21 - 43:22[Inaudible] Thomas and then
-
43:22 - 43:24[inaudible] Thomas?
-
43:24 - 43:27Yes. So at least I can do it by maybe kind of
-
43:27 - 43:30overwriting Thomas with Rain and then overwriting Rain with Thomas and kind of
-
43:30 - 43:31wiring them up. I'm gonna try to avoid that.
-
43:31 - 43:34I'm gonna actually say, well, let's just think about can we do it with
-
43:34 - 43:37leaving the information in the cells where it is?
-
43:37 - 43:40I don't know who else might point to Thomas, right? It would seem kind of weird if all of
-
43:40 - 43:44a sudden Thomas turned into Rain in some other way. That I don't know for sure
-
43:44 - 43:47who else is using this pointer. So lets assume that I can't do that
-
43:47 - 43:50variation of it, but I'd like to put Rain in between Matt and Thomas
-
43:50 - 43:53and the pointer I have is not quite good enough.
-
43:53 - 43:56The cells as is, right? Have this asymmetry. They know what follows or
-
43:56 - 43:58not. What precedes them.
-
43:58 - 44:02So, in fact, what I'm gonna change here is I'm going to run two pointers down
-
44:02 - 44:03the list,
-
44:03 - 44:05kind of in parallel,
-
44:05 - 44:08where they're always one step apart.
-
44:08 - 44:11Then I'm gonna track what was the one I last looked at
-
44:11 - 44:13and what is the one I'm currently looking at
-
44:13 - 44:16and I call this dragging a previous pointer
-
44:16 - 44:19or trailing a previous pointer behind.
-
44:19 - 44:20So
-
44:20 - 44:24each time I'm about to advance Kerr equals Kerr next, the thing I'll do right
-
44:24 - 44:27before it is to assign previous to be what Kerr is now.
-
44:27 - 44:31So then it'll advance to the next one, test against null, and keep going. So at
-
44:31 - 44:33any given state, right?
-
44:33 - 44:36Previous is exactly one behind where Kerr is
-
44:36 - 44:39and there's one special case, right? Which is that
-
44:39 - 44:44at the very first time through the loop, right? Kerr is set to be the list. Well,
-
44:44 - 44:48what's the previous of the head of the list? There actually is no previous, so actually
-
44:48 - 44:50initialize previous to be null.
-
44:50 - 44:52So the first time through, right?
-
44:52 - 44:55We've assigned previous to null and Kerr gets to go to the first one and then we
-
44:55 - 44:57say, well, is Cullaf -
-
44:57 - 44:58does
-
44:58 - 45:00Rain come before Cullaf? No.
-
45:00 - 45:04And so I'll advance both so move previous up to where Kerr is and then move
-
45:04 - 45:06Kerr up to the next one.
-
45:06 - 45:08So now they're pointing at Cullaf and Lowery together
-
45:08 - 45:12and, again, I'm comparing Lowery to Rain. Does Rain go in front of Lowery? No. So then I
-
45:12 - 45:15move up previous and move up Kerr.
-
45:15 - 45:17Does Rain go in front of Matt?
-
45:17 - 45:19No. I advance them both, right?
-
45:19 - 45:21And then I have
-
45:21 - 45:22
-
45:22 - 45:25previous at the Matt entry, Kerr at the Thomas entry,
-
45:25 - 45:28and then Rain does go right in between those, right?
-
45:28 - 45:32We know that it didn't precede Matt because we all ready made it through the loop.
-
45:32 - 45:37We know it does precede Thomas and that tells us it goes exactly in between them, right?
-
45:37 - 45:41That Matt should lead into Rain and Rain should lead into Thomas and that will have
-
45:41 - 45:44spliced it in the list at the right position
-
45:44 - 45:45relative to the
-
45:45 - 45:47other sorted entries. So I
-
45:47 - 45:55give myself just a little note here. Well, what are the possible values for previous?
-
45:55 - 46:00If the cell is gonna go anywhere in the list other than the very front,
-
46:00 - 46:05so as long as Rain follows at least one cell on the list, it's not the
-
46:05 - 46:05alphabetically
-
46:05 - 46:09first cell of all the ones I've seen, then previous will be some valid cell
-
46:09 - 46:12and potentially Kerr could be null,
-
46:12 - 46:17but there is a non-null prev in all of those cases.
-
46:17 - 46:20There's also the possibility though that previous is null
-
46:20 - 46:23in the case where the new cell was the alphabetically first. So if that one actually began
-
46:23 - 46:27with an A, let's say it was Alena.
-
46:27 - 46:30Then the first test would be if Alena is less then Cullaf. It is. It would
-
46:30 - 46:31immediately break and
-
46:31 - 46:35so previous would be null, Kerr would point to the front most cell,
-
46:35 - 46:38and I've got a little bit of a special case there
-
46:38 - 46:43where inserting at the front of the list isn't quite the same thing as inserting
-
46:43 - 46:44further down.
-
46:44 - 46:49So let me look at the code that I added to this and I ran out of room to draw pictures, so we'll have to do a little
-
46:49 - 46:51bit on the board here.
-
46:51 - 46:54That there are two pointers we need to assign
-
46:54 - 46:55for that
-
46:55 - 47:01new cell that's coming in. One is it's outgoing one
-
47:01 - 47:06and then another is it's incoming one. And so
-
47:06 - 47:11I have this list and,
-
47:11 - 47:16let's say, this new cell is going here. So this is like K, L, M,
-
47:16 - 47:17T, R.
-
47:17 - 47:22That the first line splices in the outgoing pointer in all cases. It says
-
47:22 - 47:24that the new ones next field is Kerr.
-
47:24 - 47:29So Kerr is the first cell, right? That we found that follows the cell we're trying
-
47:29 - 47:32to insert. It might be that Kerr is null,
-
47:32 - 47:33but that's totally fine too.
-
47:33 - 47:37In this case it happened to point - this is where Kerr was and this is where previous
-
47:37 - 47:39was.
-
47:39 - 47:41That it will make
-
47:41 - 47:44R point to T, so that is the outgoing pointer for the new cell
-
47:44 - 47:46and now there are two cases here.
-
47:46 - 47:51The ordinary case is that there is some previous cell. In which case the previous
-
47:51 - 47:54cell's next field needs to get updated to point to the new one.
-
47:54 - 47:58So we use the pointer to this one. It's next field
-
47:58 - 48:00no longer points to T,
-
48:00 - 48:05but instead points to R. And so I inserted R in between M and T with that
-
48:05 - 48:06adjustment.
-
48:06 - 48:09In the case where the new cell,
-
48:09 - 48:11let's say, was the A,
-
48:11 - 48:13then Kerr would be here
-
48:13 - 48:17and previous would be null.
-
48:17 - 48:20I will set A as next field to the Kerr,
-
48:20 - 48:23which spliced the outgoing pointer of A
-
48:23 - 48:25to attach to the rest of the list.
-
48:25 - 48:29But here's the special case. There is no previous next field that's gonna point to A.
-
48:29 - 48:32A actually needs to get reassigned to be the front most cell of the list. So it
-
48:32 - 48:36looks like our prepend operation where I'm saying list equals new one
-
48:36 - 48:40and the list is some reference parameter
-
48:40 - 48:42to some list elsewhere
-
48:42 - 48:46that then gets permanently set to the new cell. So I would call insert sorted
-
48:46 - 48:49from, like, the build address book function
-
48:49 - 48:52to attach it to the very front in this case.
-
48:52 - 48:56This is very common in linked list code, right? Is to have there be a bit of a special
-
48:56 - 49:00case about either the first cell or the last cell or on the empty list, right? But
-
49:00 - 49:03that there is a large
-
49:03 - 49:06- all the cells in the interior kind of behave the same. They have a cell in
-
49:06 - 49:10front of them and a cell in back of them and that insert has certain properties, but
-
49:10 - 49:13there's a little bit of an oddness with that maybe that first cell is sometimes the
-
49:13 - 49:16very last cell that requires a little special case handling.
-
49:16 - 49:20In this case, right? Putting A in the front means somebody doesn't point
-
49:20 - 49:22into A. It's the listhead that points to A
-
49:22 - 49:24and so it's not somebody's next field
-
49:24 - 49:30that we're updating. It really is the listhead pointer itself.
-
49:30 - 49:32Questions about that one?
-
49:32 - 49:35So I need to show you the recursive one. I'm not gonna be able to talk about it very much, but
-
49:35 - 49:38I'm gonna encourage you to take a look at it.
-
49:38 - 49:40Which is the
-
49:40 - 49:41
-
49:41 - 49:46same activity of inserting a cell
-
49:46 - 49:48into a list that's being kept in sorted order.
-
49:48 - 49:53Now, not using this iterative, not using this dragging of our previous pointer,
-
49:53 - 49:58but instead using a strong dense recursive powerful formulation here
-
49:58 - 50:01that basically has the idea that says, well,
-
50:01 - 50:03given a list that I'm inserting into,
-
50:03 - 50:06let's say it's the M through Z part of the list.
-
50:06 - 50:11I'm trying to insert R is I compare R to the front of the list and I say,
-
50:11 - 50:14well, does that become the new front of this list? That's what my base case is
-
50:14 - 50:18looking at. Is the list empty or does this one go in front of it? If so, prepend it.
-
50:18 - 50:19Otherwise
-
50:19 - 50:22just insert it in the remainder of this list.
-
50:22 - 50:24So if it doesn't insert
-
50:24 - 50:28at the front of M then we pass the N or the O whatever is following it and
-
50:28 - 50:31have it kind of recursively insert into the
-
50:31 - 50:34remainder of the list. Eventually it will hit the space case
-
50:34 - 50:38when it either gets to the end of the list or when there is
-
50:38 - 50:40the cell we're trying to insert
-
50:40 - 50:43belongs in front of these remaining cells. In which case, we do a prepend right
-
50:43 - 50:44there
-
50:44 - 50:46and stop the recursion.
-
50:46 - 50:49A dense little piece of code. One I'll
-
50:49 - 50:53encourage you to kind of trace a little bit on your own to kind of
-
50:53 - 50:56get an idea of how it's working, but it kind of shows in this case that the recursion is
-
50:56 - 50:57really buying you something
-
50:57 - 51:00by making it, I think, a much simpler and more direct way to
-
51:00 - 51:02express what you want to do and then kind of the
-
51:02 - 51:06more mechanical means of doing it iteratively.
-
51:06 - 51:08What we will talk about on Monday
-
51:08 - 51:12will be algorithms. We'll talk about algorithms, Chapter 7. Start talking about
-
51:12 - 51:16Big O and formal announcements algorithms and do a little bit of sorting. So I will see
-
51:16 - 51:18you on Monday
-
51:18 - 51:23and have a good weekend.
- Title:
- Lecture 13 | Programming Abstractions (Stanford)
- Description:
-
Lecture 13 by Julie Zelenski for the Programming Abstractions Course (CS106B) in the Stanford Computer Science Department.
Julie introduces linked lists and continues to discuss recursive data. She goes line by line through an example code she writes during the lecture. She then inserts variables in an order; she uses the example of an address book to explain this. Algorithm analysis are also introduced.
Complete Playlist for the Course:
http://www.youtube.com/view_play_list?p=FE6E58F856038C69CS 106B Course Website:
http://cs106b.stanford.eduStanford Center for Professional Development:
http://scpd.stanford.edu/Stanford University:
http://www.stanford.edu/Stanford University Channel on YouTube:
http://www.youtube.com/stanforduniversity/ - Video Language:
- English
- Duration:
- 51:35
N. Ueda edited English subtitles for Lecture 13 | Programming Abstractions (Stanford) | ||
Eunjeong_Kim added a translation |