Lecture 20 | Programming Abstractions (Stanford)
-
0:00 - 0:10
-
0:10 - 0:11
-
0:11 - 0:15This presentation is delivered by the Stanford Center for Professional
-
0:15 - 0:23Development.
-
0:23 - 0:25Hey there! Oh,
-
0:25 - 0:29we're back. We're back and now we're getting down and dirty. We'll do more pointers, and link
-
0:29 - 0:33list, and implementations. It's actually going to be like our life for the next
-
0:33 - 0:36week and half. There's just even more implementation, trying to think about how those
-
0:36 - 0:37things work on the backside. So
-
0:37 - 0:41I will do another alternate implementation of the stack today.
-
0:41 - 0:44So we did one based on vector and we're going to do one based on a link list.
-
0:44 - 0:47And then I'm going to do a cube based on link list, as well,
-
0:47 - 0:48to kind of just mix
-
0:48 - 0:51and match a little bit. And then, we're still at the end of the case study, which the
-
0:51 - 0:55material is covered in Chapter 9. I probably won't get thorough all of that today. What we
-
0:55 - 0:57don't finish today we'll be talking about on Friday,
-
0:57 - 1:00and then we'll go on to start talking about map implementation and look at
-
1:00 - 1:02binary search trees. How many
-
1:02 - 1:05people started [inaudible]? How many of
-
1:05 - 1:08you got somewhere feeling good?
-
1:08 - 1:09Not just yet. One thing I will
-
1:09 - 1:12tell you is that there are two implementations you're working on
-
1:12 - 1:16and I listed them in the order of the one that the material we've seen the most, right.
-
1:16 - 1:19We've talked about link list more than we have talked about things that are tree and
-
1:19 - 1:22heat based. So I listed that one first. But, in fact, actually, in terms of difficulty of coding,
-
1:22 - 1:27I think, the second one is little bit more attractable than the first. So
-
1:27 - 1:30there's no reason you can't do them in either order if it feels good to you to start on the second one
-
1:30 - 1:32before you come back to the first one.
-
1:32 - 1:35Or just trade off between working on them if one of them is giving you fits just look
-
1:35 - 1:37at the other one to clear your head,
-
1:37 - 1:41so just a thought about how to approach it. Okay.
-
1:41 - 1:46So I am going to do some coding. I'm going to come back to my slides in a little bit here.
-
1:46 - 1:50But to pick up where we left off last time, was we had written a
-
1:50 - 1:55vector based implementation of the stack
-
1:55 - 1:56abstraction
-
1:56 - 2:01and so looking at the main operations here for a stack or push and pop array
-
2:01 - 2:04that its mechanism here is just to add to the end of the vector that we've
-
2:04 - 2:08got. So I'm letting the vector handle all the growing, and resizing,
-
2:08 - 2:11and memory, and manipulations that are needed for that.
-
2:11 - 2:14And then, when asked to pop one, we just take the one that was last most added,
-
2:14 - 2:16which will be at the far end of the array.
-
2:16 - 2:19And so given the way vector behaves, knowing that we know it's a continuous
-
2:19 - 2:21array based
-
2:21 - 2:25backing behind it, then we're getting this O of one access to that last element
-
2:25 - 2:27to either add a new one down there
-
2:27 - 2:30or to retrieve one and remove it from the end
-
2:30 - 2:33so that push and pop operations will both being in constant time no matter how many elements are in the
-
2:33 - 2:36stack, 10, 15, 6 million,
-
2:36 - 2:40the little bit of work we're doing is affecting only the far end of the array
-
2:40 - 2:44and not causing the rest of the configured storage to be jostled whatsoever so
-
2:44 - 2:46pretty easy to get up and running.
-
2:46 - 2:50So in general, once you have one abstraction you can start leveraging it into
-
2:50 - 2:52building other attractions and the vector manages a lot of the things that
-
2:52 - 2:56any array based implementation would need. So rather than using a raw array,
-
2:56 - 2:57there's very little reason to kind of,
-
2:57 - 3:00you know, ditch vector and go the straight raw array in this case because all it basically does
-
3:00 - 3:03it open up opportunities for error and kind of management and
-
3:03 - 3:08the kind of efficiency you can gain back by removing vectors intermediate
-
3:08 - 3:11stuff is really not very profound so not worth,
-
3:11 - 3:12probably,
-
3:12 - 3:13taking on.
-
3:13 - 3:16What we do is consider the only link limitation. We had talked about a link
-
3:16 - 3:20list for a vector and we kind of discarded it as likely not to lead anywhere
-
3:20 - 3:21interesting.
-
3:21 - 3:24I actually, am going to fully pursue it for this stack because it actually turns out that a link list
-
3:24 - 3:28is a good fit for what the behavior that a stack needs in terms of the
-
3:28 - 3:29manipulations and flexibility.
-
3:29 - 3:33So if I have a stack of enterers where I push 10, 20, and 30. I'm going to
-
3:33 - 3:37do that same diagram we did for the vector one as I did for the stack is
-
3:37 - 3:38
-
3:38 - 3:40one possibility
-
3:40 - 3:42is that I put them in the list
-
3:42 - 3:47in this order.
-
3:47 - 3:50Another possibility
-
3:50 - 3:51is that I put them in,
-
3:51 - 3:58in this order. We'll call this Strategy A; we'll call this Strategy B.
-
3:58 - 4:01They seem, you know, fairly symmetric, right.
-
4:01 - 4:05If they're going to be a strong reason that
-
4:05 - 4:09leaves us to prefer Strategy A over B, or are they just equally
-
4:09 - 4:12easy to get the things done that we need to do?
-
4:12 - 4:16Anybody want to make an argument for me.
-
4:16 - 4:18Help me out. Last in, first out.
-
4:18 - 4:22Last in, first out.
-
4:22 - 4:25[Inaudible]. Be careful here. So 10, 20, 30 means the way the stack works is like
-
4:25 - 4:26this, 10,
-
4:26 - 4:2820, 30
-
4:28 - 4:31and so it's at the top that we're interested in, right? Um hm.
-
4:31 - 4:34That the top is where activity is taking place. Oh.
-
4:34 - 4:37So we want to be adding things and losing from the top. So do we want to put the top at
-
4:37 - 4:41the end of our list or at the front of our list?
-
4:41 - 4:46Which is the easier to access in the link list design? [Inaudible].
-
4:46 - 4:48The front, right?
-
4:48 - 4:52So in the array format we prefer this, putting the top of the vector on the far end
-
4:52 - 4:54because then there is the only jostling of
-
4:54 - 4:58that. But needing access to the top here in the front is actually going to be the better way to get the link
-
4:58 - 5:00list strategy
-
5:00 - 5:04you work in. Let me actually go through both the push and the pop to convince
-
5:04 - 5:05you why this is true.
-
5:05 - 5:09So if I have access in the 10, 20, 30 case I could actually keep a separate
-
5:09 - 5:12additional pointer, one to the front and one to the back. So it could actually
-
5:12 - 5:13become maintaining at
-
5:13 - 5:15all times as pointing to the back. If I
-
5:15 - 5:19did that, right, then subsequent push up to a 40, it's pretty easy to tack on a 40.
-
5:19 - 5:20So it turns out it would be that
-
5:20 - 5:24the adding it's the push operation that actually isn't really a problem on this
-
5:24 - 5:26Strategy A. We can still kind of easily, and over
-
5:26 - 5:30time, if we have that tail pointer just tack one on to the end. As
-
5:30 - 5:32for the pop operation,
-
5:32 - 5:33
-
5:33 - 5:34if I have to pop that 30,
-
5:34 - 5:39I need to adjust that tail pointer and move it back a cell. And that's where we
-
5:39 - 5:41start to get into trouble. If I have a pointer to
-
5:41 - 5:45the tail cell there is no mechanism in the singly linked list to back
-
5:45 - 5:46up. If I
-
5:46 - 5:48say it's time to pop 30,
-
5:48 - 5:49then I would actually need
-
5:49 - 5:52to delete the 30, get the value out, but then I need to update this tail pointer to
-
5:52 - 5:55point to 20, and 30 doesn't know
-
5:55 - 5:57where 20 is, 30's oblivious about these things.
-
5:57 - 6:00And so the only way to find 20 in singly linked list would be go back to the very
-
6:00 - 6:03beginning, walk your way down, and find the one that pointed to the cell you just took out of
-
6:03 - 6:05the list
-
6:05 - 6:08and that's going to be an operation we want to avoid.
-
6:08 - 6:11In the Strategy B case, right, adding a cell, this
-
6:11 - 6:15means putting a 40 in allocating a new cell and then attaching it,
-
6:15 - 6:18splicing it in, right between wiring in two pointers, and we can do these links in
-
6:18 - 6:19constant time,
-
6:19 - 6:24and then popping one is taking that front row cell off. Easy to get to, easy to update, and
-
6:24 - 6:25splice out
-
6:25 - 6:29so no traversal, no extra pointers needed.
-
6:29 - 6:31The idea that there are,
-
6:31 - 6:34you know, 100 or 1,000 elements following the one that's on
-
6:34 - 6:36top is irrelevant. It
-
6:36 - 6:38doesn't have any impact, whatsoever, on the running time
-
6:38 - 6:42to access the front, or stuff another front, or taking it on or off the front.
-
6:42 - 6:45So it is Strategy B
-
6:45 - 6:47that gives us the best setup when it's
-
6:47 - 6:50in the back of the linked list.
-
6:50 - 6:55So let me go ahead and do it. I think it's kind of
-
6:55 - 6:58good to see. Oh, like, what is it like to just write code and make stuff work.
-
6:58 - 7:04And so I'm kind of fond of this and you can tell me.
-
7:04 - 7:07I make a cell C
-
7:07 - 7:08it has an L type
-
7:08 - 7:12value and it has a soft T next
-
7:12 - 7:15right there.
-
7:15 - 7:19And then I have a pointer to the front linked list cell.
-
7:19 - 7:21So in addition, you know,
-
7:21 - 7:25it might that in order to make something like size operate
-
7:25 - 7:26efficiently,
-
7:26 - 7:27I might also want to catch the
-
7:27 - 7:30number of cells that update, or added or renew. I can also decide to
-
7:30 - 7:33just leave it out for now. Maybe
-
7:33 - 7:36I'll actually even change this to be the easier function, right, which
-
7:36 - 7:38is empty form.
-
7:38 - 7:40That way I don't even have to go down that road
-
7:40 - 7:44for now.
-
7:44 - 7:46Go back over here to
-
7:46 - 7:49this side and I've got to make everything now consistent with what's going on
-
7:49 - 7:50there.
-
7:50 - 7:51Okay.
-
7:51 - 7:54Let's start off with our constructor, which is a good place to make sure you get
-
7:54 - 7:56into a valid state.
-
7:56 - 7:59In this case, we're going to use the empty list so the head pointer points and tells us
-
7:59 - 8:03we have no cells whatsoever in the list. So we don't pre allocate anything,
-
8:03 - 8:04we don't get ready.
-
8:04 - 8:07What's kind of nice with this linked list is to allocate on demand
-
8:07 - 8:10each individual cell that's asked to be added to the list.
-
8:10 - 8:13The delete operation actually does show we need to do some work. I'm actually not
-
8:13 - 8:15going to implement it but I'm going to mention here that I would need to delete the
-
8:15 - 8:16entire list,
-
8:16 - 8:19which would involve, either iterates or recursion my way down to kind of
-
8:19 - 8:21do all the work.
-
8:21 - 8:25And then I changed this from size to iterate.
-
8:25 - 8:28I'd like to know if my list is empty.
-
8:28 - 8:30So I can just test for head
-
8:30 - 8:33is equal, equal
-
8:33 - 8:36to null. If it's null we have no list. Let
-
8:36 - 8:41me work on push before I work on pop. I'll
-
8:41 - 8:45turn them around. The push operation is, make myself a new cell. All
-
8:45 - 8:47right, let's go through the steps for that. New
-
8:47 - 8:50cell equals new cell
-
8:50 - 8:54T. [Inaudible] the size to hold a value
-
8:54 - 8:56and an X link. I'm going to set
-
8:56 - 8:59the new styles val to be the
-
8:59 - 9:01perimeter that came in.
-
9:01 - 9:05And now, I'm going to splice this guy onto the front of my list.
-
9:05 - 9:10So the outgoing pointer I'm doing first to the new cell is allocated and
-
9:10 - 9:15leads to what was previously the front row cell.
-
9:15 - 9:19And then it is now updated to point to this
-
9:19 - 9:21one. We've got pointer wired, one value
-
9:21 - 9:23assigned, and we've got a new
-
9:23 - 9:28cell on the front. The
-
9:28 - 9:29inverse of that,
-
9:29 - 9:32taking something off my list, I'm going to need
-
9:32 - 9:35to kind of detach that front row cell, delete its memory, get its value, things like
-
9:35 - 9:38that. So the error checking is still the same at the very beginning. Like, if I've
-
9:38 - 9:41got an empty staff I want to be sure I don't just kind of do reference no
-
9:41 - 9:42and get into
-
9:42 - 9:48some bad situations. So I report that error back using error, which will halt the program
-
9:48 - 9:49there.
-
9:49 - 9:51Otherwise, right,
-
9:51 - 9:52the element on
-
9:52 - 9:57top is the one that's in the value field of the head cell. So knowing that head's
-
9:57 - 9:59null is a safety reference to do there.
-
9:59 - 10:03And then I'm going to go ahead and
-
10:03 - 10:06get a hold of what that thing is and I'm
-
10:06 - 10:09going update
-
10:09 - 10:13the head to point to the cell after it. So splicing it out
-
10:13 - 10:14
-
10:14 - 10:17and then deleting the
-
10:17 - 10:20old cell.
-
10:20 - 10:23Just take a look at these. Once we start doing
-
10:23 - 10:25pointers, right, there's just opportunities for error.
-
10:25 - 10:28I feel kind of good about what I did here but I am going to just do a little bit of
-
10:28 - 10:30tracing to kind of
-
10:30 - 10:33confirm for myself that the most likely situations that get you in trouble with link list is you'll
-
10:33 - 10:36handle the mainstream case but somehow forget one of the edge
-
10:36 - 10:40cases. Such as, what if the list was totally empty or just had a single cell?
-
10:40 - 10:43Is there some special case handling that needs to be dealt with?
-
10:43 - 10:45So if I think about it in terms of the push case,
-
10:45 - 10:48you know, I might say, well, if there's an existing set of cells,
-
10:48 - 10:50so we're using Strategy B here, let me
-
10:50 - 10:54erase A so I know what I'm looking at,
-
10:54 - 10:58that its head is currently pointing to a set of cells, right, that my
-
10:58 - 11:00allocation of the new cell out here,
-
11:00 - 11:02right, assigning its value,
-
11:02 - 11:07assigning its next field to be where head points two, and then sending head to
-
11:07 - 11:08this new guy, it
-
11:08 - 11:10looks to be good.
-
11:10 - 11:14If I also do that tracing on the - what if the list that we were looking at was
-
11:14 - 11:17just null to begin with.
-
11:17 - 11:20So there were no cells in there. This is the very first cell. It isn't going to have any kind of trouble
-
11:20 - 11:24stumbling over this case. So I would allocate that new cell 40, assign
-
11:24 - 11:25its value.
-
11:25 - 11:28Set the next field to be what head is, so that just basically sets the
-
11:28 - 11:32trail coming out of 40 to be null and then updates the head there. So we've
-
11:32 - 11:35produced a single linked list, right, with one cell.
-
11:35 - 11:37It looks like
-
11:37 - 11:39we're doing okay on the push behaviors.
-
11:39 - 11:43Now, the pop behavior, in this sort of case may be relevant to think about, if it's
-
11:43 - 11:46totally empty. All right, we come in and we've got an empty cell,
-
11:46 - 11:49then the empty test should cause it to error and get down to the rest of the
-
11:49 - 11:50code.
-
11:50 - 11:52Let's say that B points to
-
11:52 - 11:55some sequence of things, 30, 20,
-
11:55 - 11:5610,
-
11:56 - 12:02that
-
12:02 - 12:05taking the head value off and kind of writing it down somewhere, saying, okay,
-
12:05 - 12:0730 was the top value.
-
12:07 - 12:10The old cell is currently the head so we're
-
12:10 - 12:13keeping a temporary on this thing.
-
12:13 - 12:17And then head equals head error next,
-
12:17 - 12:19which splices out
-
12:19 - 12:23the cell around so we no longer have a pointer into this 30. The only place
-
12:23 - 12:27we can get back to it is with this temporary variable we assigned right here of old
-
12:27 - 12:30and then we delete that
-
12:30 - 12:31old to reclaim that storage
-
12:31 - 12:33and then our list now is
-
12:33 - 12:37the values 20 and 10, which followed it later in the list. To, also,
-
12:37 - 12:41do a little check what if it was the very last cell
-
12:41 - 12:44in the list that we're trying to pop? Does that
-
12:44 - 12:46have any special handling that we have overlooked
-
12:46 - 12:50if we just have a ten here with a null after it? I'll go
-
12:50 - 12:55through the process of writing down the ten.
-
12:55 - 12:59Assigning old to where head is,
-
12:59 - 13:05and assigning head-to-head error next, where head error of next cell is null
-
13:05 - 13:08but pointing to that, and then we set our list to null, and then we delete this cell. And so after
-
13:08 - 13:11we're done, right, we have the empty list again, the
-
13:11 - 13:12head pointer back to null.
-
13:12 - 13:16So it seems like we're doing pretty good job. Have a bunch of cells. Have one cell.
-
13:16 - 13:25No cells. Different things kind of seem to be going through here doing the right thing. Let's do it. A little bit
-
13:25 - 13:34of code on this side. [Inaudible]. Okay. Pop empty cell. I've
-
13:34 - 13:37got that. Oh,
-
13:37 - 13:40I think I may have proved, oh, it deliberately makes the error, in
-
13:40 - 13:41fact.
-
13:41 - 13:43That it
-
13:43 - 13:48was designed to test on that. [Inaudible] up
-
13:48 - 13:52to the end. So let's
-
13:52 - 13:54
-
13:54 - 13:57see if
-
13:57 - 14:03we get back a three, two, one out of this guy. Okay. So
-
14:03 - 14:08we manage to do okay even on that.
-
14:08 - 14:10So looking at this piece of code, all
-
14:10 - 14:14right, the two operations we're most interested in, push and pop, right,
-
14:14 - 14:19are each oh of one, right. The number of elements out there, right, aren't
-
14:19 - 14:21changing anything about its performance. It does a little bit of
-
14:21 - 14:23imagination and a little bit of pointer arrangement up here to the front to
-
14:23 - 14:24the end
-
14:24 - 14:28and so it has a very nice tight allocation strategy, too, which is appealing relative
-
14:28 - 14:29to what
-
14:29 - 14:33the vector-based strategy was doing. It's like, now, it's doing things in advance on our behalf like
-
14:33 - 14:36extending our capacity so that every now and then we had some
-
14:36 - 14:39little glitch right when you were doing that big resize operation that happened infrequently,
-
14:39 - 14:41you won't have that same
-
14:41 - 14:44concern with this one because it does exactly what it needs at any given
-
14:44 - 14:47time, which is allocate a single cell, deletes a single cell,
-
14:47 - 14:51and also keeping the allocation very tidy in that way. So they'll both
-
14:51 - 14:54end of being oh of one. And both of these are
-
14:54 - 14:58commonly used viable strategies for how a stack is implemented. Right. Depending on the,
-
14:58 - 14:59
-
14:59 - 15:02you know, just the inclination of the program or they may have decided
-
15:02 - 15:05one way was the way to go versus another
-
15:05 - 15:07that
-
15:07 - 15:09you will see both used in common practice because there really isn't
-
15:09 - 15:12one of them that's obviously better or obviously worse, right.
-
15:12 - 15:16Now, this uses a little bit more memory per cell, but then you have excess capacity
-
15:16 - 15:21and vector has excess capacity but no overhead per cell.
-
15:21 - 15:23There's a few other things to kind of think about trading off. You say, well, the code,
-
15:23 - 15:27itself, is a little harder to write if you're using only [inaudible].
-
15:27 - 15:30That means it's a little bit more error prone
-
15:30 - 15:33and more likely, you'll make a mistake and have to do debug your way through it and the way with the
-
15:33 - 15:35vector it was pretty easy to get without tearing out your
-
15:35 - 15:36hair. Now, if
-
15:36 - 15:40we can
-
15:40 - 15:42do
-
15:42 - 15:44stack and queue that fast -
-
15:44 - 15:45I mean, stack that fast, then you figure queue
-
15:45 - 15:47must be
-
15:47 - 15:51not so crazy either. Let me
-
15:51 - 15:59draw you a picture of queue.
-
15:59 - 16:02Okay.
-
16:02 - 16:08I've got my
-
16:08 - 16:12queue and I can use the
-
16:12 - 16:14End queue operation on it to put in a 10, to put
-
16:14 - 16:16in a 20, to put in a 30.
-
16:16 - 16:18And
-
16:18 - 16:20I'm going to try and get back out what was
-
16:20 - 16:23front most.
-
16:23 - 16:25Okay. So queue is FIFO, first in
-
16:25 - 16:27first out,
-
16:27 - 16:30and waiting in line, whoever's been in the queue longest is the first one to come
-
16:30 - 16:31out,
-
16:31 - 16:33very fair handling of things.
-
16:33 - 16:37And so if were to think about this in terms of let's go straight across the
-
16:37 - 16:39linked list. We just got our head around the link list with the stack. Let's see if there's a link list for the
-
16:39 - 16:40queue
-
16:40 - 16:44provide the same kind of easy access to the things we need to do the work.
-
16:44 - 16:48So it seems like the
-
16:48 - 16:51two strategies that we looked at for stack
-
16:51 - 16:55are probably the same two to look at for this one, right, which we go in the front
-
16:55 - 16:57ways orders. I mean the front of the queue accessible
-
16:57 - 17:01in there and reversing our way down to the tail
-
17:01 - 17:05or the other way around. Right. I mean, the tail of the queue up
-
17:05 - 17:09here in the front
-
17:09 - 17:15leading the way to the head of the queue. So this is head - I'll call it
-
17:15 - 17:17front of queue,
-
17:17 - 17:20and this is back,
-
17:20 - 17:24this is the back
-
17:24 - 17:27and that's the front. Okay. So that will be GA that will be GB. But first off,
-
17:27 - 17:29ask yourself,
-
17:29 - 17:30where does the queue do its work?
-
17:30 - 17:38Does it do it at the front or does it do it at the back?
-
17:38 - 17:41It does it at both.
-
17:41 - 17:44But when you're end queuing, right, you're manipulating the back of the queue, adding
-
17:44 - 17:47something to the tail end of the line. When
-
17:47 - 17:51you are de queuing, you're adding something to the front of the queue. So like unlike the stack where both the
-
17:51 - 17:53actions were happening in the same place, and that kind of unified your thinking
-
17:53 - 17:56about where to
-
17:56 - 17:57allow for that,
-
17:57 - 18:00you know, easy access to the top, the one thing the stack cared
-
18:00 - 18:03about, but the bottom of the stack, right, was, you know,
-
18:03 - 18:04buried and it didn't matter.
-
18:04 - 18:06The queue actually needs accesses to both.
-
18:06 - 18:07So that
-
18:07 - 18:10sort of sounds like that both these strategies, right, have the potential to be
-
18:10 - 18:14trouble for us. Because it's like in the link list form, right, you know the idea that
-
18:14 - 18:17access to the head is easy, access to the tail that is a little bit more tricky.
-
18:17 - 18:20Now, I said we could add a tail pointer. And maybe that's actually going to be part of the
-
18:20 - 18:22answer to this, right,
-
18:22 - 18:26but as it is, with no head pointers in here, that adding an item to A would
-
18:26 - 18:30involve traversing that queue to find the end to put a new one on.
-
18:30 - 18:34Similarly, if indeed, the inverse operation is going to be our trouble, which
-
18:34 - 18:38is de queuing, we have to kind of walk its way down to find the last element
-
18:38 - 18:41in the link list ordering, which is [inaudible] queue.
-
18:41 - 18:43So what say we add a
-
18:43 - 18:44tail pointer in both cases? So we
-
18:44 - 18:46have a head that
-
18:46 - 18:48points to here and a tail that points to there, it's
-
18:48 - 18:50like that will make our
-
18:50 - 18:53problem a little bit easier to deal with. So
-
18:53 - 18:55let me look at B first.
-
18:55 - 18:58That adding to the back of the queue is easy. We saw how we did that with the stack,
-
18:58 - 18:59right, so that
-
18:59 - 19:01the End queue
-
19:01 - 19:05operation doesn't need that tail pointer and it already kind of wasn't a problem for us.
-
19:05 - 19:08Now, the D queue operation would mean, okay, using our tail pointer to know where the
-
19:08 - 19:11last close value is tells us it's ten.
-
19:11 - 19:14But we have the same problem I had pointed out with the stack, which is,
-
19:14 - 19:18we can get to this value, we can return this value, you know, we can delete this
-
19:18 - 19:23cell, but what we need to do, also, in the operation, update our tail pointer so a
-
19:23 - 19:25subsequent D queue can do its work efficiently.
-
19:25 - 19:28And it's that backing up of the tail pointer that
-
19:28 - 19:29is the sticky point
-
19:29 - 19:33that given that ten doesn't know who points into it, the single link list if very
-
19:33 - 19:35asymmetric that way.
-
19:35 - 19:37But you only know what's follows you, not what proceeds,
-
19:37 - 19:40but backing up this pointer is not easy. It
-
19:40 - 19:44involves the reversal of going back to the beginning, walking your way down to find somebody who
-
19:44 - 19:46points to the last [inaudible].
-
19:46 - 19:50So it seems like this tail pointer didn't buy us a lot. It helped a little bit, you know,
-
19:50 - 19:53to get some of the operation up and running, but in the end, keeping and maintaining
-
19:53 - 19:56that tail pointer sort of came back to bite us.
-
19:56 - 19:58In the case of the Strategy A,
-
19:58 - 20:02the tail pointer gives us immediate access to the back, which we're going to need for
-
20:02 - 20:05the end queue. If I go to end queue of 40, in this case,
-
20:05 - 20:10then what I'm going to need to do is make a new cell, attach it off of the
-
20:10 - 20:11current cell,
-
20:11 - 20:13and then update the tail,
-
20:13 - 20:17right, to point to that cell while that update's moving forward down the list,
-
20:17 - 20:20right. If you're on the third cell and you add a fourth cell, you need to move the tail
-
20:20 - 20:24from the third to the fourth. Moving that direction's easy. It's the backing
-
20:24 - 20:27up where we got into trouble. So in fact, this
-
20:27 - 20:31suggests that Strategy A is the one we can make both these operations
-
20:31 - 20:33manipulate in constant time in a way
-
20:33 - 20:35that this one got
-
20:35 - 20:37us into trouble.
-
20:37 - 20:41I think we can do it.
-
20:41 - 20:44Let's switch it over. I've got an
-
20:44 - 20:49empty queue here.
-
20:49 - 20:53Also, it is empty in size. This is the same problem with size, which is either you have to go count them
-
20:53 - 20:55or you have to
-
20:55 - 20:55
-
20:55 - 20:57cache the size.
-
20:57 - 21:01I will build the same exactly structure, in fact.
-
21:01 - 21:11Now, I'll type
-
21:11 - 21:12next. It's going to have both a
-
21:12 - 21:14head and a tail pointer
-
21:14 - 21:18so we can keep track of the two ends we've got going. I think I'm
-
21:18 - 21:24missing my [inaudible]. Slip over.
-
21:24 - 21:29Okay. And
-
21:29 - 21:32then I will make the same comment here about, yeah, you need to delete all cells.
-
21:32 - 21:34So I set the head and the tail to null. I'm
-
21:34 - 21:41now in my empty state that tells me I've got nothing in the queue, nothing at all, so far. And
-
21:41 - 21:48my Y is empty. Oh.
-
21:48 - 21:50We'll check that
-
21:50 - 21:53return equals, equals null, just like
-
21:53 - 21:54it did. In fact, it looks a lot like
-
21:54 - 21:55the stack, actually.
-
21:55 - 21:59And here I'm going to show you something kind of funny. If I go take
-
21:59 - 22:04my stack CCPs pop.
-
22:04 - 22:08So if you remember what pop did over here, is it took the front most cell off the
-
22:08 - 22:11list. And
-
22:11 - 22:12in the case of the queue
-
22:12 - 22:16that was the
-
22:16 - 22:18popping operation. And
-
22:18 - 22:21it turns out the D queue
-
22:21 - 22:25operation is exactly the same.
-
22:25 - 22:29If we're empty, right, then we want to raise there. Otherwise, we take the head's
-
22:29 - 22:29value.
-
22:29 - 22:33We move around the head, we delete the old memory. So it's not
-
22:33 - 22:36actually the top element. I should, actually, be a little bit more
-
22:36 - 22:39careful about my copying and pasting here. I could really call that
-
22:39 - 22:41front. It's the front-most element on the top.
-
22:41 - 22:43But it's like the exact same mechanics work
-
22:43 - 22:48to take a cell off the front in that way. Well, that's sort of
-
22:48 - 22:48nice.
-
22:48 - 22:51And it's like, yeah, well, since I have some code around I want to go try it.
-
22:51 - 22:55My stack, also, kind of does some things useful in push that I might be able to use. It's not
-
22:55 - 22:58exactly the same because it's adding it to the front, but it is
-
22:58 - 23:00setting up a new cell. So I'm going to
-
23:00 - 23:05make a new cell and I set its value. Then, it's attaching
-
23:05 - 23:07looks a little different. Let's take a look.
-
23:07 - 23:11We omitted a cell, copied the value in,
-
23:11 - 23:16now the goal is giving our pointer to the tail, we want to attach onto the tail.
-
23:16 - 23:22So we know that it's always going to have a next of null, the new cell. So no
-
23:22 - 23:23matter what,
-
23:23 - 23:26it will be the new last cell and it defiantly needs that value that tells
-
23:26 - 23:28us we're at the end of the list.
-
23:28 - 23:32And then we have to attach it to our tail. I'm going to write this code first and it's going to be
-
23:32 - 23:35wrong. So just go along with me in this case.
-
23:35 - 23:37If the tail's next is the new cell.
-
23:37 - 23:40So if I'm wiring in the pointer from the tail onto the cell we have
-
23:40 - 23:41there,
-
23:41 - 23:48and then we want to update the tail to point to the cell. So
-
23:48 - 23:48almost,
-
23:48 - 23:53but not quite, everything I need to do.
-
23:53 - 23:56Someone want to point out to me what it is I have failed
-
23:56 - 24:05to consider in this situation. [Inaudible].
-
24:05 - 24:09It's the what? [Inaudible]. Yeah. ? trying to make null point to something [inaudible]. Exactly. So if my queue is totally empty. So in these cases like
-
24:09 - 24:12- one thing you can often think about whenever you see yourself with this
-
24:12 - 24:15error, and you're dereferencing something, you have to considered, well, is there a possibility
-
24:15 - 24:20that that value is null. And if so I'd better do something
-
24:20 - 24:23to protect against it. So in the case of the new cell here, I'm setting aside and
-
24:23 - 24:27not clearing that cell. We know it's valid, [inaudible], we've got good memory.
-
24:27 - 24:30That part's good but the access to the tail, and that's assuming
-
24:30 - 24:34there is a tail, that there is at least one cell already in the queue that the tail
-
24:34 - 24:35is pointing to.
-
24:35 - 24:37When that's not true,
-
24:37 - 24:39this is going to blow up. It's going to try to dereference it.
-
24:39 - 24:43So what we can do here is we can just check for that. We can say
-
24:43 - 24:45if the queue is empty
-
24:45 - 24:48then
-
24:48 - 24:50what we want to do is say that head
-
24:50 - 24:53equals tail equals new
-
24:53 - 24:54cell.
-
24:54 - 25:00Otherwise, we've got some existing tail and we
-
25:00 - 25:02just need to attach to it.
-
25:02 - 25:05Now, this is what I meant about that often there are little bit
-
25:05 - 25:10of special cases for certain
-
25:10 - 25:12different inputs. In particular, the most common ones are
-
25:12 - 25:16an empty list or a single link list being distinguished from a list that has
-
25:16 - 25:20two or more elements. So sometimes it's all about - a single link list has problems and
-
25:20 - 25:23so does the empty list. In this case, it's exactly the empty list. Like a
-
25:23 - 25:27single cell is actually fine, you know, one, ten, 6,000
-
25:27 - 25:31all work equally well. It's that empty case that we have to work on
-
25:31 - 25:36setting our head and tail to that. So with
-
25:36 - 25:38this plan we go back to my
-
25:38 - 25:40use of this. And
-
25:40 - 25:47stop talking about my stack and change into my queue,
-
25:47 - 25:56end queuing instead
-
25:56 - 25:58of pushing. [Inaudible]. Oh, 591 errors.
-
25:58 - 26:01Well,
-
26:01 - 26:15that's really - 591, what is that? [Inaudible].
-
26:15 - 26:17Oh, yeah, this is the year I was going
-
26:17 - 26:20to talk about but I
-
26:20 - 26:23failed to do.
-
26:23 - 26:26So this is the kind of thing you'll get
-
26:26 - 26:30from failing to protect your [inaudible] from
-
26:30 - 26:31being revisited.
-
26:31 - 26:33And so I'll
-
26:33 - 26:36be - if I haven't deft this
-
26:36 - 26:39funny little symbol I just made up then I want to find it in the
-
26:39 - 26:42end deft. So if it came back around and it saw this same header file, it was
-
26:42 - 26:45supposed to say I already seen that symbol and I won't do it. But, in fact, I had
-
26:45 - 26:47accidentally named one of them
-
26:47 - 26:50with a capital H and one with a lowercase H. It says if this symbol's not been
-
26:50 - 26:53identified then define this other symbol and keep going. And so the next time it saw
-
26:53 - 26:57the header files it said if that this lowercase H hasn't been
-
26:57 - 27:00defined, well it hadn't so it made it again and then it kept doing that until it got really
-
27:00 - 27:03totally twisted up about it. So I will
-
27:03 - 27:06make them match, with any
-
27:06 - 27:07luck,
-
27:07 - 27:11without the caps lock on. Three times is a charm.
-
27:11 - 27:12And then one, two, three
-
27:12 - 27:21pop out the other side of queue, as I was hoping. Okay.
-
27:21 - 27:24So you know what I'm going to do, actually? I'm actually not going
-
27:24 - 27:27to go through the alternate implementation of queue. I'm just saying
-
27:27 - 27:30like given that it works so well for stack, right, to have this kind of
-
27:30 - 27:34single link list, you know, efficient allocation, it's not surprising that queue,
-
27:34 - 27:35like, given to us. And what
-
27:35 - 27:37this is, like I said earlier, I said, well,
-
27:37 - 27:41you know you can do things with vector, you can do things with
-
27:41 - 27:44stack, anything you do with stack you can do with vector if you were just being
-
27:44 - 27:48careful. Right. The pushing, and popping, and the queue D queue, are operations that you could express
-
27:48 - 27:52in other terms of vector adds and removes and inserts that things.
-
27:52 - 27:55But one of the nice things about providing a structure like a stack or queue is it says
-
27:55 - 27:58these are the only things you're allowed to add at this end, remove from that end,
-
27:58 - 28:02it gives you options as a implementer that don't make sense for the general
-
28:02 - 28:06purpose case. That the vector as a link list had some compromises
-
28:06 - 28:10that probably weren't worth making. But in the case of stack and queue it actually came out
-
28:10 - 28:13very cleanly and very nicely, like this tidy little access to one end, or the
-
28:13 - 28:15other end, or both, right,
-
28:15 - 28:17was easily managed with a link list and then it didn't have any of the constraints of
-
28:17 - 28:20the continuous memory to fight with.
-
28:20 - 28:21And so often having a structure
-
28:21 - 28:25that actually offers less gives you some different options as an
-
28:25 - 28:28implementer because you know you don't have to support access into the middle in
-
28:28 - 28:31an efficient way because
-
28:31 - 28:33the stack and queue don't let you. They don't let you riffle through the
-
28:33 - 28:35middle of the stack or the queue to do things
-
28:35 - 28:38and that gives you some freedom as an implementer, which is neat to take advantage
-
28:38 - 28:43of. Yes, sir. [Inaudible] in Java
-
28:43 - 28:55that, you know, we supposed to use an Array whenever we could because Array uses more
-
28:55 - 29:00memory ? Um hm. Does the queue
-
29:00 - 29:03and stack use more memory than an Array, for example? So typically they'll be about the same, because of exactly this one thing, which is it allocates tightly so it asks for one cell per entry that's in there, right. And that cell has this overhead in the form of this extra pointer.
-
29:03 - 29:06Right. So in effect it means that everything got a little bit bigger because
-
29:06 - 29:08everything's carrying a little overhead.
-
29:08 - 29:11Okay. So there's a little bit more memory. The thing the Array is doing is it tends to be
-
29:11 - 29:15allocating extra slots that aren't being used. So it's not usually tightly allocated
-
29:15 - 29:18either. So in any given situation it could be as much as twice as big
-
29:18 - 29:19because it had that extra space.
-
29:19 - 29:22So kind of in the tradeoff they tend to be in the same
-
29:22 - 29:25general range. This one has about twice the space, I think it's about four
-
29:25 - 29:28bites it has a four-byte pointer. The thing's much bigger
-
29:28 - 29:30and it turns out actually this four bite pointer might be a smaller percentage of
-
29:30 - 29:35the overhead and will be a larger amount of the capacity in the excess case.
-
29:35 - 29:37So for a lot of things they're going to be about the same range. And then there's
-
29:37 - 29:40a few isolated situations where,
-
29:40 - 29:43yeah, if you have very big things being stored having a lot of excess capacity
-
29:43 - 29:45is likely to be a more expensive
-
29:45 - 29:48part of the vector strategy than the link list. But the
-
29:48 - 29:51link list does have this built in overhead for every element.
-
29:51 - 29:54And so it's not the case where you would say right off the bat,
-
29:54 - 29:55well,
-
29:55 - 29:58definitely an array over link list because that the allocation space.
-
29:58 - 30:01It's like, hey, you have to think about the whole picture.
-
30:01 - 30:05That is going to be the whole next lectures. Well, you
-
30:05 - 30:06know, it's about tradeoffs.
-
30:06 - 30:09It's not that one strategy's always going to be
-
30:09 - 30:12the clearly better one. If it is, then we don't need to think about
-
30:12 - 30:14anything else. There are times when
-
30:14 - 30:16you know
-
30:16 - 30:16
-
30:16 - 30:19that one is just great and there's no reason to think about anything else. And then
-
30:19 - 30:20there's other times when
-
30:20 - 30:24there are reasons to think about different ways to solve the same problem.
-
30:24 - 30:26So let me
-
30:26 - 30:27propose a case study
-
30:27 - 30:31that has some
-
30:31 - 30:34meat. You may think along the way, but you're going to really have to pretend that
-
30:34 - 30:38this is going to be relevant at first because it's going to seem like you've been
-
30:38 - 30:41transferred back to
-
30:41 - 30:441970, which was a very bad year, long before you born.
-
30:44 - 30:49I want you to think about the idea of a text setter. So Microsoft Word,
-
30:49 - 30:50or
-
30:50 - 30:53you know your email send window, or
-
30:53 - 30:57BB edit, or X code. All these things, right, have some backing of
-
30:57 - 31:00what usually is called a buffer,
-
31:00 - 31:02a buffer, sort of a funny word, right,
-
31:02 - 31:06but a buffer of characters behind it.
-
31:06 - 31:07Okay. And that buffer
-
31:07 - 31:11is used as the kind of document storage for all the characters
-
31:11 - 31:12
-
31:12 - 31:15that you're editing and moving around. As you kind of bop around and move around there's
-
31:15 - 31:19something often called the cursor where you type characters
-
31:19 - 31:21and characters get moved as you insert.
-
31:21 - 31:25You can select things, and delete them, and cut, copy, and paste, and all that sort of stuff.
-
31:25 - 31:28So what does that data structure look like? What is the kind of thing that wants to
-
31:28 - 31:29back
-
31:29 - 31:30a buffer?
-
31:30 - 31:33What kinds of things are important in that
-
31:33 - 31:35context to be able to support
-
31:35 - 31:40and what operations needs to be optimized for that tool to field [inaudible]?
-
31:40 - 31:44So what we're going to look at is a real simplification kind of taking that problem, kind of
-
31:44 - 31:48distilling it down to its essences and looking at just six operations that are kind
-
31:48 - 31:50of at the core of any text editor
-
31:50 - 31:54about moving the cursor forward and backwards with these commands.
-
31:54 - 31:57Jumping to the front and the back of the entire buffer and then inserting and
-
31:57 - 32:00deleting in relative to the cursor
-
32:00 - 32:01within that buffer.
-
32:01 - 32:04And we're going to do this with an extremely old school interface that's
-
32:04 - 32:08actually command base. It's like VI comes back from the dead for those of you who
-
32:08 - 32:11have ever heard of such things as VI and E Max.
-
32:11 - 32:13And so we're going to look at this because there's actually a lot of ways
-
32:13 - 32:15you can approach that,
-
32:15 - 32:18that take advantage of some of the things that we've already built like the vector, and stacking queue,
-
32:18 - 32:21and the link list. And sort of think about what
-
32:21 - 32:24kind of options play out well.
-
32:24 - 32:28What I'm going to show you first off is just what the tool looks like
-
32:28 - 32:31so you can really feel
-
32:31 - 32:33schooled in the old way of doing things.
-
32:33 - 32:34So I insert
-
32:34 - 32:38the characters A, B, C, D, E, F, G into the editor.
-
32:38 - 32:41And then I can use the command B to backup.
-
32:41 - 32:44I can use the command J to jump to the beginning, E to jump to the end,
-
32:44 - 32:46and so F and B,
-
32:46 - 32:50B moving me backwards, F moving me forwards, and then once I'm at a place, let's say I jump
-
32:50 - 32:53to the end, I can insert Z, Z,
-
32:53 - 32:58Y, X here at the beginning and it'll slide things over, and then I can delete characters
-
32:58 - 33:00shuffling things down.
-
33:00 - 33:04So that's what we've got. Imagine now, it's like building
-
33:04 - 33:07Microsoft Word on top of this. There's a lot of stuff that goes, you know, between here
-
33:07 - 33:11and there. but it does give you an idea that the kind of core data requirements
-
33:11 - 33:12every word processor
-
33:12 - 33:16needs some tool like this some abstraction underneath it to manage the
-
33:16 - 33:23character data. Okay. Where do we start? Where do
-
33:23 - 33:31we start?
-
33:31 - 33:33Anyone want to propose an implementation.
-
33:33 - 33:37What's the easiest thing to do? [Inaudible]. In a
-
33:37 - 33:40way. Something like that. You know, and if you think Array,
-
33:40 - 33:43then you should immediately think after it, no, I don't want to deal with Array, I want a vector.
-
33:43 - 33:44I'd like a vector.
-
33:44 - 33:45Vector please.
-
33:45 - 33:47Right. So I'm going to show you what the interface looks like, here, that we
-
33:47 - 33:50have a buffer in these six operations. We're going
-
33:50 - 33:52to think about what the private part looks like,
-
33:52 - 33:54and we say, what about vector.
-
33:54 - 33:57Vector handles big, you know,
-
33:57 - 34:00chunky things indexed
-
34:00 - 34:01by slots.
-
34:01 - 34:05That might be a good idea. So if I had the buffer contents A, B, C, D, E,
-
34:05 - 34:08right, and if I could slam those into a vector,
-
34:08 - 34:10and then I would need one other little bit of information here, which is
-
34:10 - 34:14where is the cursor in any given point because the cursor is actually where the
-
34:14 - 34:16uncertain lead operations take place relative to the cursor.
-
34:16 - 34:19The buffer's also going to manage that, knowing where the insertion point is
-
34:19 - 34:22and then deleting it and inserting relative to that.
-
34:22 - 34:23So I say, okay.
-
34:23 - 34:25I need some index.
-
34:25 - 34:29The cursor actually is between two character positions.
-
34:29 - 34:31
-
34:31 - 34:31
-
34:31 - 34:33This is like slot zero, one, and two.
-
34:33 - 34:37And the cursor is between, actually, one
-
34:37 - 34:41and two. And there's just a minor detail to kind of have worked out
-
34:41 - 34:46before we start trying to write this code, which is do we want the
-
34:46 - 34:49cursor to hold the index on the character that's to the left of it or to the
-
34:49 - 34:50right of it.
-
34:50 - 34:52It's totally symmetric, right.
-
34:52 - 34:55If I have these five characters, it could be that my cursor then goes from
-
34:55 - 34:56zero
-
34:56 - 34:58to four, it could be that it goes
-
34:58 - 35:01from zero to five, or it could be it goes from negative one to four, depending on
-
35:01 - 35:05which way I'm doing it. I'm going to happen to use the one that does zero
-
35:05 - 35:07to five
-
35:07 - 35:12where it's actually recorded as the character that's after it. Okay.
-
35:12 - 35:16So that's just kind of the staring point. I'm going to write some code and
-
35:16 - 35:20make it happen.
-
35:20 - 35:23So I'm going
-
35:23 - 35:25to remove
-
35:25 - 35:34this. Reference it, that's okay.
-
35:34 - 35:36And then I'm going to add the
-
35:36 - 35:37things I want to
-
35:37 - 35:39replace it with. So I put in the
-
35:39 - 35:45editor code and to put in the buffer code. Was buffer already in here? I think buffer's already here.
-
35:45 - 35:51Okay. Let's take a look. I get my buffer.
-
35:51 - 36:02So
-
36:02 - 36:08right now, let's take a look what's in buffered. I think I have the
-
36:08 - 36:11starting set information. So it has move cursor over, you know move the
-
36:11 - 36:14cursor around, it has the delete, and it has - let
-
36:14 - 36:18me make it have
-
36:18 - 36:20some variables that I want. I've got
-
36:20 - 36:23my cursor. I've got my vector of characters. Right now, it has
-
36:23 - 36:26a lot of copying, I think, just in anticipation of going places
-
36:26 - 36:29where copying is going to be required.
-
36:29 - 36:31Right now, because it's using vector and vector has deep copying behavior, I'm
-
36:31 - 36:37actually okay if I let windows copy and go through. But I'm actually going to
-
36:37 - 36:39not do that right away.
-
36:39 - 36:45All right. So then let's look at the implementation side of this and I have an
-
36:45 - 36:47implementation in here I want to get rid of. Sorry about this but I
-
36:47 - 36:54left the old one in here. That will do all the things that will need to
-
36:54 - 36:56get done.
-
36:56 - 36:58Okay. So let's deal with
-
36:58 - 37:06at the beginning. Starting off, right, we will set the cursor to zero. So that's
-
37:06 - 37:08the vector gets started,
-
37:08 - 37:11initialize empty, and nothing else I need to do with the vector.
-
37:11 - 37:16A character [inaudible] cursor position in that, and then moving the cursor position
-
37:16 - 37:17forward,
-
37:17 - 37:21it's mostly just doing this, right, cursor plus, plus, right. It's just
-
37:21 - 37:23an easy index to move it down. But
-
37:23 - 37:26I do need to make sure that the cursor isn't already at the end. So if
-
37:26 - 37:29the cursor is less than
-
37:29 - 37:36the size of the vector then I will let it advance. But it never gets beyond the
-
37:36 - 37:38
-
37:38 - 37:40size itself. So
-
37:40 - 37:43like all of these are going to have same problems. Like, if I'm already at the end and somebody asks me to advance, I don't
-
37:43 - 37:46want to suddenly get my cursor in some lax stated that
-
37:46 - 37:52sort of back that. Similarly, on this one, if the cursor
-
37:52 - 37:56is greater than zero, all right, then we can back it up and
-
37:56 - 37:58move the cursor around.
-
37:58 - 38:01Moving the cursor at the start is very easy.
-
38:01 - 38:03Moving the cursor to the end is, also,
-
38:03 - 38:05very easy, right. We have a
-
38:05 - 38:08convention about what it is.
-
38:08 - 38:11And so then inserting a character
-
38:11 - 38:15is, also, pretty easy because all the hard work is done
-
38:15 - 38:17by the vector.
-
38:17 - 38:18
-
38:18 - 38:20When I say insert this new character
-
38:20 - 38:23at the cursor position, right, then this character advance the
-
38:23 - 38:26cursor to be kind of past it, and then
-
38:26 - 38:31deleting the character, also, pretty easy. Let
-
38:31 - 38:34me show you, before I go finishing the cursor, I just want to show
-
38:34 - 38:38you this little diagram of what's happening while I'm doing stuff. So this is kind of a
-
38:38 - 38:41visualization of the things that are happening. So this is showing the vector and
-
38:41 - 38:45its length. And then the cursor position
-
38:45 - 38:48as we've done things. Inserted six characters, the cursor's currently sitting
-
38:48 - 38:52at the end, and for the length of the cursor, actually, the same value right now. If
-
38:52 - 38:56I issue a back command, right, that deducts the cursor by
-
38:56 - 38:58one, it shows another one backs up by one,
-
38:58 - 39:01and then eventually the cursor gets to the position zero and subsequent backs don't
-
39:01 - 39:04do anything to it, it just kind of bounces off the edge. And
-
39:04 - 39:08moving forward, things are easier to deal with. It will advance until the gets to the length,
-
39:08 - 39:10the size of that text, and it won't go any further.
-
39:10 - 39:14And that jumping to the front in the end are just a matter of updating that
-
39:14 - 39:17cursor position from zero to the size and whatnot.
-
39:17 - 39:19The operation where
-
39:19 - 39:21things get a little
-
39:21 - 39:22more
-
39:22 - 39:25bogged down is on this insert
-
39:25 - 39:30where I need to insert a position. If I insert the X, Y, Z
-
39:30 - 39:32into the middle there and you can see it kind of
-
39:32 - 39:37chopping those characters down, making that space to insert those things in the
-
39:37 - 39:37middle.
-
39:37 - 39:41Similarly, doing delete operations, if I jump
-
39:41 - 39:43to the
-
39:43 - 39:45beginning I start doing deletes here.
-
39:45 - 39:48It has to copy all those characters over and
-
39:48 - 39:53deduct that length, right, so that the vectors do that work for us on remove that.
-
39:53 - 39:55That means that if the vector's very large, which is
-
39:55 - 39:58not a typical in a word processor situation, you could have you PhD theses
-
39:58 - 40:00which has hundreds of pages,
-
40:00 - 40:03if you go back to the beginning and you start deleting characters you'd hate to think it was just
-
40:03 - 40:05taking this massive shuffle time
-
40:05 - 40:09to get the work done. So
-
40:09 - 40:13let's see my - I'm going
-
40:13 - 40:14to
-
40:14 - 40:24bring in the display that
-
40:24 - 40:38-
-
40:38 - 40:40whoops,
-
40:40 - 40:42I don't like something here. [Inaudible]. Now, what do we have? Oh, look at this. Well, well, we will continue on.
-
40:42 - 41:00This inside - okay. Hello. [Inaudible]. I have no idea. I'm not going to try to [inaudible].
-
41:00 - 41:02Okay.
-
41:02 - 41:08It's inside.
-
41:08 - 41:21That's got me totally upset. Okay. We still have our old code somewhere. Okay. Why do I still have the wrong - what is - okay. Oh,
-
41:21 - 41:25well. Today's not my lucky day. I'm not going to worry about that too much. I'm just going to show [inaudible]. Okay.
-
41:25 - 41:27So
-
41:27 - 41:29seeing what's actually happening, right, it's like just mostly
-
41:29 - 41:31
-
41:31 - 41:34kind of moving that stuff back and forth, and then having the vector do the big
-
41:34 - 41:37work, right, of inserting and deleting those characters, and doing all the copying
-
41:37 - 41:40to get the thing done.
-
41:40 - 41:43We'll come back over here
-
41:43 - 41:47and kind of see what good it does and what things it's not so hot
-
41:47 - 41:48at, right,
-
41:48 - 41:51is that it is easy to move the cursor wherever you want.
-
41:51 - 41:54You know, that moving it a long distance or a short distance, moving it is a little
-
41:54 - 41:55bit
-
41:55 - 41:56
-
41:56 - 41:59or to the beginning to the end, equally easy as by just resetting
-
41:59 - 42:01some variable.
-
42:01 - 42:05It's the enter and delete, right where this one actually really suffers, right,
-
42:05 - 42:08based on how many characters, right, follow that cursor,
-
42:08 - 42:11right you could potentially be moving the entire contents of the buffer.
-
42:11 - 42:14Adding at the end is actually going to be relatively fast. So if you have
-
42:14 - 42:17to type in order, like you just type you theses out
-
42:17 - 42:19and never go back to edit anything,
-
42:19 - 42:22then it would be fine, adding those characters at the end. But at any
-
42:22 - 42:25point, if you move the cursor back into the mid of the body, somewhere in
-
42:25 - 42:28the front, somewhere in the middle, right, a lot of characters get shuffled as you
-
42:28 - 42:30change, makes edits in the middle there.
-
42:30 - 42:35And so what this seems that it actually has good movement but bad editing
-
42:35 - 42:38as a buffer strategy.
-
42:38 - 42:39That's
-
42:39 - 42:40probably,
-
42:40 - 42:43you know, given that we have these six operations we'll all interested in,
-
42:43 - 42:46this is probably not the mix that seems to make the most sense for something
-
42:46 - 42:49that's called an editor, right. It is the editing operations are the ones that is
-
42:49 - 42:52weakest on, it has its most
-
42:52 - 42:53
-
42:53 - 42:54debilitating performance,
-
42:54 - 42:58it wouldn't make that good of an editor, right, if that was going to be your behavior. It
-
42:58 - 43:02has one advantage that we're going see, actually, we're going to have to kind of
-
43:02 - 43:06make compromises on it, which it actually uses very little extra space, though, but
-
43:06 - 43:08it's using the vector,
-
43:08 - 43:12which potentially might have excess capacity up to twice that. So maybe it's
-
43:12 - 43:14about two bites per char in the very worse case.
-
43:14 - 43:18But it actually has no per character overhead that's already imbedded
-
43:18 - 43:23in the data structure from this side.
-
43:23 - 43:31Now, I'm just going to go totally somewhere else. Okay.
-
43:31 - 43:34So instead of
-
43:34 - 43:37thinking of it as vector, thinking of it as continuous block,
-
43:37 - 43:41is to kind of realize the editing operations, right,
-
43:41 - 43:44that comes back to the idea, like if I were working at the very end of my document that I
-
43:44 - 43:47can edit there efficiently.
-
43:47 - 43:48
-
43:48 - 43:51It kind of inspires me to think of, how do I think I can make it so
-
43:51 - 43:55the insertion point is somehow in the efficient place. Like the
-
43:55 - 43:58edits that are happening on the insertion point, can I somehow make it to where
-
43:58 - 44:01access to the insertion point is easy?
-
44:01 - 44:04That rather than bearing that in the middle of my vector, if I can expose that
-
44:04 - 44:08to make it accessible easily in the way the code manipulates the internal of the
-
44:08 - 44:09buffer.
-
44:09 - 44:14And so the idea here is to break up the text into two pieces.
-
44:14 - 44:17Things that are to the left of the cursor, things that are to the right, and I'm calling this
-
44:17 - 44:19the before and the after.
-
44:19 - 44:20And then
-
44:20 - 44:24organize those so they're actually averted from each other to where all the
-
44:24 - 44:27characters that lead up to the cursor
-
44:27 - 44:31are set up to where B is very close, assessable at the top of, in this
-
44:31 - 44:32case, a stack,
-
44:32 - 44:36and that the things that are farther away are buried further down in the stack in that
-
44:36 - 44:37inaccessible region.
-
44:37 - 44:41And similarly over here, but inverted, that C is the top of this stack and D
-
44:41 - 44:44and E, and things are further down, they are buried
-
44:44 - 44:46away from me,
-
44:46 - 44:50figuring the things I really need access to are right next to the cursor
-
44:50 - 44:55that I'm willing to kind of move those other things father away to gain that access.
-
44:55 - 45:00And so what this buffer does is it uses two stacks, a
-
45:00 - 45:01before stack,
-
45:01 - 45:03an after stack,
-
45:03 - 45:07and that the operations for moving the data around
-
45:07 - 45:09become
-
45:09 - 45:10transferring things
-
45:10 - 45:13from the before to the after stack.
-
45:13 - 45:16Where's the cursor?
-
45:16 - 45:19How does the cursor represent it? Do I need some more data here?
-
45:19 - 45:25Some integer some ?
-
45:25 - 45:28It's really kind of odd to think about but there is no explicit cursor, right,
-
45:28 - 45:31being stored here but the cursor is, in this case, right, like
-
45:31 - 45:34modeled by what's on the before stack or all the things to the left of the cursor.
-
45:34 - 45:38What's on the after stack is following the cursor. So in
-
45:38 - 45:39fact,
-
45:39 - 45:42the cursor is represented as the empty space between these two
-
45:42 - 45:45where you have,
-
45:45 - 45:48you know, how many ever characters wrong before is actually the index of where
-
45:48 - 45:51the cursor is. So kind of a
-
45:51 - 45:54wacky way of thinking about it, but one that actually have some pretty neat properties
-
45:54 - 45:57in terms of making it run efficiently.
-
45:57 - 46:01So let me show you
-
46:01 - 46:02the
-
46:02 - 46:03
-
46:03 - 46:05diagram of it happening.
-
46:05 - 46:09So insert A, B, C, D, E, F, G.
-
46:09 - 46:12And so, the operation of inserting
-
46:12 - 46:15a new character into this form of the buffer
-
46:15 - 46:19is pushing something on the before stack.
-
46:19 - 46:23So if I want to move the cursor, let's say I want to move it back one,
-
46:23 - 46:25then I pop
-
46:25 - 46:27the top off of the before push it on the after.
-
46:27 - 46:32I keep doing that and it transfers the G to the H, you know, the E and so on, as I
-
46:32 - 46:33back up.
-
46:33 - 46:37Moving forward does that same operation in the inverse. If I want to move forward I take
-
46:37 - 46:40something off the top of the after and push it on before. So it's kind of shuffling it
-
46:40 - 46:42from one side to the other.
-
46:42 - 46:46Given that these push and pop operations are constant on both implementations of
-
46:46 - 46:47the stack we saw,
-
46:47 - 46:52then that means that our cursor movement is also of one so I can do
-
46:52 - 46:55this. And if I do deletes it's actually just popping from the after stack and
-
46:55 - 46:57throwing it away.
-
46:57 - 47:00So also easy to do edits
-
47:00 - 47:04because I'm talking about adding things to the before and deleting things from after,
-
47:04 - 47:06both of which can be done very efficiently.
-
47:06 - 47:07The one operation
-
47:07 - 47:10that this guy has trouble with
-
47:10 - 47:14is big cursor movement.
-
47:14 - 47:17If I want to go all the way to the beginning
-
47:17 - 47:19or all the way to the end,
-
47:19 - 47:22then everything's got to go. No
-
47:22 - 47:23matter
-
47:23 - 47:28how many things I have to empty out the entire after stack to position the
-
47:28 - 47:29cursor at the end,
-
47:29 - 47:31or empty out the entire before stack
-
47:31 - 47:35to get it all the way over here.
-
47:35 - 47:38So I could of sort of talk you though this code, and actually, I won't type it
-
47:38 - 47:41just because I actually want to talk about its analysis more than I want to see its code. Each of
-
47:41 - 47:43these actually becomes a one liner.
-
47:43 - 47:46Insert is push on the before stack.
-
47:46 - 47:49Delete is pop from the after stack. The cursor movement is popping
-
47:49 - 47:53from one and pushing on the other depending on the direction and then that same code
-
47:53 - 47:56just for the Y loop, like wild or something on the one stack, just keep
-
47:56 - 47:59pushing and popping from one empty to the other.
-
47:59 - 48:02So very little code to write, right,
-
48:02 - 48:05depending a lot on the stacks abstractions coming through for us
-
48:05 - 48:09and then making this ultra fit that we've managed to get editing suddenly,
-
48:09 - 48:10like, a lot more efficient
-
48:10 - 48:15but the cost of sacrificing one of our other operations. Let's take a look at what that
-
48:15 - 48:19look like, right.
-
48:19 - 48:22Suddenly I can do all this insert and delete
-
48:22 - 48:23at the insertion point
-
48:23 - 48:24
-
48:24 - 48:25with very little trouble,
-
48:25 - 48:29and I suddenly made this other operation, oddly enough,
-
48:29 - 48:30slow.
-
48:30 - 48:33All a sudden it's like if you go back to the beginning of your document you're in the
-
48:33 - 48:36middle of editing, you're at the bottom. You say, oh, I want to go back to the beginning
-
48:36 - 48:39and you can imagine how that would feel if you were typing
-
48:39 - 48:42it would actually be the act of going up and clicking up in the top right by where you made
-
48:42 - 48:44the insertion and all a sudden you'd see the white cursor
-
48:44 - 48:45and you'd be like,
-
48:45 - 48:49why is that taking so long. How could that possibly be, you know,
-
48:49 - 48:51that it's doing this kind of rearrangement, but yet it made
-
48:51 - 48:54editing even on a million character document fast. But
-
48:54 - 48:55that movement
-
48:55 - 48:58long distances, you know, jumping a couple of pages or
-
48:58 - 48:59front to back,
-
48:59 - 49:05suddenly, having to do this big transfer behind the scenes, so
-
49:05 - 49:08different, right. So now I had six operations, I had four fast,
-
49:08 - 49:09two slow,
-
49:09 - 49:12now I have four fast, two slow.
-
49:12 - 49:16It still might be that, actually, this is an interesting improvement, though, because
-
49:16 - 49:19we have decided those are operations that we're willing to tolerate,
-
49:19 - 49:23being slower, especially, if it means some operation that we're more interested in, if
-
49:23 - 49:24performance being faster.
-
49:24 - 49:28And that likely seems like it's moving in the right direction because editing, right, being
-
49:28 - 49:31the whole purpose, right, behind what we're trying to do is
-
49:31 - 49:32a text setter,
-
49:32 - 49:34that seems like that might be a good call.
-
49:34 - 49:38What I'm going to start looking at and it's going to be something I want to talk about
-
49:38 - 49:39next time,
-
49:39 - 49:42is what can a link list do for us?
-
49:42 - 49:46Both of those are fighting against that continuous thing, the copying and the
-
49:46 - 49:48shuffling, and the inserting
-
49:48 - 49:51is there something about that flexibility of the rewiring
-
49:51 - 49:53that can kind of get us out of this
-
49:53 - 49:55some operations having to be slow
-
49:55 - 50:00because other operations are fast. Question. [Inaudible]. Yeah.
-
50:00 - 50:03Why is space used for stacks when
-
50:03 - 50:04those are half? Yeah.
-
50:04 - 50:08So in this case, right, depending on how you're
-
50:08 - 50:09modeling your stack, if it is with
-
50:09 - 50:12vectors, right, then you're likely to have the before and the after stack, both
-
50:12 - 50:16have capacity for everything, even when they're not used, right. And so it's very
-
50:16 - 50:17likely that either right
-
50:17 - 50:20give 100 characters they're either on one stack or the other, but the other one might be kind of
-
50:20 - 50:23harboring the 100 spots for them when they come back.
-
50:23 - 50:27Or it could just be that you have the link list, which are allocating and de allocating but
-
50:27 - 50:30has the overhead of that. So it's likely that no matter which implementation the stack
-
50:30 - 50:33you have, you probably have about twice the storage that you need because of the
-
50:33 - 50:38two sides and the overhead that's kind of coming and going there.
-
50:38 - 50:41So we will see the link list and we'll talk that guy through on
-
50:41 - 50:46Friday. I'll see you then.
- Title:
- Lecture 20 | Programming Abstractions (Stanford)
- Description:
-
Lecture 20 by Julie Zelenski for the Programming Abstractions Course (CS106B) in the Stanford Computer Science Department.
Julie continues discussing Vector and moves on to stack and queue, covering chapter ten in the course textbook. She goes over several rules for templates again to reinforce how important they are.
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:00
N. Ueda edited English subtitles for Lecture 20 | Programming Abstractions (Stanford) | ||
Eunjeong_Kim added a translation |