WEBVTT

00:00:00.000 --> 00:00:01.992
[SQUEAKING]

00:00:01.992 --> 00:00:03.984
[RUSTLING]

00:00:03.984 --> 00:00:07.470
[CLICKING]

00:00:13.250 --> 00:00:15.480
ERIK DEMAINE: All right,
let's get started.

00:00:15.480 --> 00:00:16.730
Welcome back to 006.

00:00:16.730 --> 00:00:19.070
Today we are doing some of
the coolest data structures

00:00:19.070 --> 00:00:21.650
we will see in this class--
maybe some of the coolest data

00:00:21.650 --> 00:00:22.880
structures ever.

00:00:22.880 --> 00:00:24.920
Binary trees.

00:00:24.920 --> 00:00:29.310
You've certainly seen trees
in many forms in the past,

00:00:29.310 --> 00:00:31.130
including in this
class, we've talked--

00:00:31.130 --> 00:00:34.200
used trees as a
lower-bound tool for--

00:00:34.200 --> 00:00:36.410
in the decision tree model.

00:00:36.410 --> 00:00:38.640
But this lecture
and the next lecture

00:00:38.640 --> 00:00:41.480
we're going to build
one data structure that

00:00:41.480 --> 00:00:44.510
is almost superior to
all data structures

00:00:44.510 --> 00:00:49.640
we have seen and can do
almost anything really fast.

00:00:49.640 --> 00:00:52.010
First, recall all
the data structures

00:00:52.010 --> 00:00:54.910
we've seen so far. arrays,
linked lists, dynamic arrays,

00:00:54.910 --> 00:00:57.410
sorted arrays, hash tables.

00:00:57.410 --> 00:01:01.430
And the two sets of operations
we're interested in supporting,

00:01:01.430 --> 00:01:03.560
the two interfaces,
one was sequences

00:01:03.560 --> 00:01:05.810
where we're maintaining
items in a specified order.

00:01:05.810 --> 00:01:08.687
We want to be able to insert an
item right after another item

00:01:08.687 --> 00:01:10.520
or delete an item in
the middle of the list,

00:01:10.520 --> 00:01:13.130
and always be able to
access the i-th item.

00:01:13.130 --> 00:01:16.230
We haven't seen any good data
structures for that problem.

00:01:16.230 --> 00:01:18.890
We're really good at
inserting and deleting

00:01:18.890 --> 00:01:21.110
at the beginning or the
end of the sequence,

00:01:21.110 --> 00:01:23.030
but we haven't seen
anything that's

00:01:23.030 --> 00:01:26.067
efficient at inserting
in the middle of the list

00:01:26.067 --> 00:01:27.650
or deleting in the
middle of the list.

00:01:27.650 --> 00:01:29.990
Linked lists, you can't
even get to the middle

00:01:29.990 --> 00:01:31.880
in less than linear time.

00:01:31.880 --> 00:01:33.338
Array, you can
get to the middle,

00:01:33.338 --> 00:01:34.880
but if you make any
changes, you have

00:01:34.880 --> 00:01:37.170
to do the shift, which
is very expensive.

00:01:37.170 --> 00:01:41.060
So today-- or sorry, next
lecture, for the first time

00:01:41.060 --> 00:01:46.502
we will see all of those
operations efficient.

00:01:46.502 --> 00:01:53.210
I mentioned our goal where
efficient means logarithmic.

00:01:53.210 --> 00:01:56.810
So we're not quite as
good as linked lists

00:01:56.810 --> 00:02:00.050
and dynamic arrays at inserting
and deleting at the end.

00:02:00.050 --> 00:02:02.450
Those-- there that we
achieve constant or constant

00:02:02.450 --> 00:02:03.800
amortized time.

00:02:03.800 --> 00:02:05.960
But up to this log
factor, we're going

00:02:05.960 --> 00:02:07.490
to get the best of
all worlds where

00:02:07.490 --> 00:02:11.618
we can solve all the things, all
the operations that don't build

00:02:11.618 --> 00:02:14.160
or iterate through the entire
structure, and that, of course,

00:02:14.160 --> 00:02:15.378
takes linear time.

00:02:15.378 --> 00:02:17.420
But we can do all the
others in logarithmic time.

00:02:17.420 --> 00:02:20.990
For sets, sets we're
maintaining a bunch

00:02:20.990 --> 00:02:24.050
of items which
have intrinsic keys

00:02:24.050 --> 00:02:26.720
and we want to search by key.

00:02:26.720 --> 00:02:29.120
So hash tables are
great if you're only

00:02:29.120 --> 00:02:30.740
doing exact searches.

00:02:30.740 --> 00:02:33.910
If you want to find a key and
get yes or no, is it in there?

00:02:33.910 --> 00:02:36.290
If it's in there,
give me the item.

00:02:36.290 --> 00:02:38.900
That's what Python
dictionaries do.

00:02:38.900 --> 00:02:41.420
And they're great at
inserting and deleting,

00:02:41.420 --> 00:02:45.800
but they're really bad at
find previous and find next.

00:02:45.800 --> 00:02:47.810
This is the unsuccessful case.

00:02:47.810 --> 00:02:50.870
So if I search for a key and
it's not in my structure,

00:02:50.870 --> 00:02:53.330
I would like to know more
than just the answer no.

00:02:53.330 --> 00:02:56.990
I'd like to know what the
previous and next items that

00:02:56.990 --> 00:02:58.680
are actually in the structure.

00:02:58.680 --> 00:03:01.670
So what are my nearest
matches when I search by key?

00:03:01.670 --> 00:03:05.360
That's a natural query, and
the only data structure we have

00:03:05.360 --> 00:03:07.490
that's good at it
is a sorted array,

00:03:07.490 --> 00:03:09.860
because binary search
gives this to us.

00:03:09.860 --> 00:03:13.140
If we search for a key bi binary
search and we don't find it,

00:03:13.140 --> 00:03:14.930
the position that
we end up at is

00:03:14.930 --> 00:03:17.692
right between the
previous and next one.

00:03:17.692 --> 00:03:19.400
But of course, sorted
arrays are terrible

00:03:19.400 --> 00:03:21.630
for dynamic operations.

00:03:21.630 --> 00:03:23.840
We don't know how to maintain--

00:03:23.840 --> 00:03:26.770
we can't maintain a sorted
array without any gaps

00:03:26.770 --> 00:03:28.520
when we're doing
insertions and deletions.

00:03:28.520 --> 00:03:31.100
In some sense, today
and next class,

00:03:31.100 --> 00:03:35.060
binary trees let us represent
a sorted order or a general

00:03:35.060 --> 00:03:38.930
and order of items
dynamically and still allow

00:03:38.930 --> 00:03:41.975
us to do very fast
things like get_at of i

00:03:41.975 --> 00:03:44.030
and find previous of the key.

00:03:44.030 --> 00:03:45.510
So that's our goal.

00:03:45.510 --> 00:03:47.780
We're not going to quite
get to this goal today.

00:03:47.780 --> 00:03:52.400
We're going to get an
incomparable thing called

00:03:52.400 --> 00:03:55.070
the height of the tree,
and then on Thursday we'll

00:03:55.070 --> 00:03:56.840
be able to finish and
achieve this goal.

00:03:56.840 --> 00:03:59.810
Today is just in
service to that goal.

00:04:02.370 --> 00:04:05.750
So what is a binary tree?

00:04:05.750 --> 00:04:12.470
Let me draw an example and
then define it more precisely.

00:04:12.470 --> 00:04:15.650
Mathematicians will call
this a rooted binary tree,

00:04:15.650 --> 00:04:19.880
in case you've seen
that in 042, say.

00:04:19.880 --> 00:04:21.080
Here is a picture.

00:04:36.480 --> 00:04:39.128
So this is an example
of a binary tree.

00:04:39.128 --> 00:04:41.420
It has a bunch of nodes which
we're drawing in circles.

00:04:41.420 --> 00:04:43.580
It has items in the
nodes which we're--

00:04:43.580 --> 00:04:45.720
I'm writing as letters here.

00:04:45.720 --> 00:04:48.170
So this is item
A, item B, item C.

00:04:48.170 --> 00:04:50.200
And it has these
links between them.

00:04:50.200 --> 00:04:52.550
This is like linked lists.

00:04:52.550 --> 00:04:57.590
But in general,
a node X is going

00:04:57.590 --> 00:05:05.720
to have a parent pointer,
a left child, left pointer,

00:05:05.720 --> 00:05:09.170
and a right child,
right pointer.

00:05:09.170 --> 00:05:14.220
And it also has an
item inside of it.

00:05:14.220 --> 00:05:17.090
So I'm going to talk about
node.left is a pointer

00:05:17.090 --> 00:05:19.400
to the left--

00:05:19.400 --> 00:05:20.930
the node down here.

00:05:20.930 --> 00:05:25.400
Node.right, node.parent,
node.item gives me--

00:05:25.400 --> 00:05:29.570
so if I look at the
node A, its item

00:05:29.570 --> 00:05:37.910
is A. So let me draw
for you some examples.

00:05:53.706 --> 00:05:58.290
OK, the parent of A is nothing,
so we call A the root 0.

00:05:58.290 --> 00:06:01.550
There's going to be a unique
node that has no parent.

00:06:01.550 --> 00:06:05.580
It's sad to have no
parents, but here you go.

00:06:05.580 --> 00:06:07.740
Then we have node B
which-- whose parent

00:06:07.740 --> 00:06:11.520
is A. Node C whose parent--
its parent is A; node D,

00:06:11.520 --> 00:06:15.540
its parent is B; node E,
its parent is B; and node F,

00:06:15.540 --> 00:06:19.590
its parent is D. The
alphabetical order here happens

00:06:19.590 --> 00:06:23.130
to be ordered by parent.

00:06:23.130 --> 00:06:25.810
Then we have left pointer, so
I'll just do a few of them.

00:06:25.810 --> 00:06:30.690
So the left pointer of A is
B. The right pointer of A--

00:06:30.690 --> 00:06:32.757
sorry, B the node--

00:06:32.757 --> 00:06:33.840
these should all be nodes.

00:06:37.020 --> 00:06:39.210
I'm circling for nodes,
I'm just reading the letter

00:06:39.210 --> 00:06:41.070
for the item to make
it clear that those

00:06:41.070 --> 00:06:42.630
are different things.

00:06:42.630 --> 00:06:46.390
The right pointer for A
is C; left pointer for B

00:06:46.390 --> 00:06:51.460
is D; right pointer
for B is E; and so on.

00:06:51.460 --> 00:06:53.130
So in other words,
each of these lines

00:06:53.130 --> 00:06:55.470
is a bidirectional pointer.

00:06:55.470 --> 00:06:57.360
In this direction, it's
the parent direction;

00:06:57.360 --> 00:06:59.952
in this direction,
it's left in this case.

00:06:59.952 --> 00:07:02.160
Because it's bidirectional,
we don't draw the arrows,

00:07:02.160 --> 00:07:07.860
we just draw undirected lines.

00:07:07.860 --> 00:07:11.340
This is, in general, what
a binary tree looks like.

00:07:11.340 --> 00:07:15.060
A key invariant is
that if you take a node

00:07:15.060 --> 00:07:17.460
and say go to its left pointer--

00:07:17.460 --> 00:07:22.530
left child and then go
to that node's parent,

00:07:22.530 --> 00:07:25.450
this should be the same as node.

00:07:25.450 --> 00:07:27.480
So that's just
saying these are--

00:07:27.480 --> 00:07:30.630
parent is always the inverse
of a left or right operation.

00:07:30.630 --> 00:07:31.980
This is also true for right.

00:07:34.680 --> 00:07:36.090
OK, and that's a binary tree.

00:07:36.090 --> 00:07:38.580
Now, the intuition of
what's going on here

00:07:38.580 --> 00:07:43.830
is, you could say we're
inspired by a linked list.

00:07:43.830 --> 00:07:47.490
Linked lists had a
very similar structure.

00:07:47.490 --> 00:07:51.990
Maybe an item-- or there's a
node, it had an item in it,

00:07:51.990 --> 00:07:56.742
and it had a next pointer and
it had a previous pointer.

00:07:56.742 --> 00:07:58.950
So in some sense, what
we're-- if it's doubly linked,

00:07:58.950 --> 00:08:00.033
we had a previous pointer.

00:08:00.033 --> 00:08:02.620
If it was singly linked,
we only had a next pointer.

00:08:02.620 --> 00:08:06.150
And if you think about the
limits of linked lists,

00:08:06.150 --> 00:08:08.400
especially singly-linked
lists, if you just

00:08:08.400 --> 00:08:12.210
have one pointer per node,
you can only build the list.

00:08:12.210 --> 00:08:22.500
And so the result is this node
is going to have depth linear.

00:08:22.500 --> 00:08:24.240
Depth means how
many pointers do I

00:08:24.240 --> 00:08:27.540
have to follow to get here
from the root of the structure?

00:08:27.540 --> 00:08:29.040
Which for linked
lists was the head.

00:08:29.040 --> 00:08:32.190
If it was doubly linked, OK,
I can have a head and a tail

00:08:32.190 --> 00:08:34.440
and I can put
bidirections on here.

00:08:34.440 --> 00:08:36.929
But then still, the middle
item has depth linear.

00:08:36.929 --> 00:08:39.870
So there's no way to get
there unless in linear time.

00:08:39.870 --> 00:08:43.950
With binary trees, because we
use two types of next pointers,

00:08:43.950 --> 00:08:46.720
left and right, we
can build a tree.

00:08:46.720 --> 00:08:49.140
And we know trees in
general have logarithmic--

00:08:49.140 --> 00:08:52.170
can have logarithmic height.

00:08:52.170 --> 00:08:56.130
And so it's possible in
a tree to get to any node

00:08:56.130 --> 00:08:58.980
starting from the root
and only log n traversals.

00:08:58.980 --> 00:09:01.080
So that's the intuition
on what's going on.

00:09:01.080 --> 00:09:08.260
Now today, we're going to talk
about the height of a tree.

00:09:08.260 --> 00:09:14.460
So let me define a couple
of definitions here.

00:09:18.570 --> 00:09:24.560
Subtree height of a node.

00:09:27.090 --> 00:09:30.630
So a tree decomposes
into subtrees.

00:09:30.630 --> 00:09:35.070
So for example, the subtree
rooted at B or the subtree of B

00:09:35.070 --> 00:09:40.510
is this portion of the tree.

00:09:40.510 --> 00:09:44.140
So it's that node and all of
the descendants of this node.

00:09:44.140 --> 00:09:46.280
So because we have
parents and children,

00:09:46.280 --> 00:09:49.750
we can generalize in
the familial tree sense.

00:09:49.750 --> 00:09:52.040
We can talk about
ancestors of a node.

00:09:52.040 --> 00:09:55.670
So the ancestors of F are
its parent, its grandparent,

00:09:55.670 --> 00:09:57.370
great-grandparents and so on.

00:09:57.370 --> 00:10:01.270
Together, all of these
are called ancestors.

00:10:01.270 --> 00:10:04.090
It doesn't quite correspond
to familial trees

00:10:04.090 --> 00:10:06.700
because familial trees
you have two parents.

00:10:06.700 --> 00:10:10.090
Here, you only have
a unique parent.

00:10:10.090 --> 00:10:13.210
Or the poor root has no parent.

00:10:13.210 --> 00:10:15.115
We also talk about--

00:10:15.115 --> 00:10:19.660
it's like mixed metaphors--
leaves of the tree.

00:10:19.660 --> 00:10:26.350
These are people
with no children.

00:10:26.350 --> 00:10:30.557
Parents will complain
about this, but many--

00:10:30.557 --> 00:10:32.890
like many of us in this room,
they have no children yet,

00:10:32.890 --> 00:10:34.480
so we are called leaves.

00:10:34.480 --> 00:10:37.240
You can tell your parent, hey,
I'm just the leaf, you know?

00:10:37.240 --> 00:10:39.590
Blowing in the wind.

00:10:39.590 --> 00:10:43.210
So this-- ah, it's so
many mixed metaphors,

00:10:43.210 --> 00:10:46.300
but we always draw
trees downwards

00:10:46.300 --> 00:10:48.760
like the root
structure of a tree.

00:10:48.760 --> 00:10:50.950
Yet we call the
ends of the roots

00:10:50.950 --> 00:10:52.720
leaves, which is upside-down.

00:10:52.720 --> 00:10:55.540
Anyway, that's trees for you.

00:10:55.540 --> 00:10:57.220
Lots of entertaining analogies.

00:10:57.220 --> 00:10:58.690
OK, but ancestors are useful.

00:10:58.690 --> 00:11:00.200
Descendants are also useful.

00:11:00.200 --> 00:11:03.010
So the descendants of B are
all of its children and all

00:11:03.010 --> 00:11:04.510
of its grandchildren
and all the way

00:11:04.510 --> 00:11:07.190
down, but just
within the subtree.

00:11:07.190 --> 00:11:12.490
So the subtree of X consists
of X and its descendants.

00:11:16.900 --> 00:11:21.830
And we think of X being
the root of that subtree.

00:11:21.830 --> 00:11:23.740
So we're kind of
forgetting about everything

00:11:23.740 --> 00:11:28.120
outside of the subtree when we
talk about the subtree of X.

00:11:28.120 --> 00:11:30.430
Let's talk about
the depth of a node.

00:11:33.370 --> 00:11:34.495
Depth of a node is--

00:11:37.000 --> 00:11:41.950
I guess the number
of its ancestors.

00:11:41.950 --> 00:11:46.360
That's right.

00:11:46.360 --> 00:11:49.900
I usually think of
it as the number

00:11:49.900 --> 00:11:59.950
of edges in the path
from X up to the root.

00:12:02.560 --> 00:12:06.220
So every node has a unique
path that goes upwards

00:12:06.220 --> 00:12:08.270
until it can't go up anymore.

00:12:08.270 --> 00:12:12.880
So the depth of E is 2
because there are two edges--

00:12:12.880 --> 00:12:16.510
1, 2-- in the path
from the root A to E.

00:12:16.510 --> 00:12:20.410
So maybe I'll read some
depths, depth of these is 2.

00:12:20.410 --> 00:12:24.460
Depth of these guys is 1,
depth of the root is 0.

00:12:24.460 --> 00:12:26.600
2, 3.

00:12:26.600 --> 00:12:31.160
So those are depth.

00:12:31.160 --> 00:12:38.940
I'm going to clean
this up a little bit

00:12:38.940 --> 00:12:40.740
so we can focus on the image.

00:12:40.740 --> 00:12:41.240
All right.

00:12:41.240 --> 00:12:43.920
Height-- so depth is
measuring downwards

00:12:43.920 --> 00:12:46.710
because if you imagine
depth within water,

00:12:46.710 --> 00:12:49.570
this is the surface
of the water,

00:12:49.570 --> 00:12:52.260
and then we measure how deep
you are from the surface.

00:12:52.260 --> 00:12:54.180
Height is in the
reverse direction.

00:12:54.180 --> 00:12:56.040
We're going to measure
from the leaf level

00:12:56.040 --> 00:12:58.890
up, because leaves are
the bottom of the tree.

00:12:58.890 --> 00:13:07.170
So height of a node is going
to be the number of edges

00:13:07.170 --> 00:13:20.210
and the longest
downward path, which

00:13:20.210 --> 00:13:27.045
is the same thing as the maximum
depth of a node in X's subtree.

00:13:32.900 --> 00:13:37.100
Let's do height in red.

00:13:37.100 --> 00:13:39.890
So, how long is the longest
path from F to a leaf?

00:13:39.890 --> 00:13:44.270
Well, F is leaf, so all
leaves have depth 0.

00:13:44.270 --> 00:13:45.920
Sorry, height 0.

00:13:45.920 --> 00:13:49.310
Don't get it backwards.

00:13:49.310 --> 00:13:53.360
D here, it's-- so there
are two ways to go down.

00:13:53.360 --> 00:13:55.430
This doesn't go to a leaf.

00:13:55.430 --> 00:13:58.370
This one goes to leaf
and its height is 0.

00:13:58.370 --> 00:13:59.960
So this height is 1.

00:13:59.960 --> 00:14:02.600
There's one edge to a leaf here.

00:14:02.600 --> 00:14:04.910
B has two leaves it can get to.

00:14:04.910 --> 00:14:08.480
We take the longest
one, so that's length 2.

00:14:08.480 --> 00:14:11.090
A similarly has height 3.

00:14:16.170 --> 00:14:16.670
OK.

00:14:16.670 --> 00:14:21.680
So height we measure upward,
depth we measure downward.

00:14:21.680 --> 00:14:24.350
One thing we care about
is just the height

00:14:24.350 --> 00:14:29.750
of the overall tree, which
is the height of the root.

00:14:32.810 --> 00:14:35.090
And I call that h because
we're going to use it a lot.

00:14:39.530 --> 00:14:42.500
And what we're going to achieve
today is all of these running

00:14:42.500 --> 00:14:46.130
times, instead of being log n,
they're going to be order h.

00:14:49.070 --> 00:14:53.150
Today, our goal is to get all
the operations we care about

00:14:53.150 --> 00:14:54.430
in order h time.

00:14:57.110 --> 00:14:58.850
And then next
lecture we're going

00:14:58.850 --> 00:15:01.700
to guarantee that
as always log n

00:15:01.700 --> 00:15:03.607
and then we'll get log n time.

00:15:03.607 --> 00:15:05.690
So we need to do a bunch
of work to achieve log n.

00:15:05.690 --> 00:15:08.570
Today we'll do the work that's
all the tree manipulation.

00:15:08.570 --> 00:15:11.090
And as long as your tree
is nice and shallow,

00:15:11.090 --> 00:15:14.150
it doesn't have high height,
because logarithmic height,

00:15:14.150 --> 00:15:15.500
everything will be log n.

00:15:15.500 --> 00:15:18.470
Of course, there are
trees that are really bad.

00:15:18.470 --> 00:15:27.800
We can have a tree like
this, which is basically

00:15:27.800 --> 00:15:31.220
a linked list where we only
use right pointers and all

00:15:31.220 --> 00:15:32.750
the left pointers are none.

00:15:32.750 --> 00:15:37.772
So there are trees that are
very high, have high height.

00:15:37.772 --> 00:15:39.980
We want to avoid these, but
we won't worry about that

00:15:39.980 --> 00:15:40.760
till next lecture.

00:15:40.760 --> 00:15:41.580
Question?

00:15:41.580 --> 00:15:42.913
AUDIENCE: A couple of questions.

00:15:42.913 --> 00:15:45.258
Is the height of C--
of node C is 0 or--

00:15:45.258 --> 00:15:47.050
ERIK DEMAINE: What is
the height of node C?

00:15:47.050 --> 00:15:48.903
Height of node C is 0.

00:15:48.903 --> 00:15:50.570
Because the length
of the longest path--

00:15:50.570 --> 00:15:53.496
the number of edges in the
longest downward path is 0.

00:15:53.496 --> 00:15:54.290
AUDIENCE: Oh.

00:15:54.290 --> 00:15:54.740
ERIK DEMAINE: Yeah.

00:15:54.740 --> 00:15:56.198
We're counting
edges, not vertices.

00:15:59.840 --> 00:16:01.335
Yeah.

00:16:01.335 --> 00:16:03.710
So the height of the tree is,
of course, just the depth--

00:16:03.710 --> 00:16:04.725
the maximum depth.

00:16:04.725 --> 00:16:05.600
I think that's right.

00:16:05.600 --> 00:16:09.410
So the height here is
3, and the maximum depth

00:16:09.410 --> 00:16:11.390
is this terribly drawn 3.

00:16:11.390 --> 00:16:14.390
So these happen to correspond
in the maximum case.

00:16:14.390 --> 00:16:17.330
But We use height to
always mean maximum,

00:16:17.330 --> 00:16:20.780
and so that's why we talk
about the height of the tree.

00:16:20.780 --> 00:16:24.980
Depth of the tree is not
defined, just depth of nodes.

00:16:24.980 --> 00:16:27.710
OK.

00:16:27.710 --> 00:16:29.780
How do we use these
trees to represent

00:16:29.780 --> 00:16:33.380
either a sequence or a set?

00:16:33.380 --> 00:16:36.620
I claim that there
is a natural order

00:16:36.620 --> 00:16:51.650
in trees called the traversal
order of nodes or items

00:16:51.650 --> 00:16:53.120
in the tree.

00:16:53.120 --> 00:16:58.115
So I'm going to define
a particular order, say,

00:16:58.115 --> 00:16:59.896
in this example.

00:16:59.896 --> 00:17:01.130
Let's do the example first.

00:17:03.820 --> 00:17:20.839
The traversal order is going
to be F, D, B, E, A, C.

00:17:20.839 --> 00:17:22.829
I feel like I'm in music class.

00:17:22.829 --> 00:17:27.050
This is my guitar or something,
but it's not, I hope.

00:17:27.050 --> 00:17:29.150
If it is, it's coincidence.

00:17:29.150 --> 00:17:32.000
So what is this order?

00:17:32.000 --> 00:17:35.330
What I'd like to
do is recursively

00:17:35.330 --> 00:17:38.300
define an order where
the root of the tree

00:17:38.300 --> 00:17:41.720
is somewhere in the middle, and
everything in the left subtree

00:17:41.720 --> 00:17:44.840
is left earlier in the
order than the root,

00:17:44.840 --> 00:17:47.350
and everything in the
right subtree is later.

00:17:47.350 --> 00:17:50.120
So you can see here
C comes after A,

00:17:50.120 --> 00:17:52.670
and then all the other
nodes come before A.

00:17:52.670 --> 00:17:57.170
And recursively, if I look at
a node B, this node B, which

00:17:57.170 --> 00:18:00.410
appears over here, E
is to the right of it,

00:18:00.410 --> 00:18:04.355
but this is all to the left
of A. So E is between B

00:18:04.355 --> 00:18:07.460
and A. With B on
the left, and then

00:18:07.460 --> 00:18:09.110
F and D to the left of that.

00:18:09.110 --> 00:18:11.630
And again, F comes
before D because F

00:18:11.630 --> 00:18:24.410
is in the left subtree of
D. So we say for every node,

00:18:24.410 --> 00:18:37.700
the nodes in X.left are before
X and the nodes in X.right

00:18:37.700 --> 00:18:43.190
come after X.

00:18:43.190 --> 00:18:46.390
And this uniquely defines an
order called a traversal order.

00:18:46.390 --> 00:18:49.200
That's also called
in-order traversal order.

00:18:49.200 --> 00:18:51.890
It's called in-order because
it's in the traversal order,

00:18:51.890 --> 00:18:54.530
so it's very
circular, but you may

00:18:54.530 --> 00:18:57.380
have seen in-order traversal,
this is the same thing.

00:18:57.380 --> 00:19:00.750
There's a very simple
algorithm for computing this.

00:19:00.750 --> 00:19:04.670
If I want to iterate--

00:19:04.670 --> 00:19:07.070
let's call this-- yeah.

00:19:07.070 --> 00:19:11.360
If I want to iterate all the
nodes within a subtree X,

00:19:11.360 --> 00:19:15.020
rooted by X, I
just iterate on all

00:19:15.020 --> 00:19:20.300
of the notes in the left
subtree, then I output X

00:19:20.300 --> 00:19:25.970
itself, then I iterate on all
the nodes in the right subtree.

00:19:30.890 --> 00:19:33.350
OK, you may have seen
that algorithm before.

00:19:33.350 --> 00:19:35.970
This is just another way
to codify the same thing.

00:19:35.970 --> 00:19:38.180
The result is, all the
nodes within a subtree

00:19:38.180 --> 00:19:41.750
appear continuously with
no interruptions, and then

00:19:41.750 --> 00:19:42.605
the parent--

00:19:42.605 --> 00:19:44.730
parents are going to come
before or after depending

00:19:44.730 --> 00:19:48.500
on whether this is a
left or a right child.

00:19:48.500 --> 00:19:52.370
OK, so now it's just a matter
of connecting the dots,

00:19:52.370 --> 00:19:54.680
because we're
representing an order.

00:19:54.680 --> 00:19:57.560
And for a sequence, that is
going to be the sequence order.

00:19:57.560 --> 00:20:00.260
If we want to store n
items X0 through X1,

00:20:00.260 --> 00:20:02.990
we're going to build
some kind of tree.

00:20:02.990 --> 00:20:06.740
We're going to put X0 here,
X1 here, X2 here, X3 here, X4

00:20:06.740 --> 00:20:08.260
here, X5 in here.

00:20:08.260 --> 00:20:10.760
You can see, I'm very used to
dealing with traversal orders.

00:20:10.760 --> 00:20:11.885
It takes a little while.

00:20:11.885 --> 00:20:13.010
You could also see it here.

00:20:13.010 --> 00:20:15.490
We're going to put
X1 on this node, X2--

00:20:15.490 --> 00:20:15.990
sorry.

00:20:15.990 --> 00:20:18.600
X0 here, X1 here,
X2 here, and so on.

00:20:18.600 --> 00:20:21.907
That's the same
order that I gave.

00:20:21.907 --> 00:20:22.990
OK, that's four sequences.

00:20:22.990 --> 00:20:25.840
For sets, that order is just
going to be disordered order,

00:20:25.840 --> 00:20:27.820
and we're going to be
effectively representing

00:20:27.820 --> 00:20:31.760
the sorted order of
keys, say, increasing.

00:20:31.760 --> 00:20:36.460
But before we get to that, let's
talk about different operations

00:20:36.460 --> 00:20:43.960
we can do just playing
around with traversal order.

00:20:43.960 --> 00:20:46.930
And then we're going to use
these to build the sequence

00:20:46.930 --> 00:20:49.730
and set operations
that we care about.

00:20:49.730 --> 00:20:54.550
So a first operation
I'll call subtree first.

00:20:54.550 --> 00:20:58.288
Seems appropriate that
it's called first.

00:20:58.288 --> 00:21:00.490
It's the first one.

00:21:00.490 --> 00:21:05.230
So, given a node,
which I'll call node,

00:21:05.230 --> 00:21:11.060
this defines a subtree,
which usually we

00:21:11.060 --> 00:21:16.470
draw subtrees as triangles
hanging off of the node.

00:21:16.470 --> 00:21:20.240
So here, I would write
X, and then there's

00:21:20.240 --> 00:21:23.240
some subtree of all
the descendants of X.

00:21:23.240 --> 00:21:25.370
So with subtree
first, I would like

00:21:25.370 --> 00:21:35.780
to say among all the nodes in
this subtree, which comes first

00:21:35.780 --> 00:21:36.920
in this traversal order?

00:21:43.350 --> 00:21:49.430
So just restricting to that
subtree, subtree of node.

00:21:55.200 --> 00:21:58.440
So, where is it in this tree?

00:21:58.440 --> 00:21:59.234
Yeah?

00:21:59.234 --> 00:22:03.608
AUDIENCE: A node can be only
part of one subtree, right?

00:22:03.608 --> 00:22:05.900
ERIK DEMAINE: A node is
actually part of many subtrees,

00:22:05.900 --> 00:22:07.220
good question.

00:22:07.220 --> 00:22:09.470
F, F is in its
own-- in the subtree

00:22:09.470 --> 00:22:13.400
of F. F is also in the subtree
of D, F is in the subtree of B

00:22:13.400 --> 00:22:15.650
like I drew, F as
in the subtree of A.

00:22:15.650 --> 00:22:18.050
It's in the subtree of
exactly its ancestors.

00:22:20.680 --> 00:22:24.100
But in this operation, when we--

00:22:24.100 --> 00:22:26.200
our node only
defines one subtree.

00:22:26.200 --> 00:22:28.150
It is the root of
only one subtree.

00:22:28.150 --> 00:22:30.860
And that's the subtree
we're talking about.

00:22:30.860 --> 00:22:33.100
And then I want to know,
among all those nodes, which

00:22:33.100 --> 00:22:36.250
includes the node
itself and other things,

00:22:36.250 --> 00:22:38.920
which one comes first
in this traversal order?

00:22:38.920 --> 00:22:42.328
This is like practice
with traversal orders.

00:22:42.328 --> 00:22:43.870
So where should I
look for this node?

00:22:49.310 --> 00:22:50.900
Yeah.

00:22:50.900 --> 00:22:52.880
The leftmost leaf, yeah.

00:22:52.880 --> 00:22:57.200
And the picture, it's here,
but pictures can be deceiving.

00:22:57.200 --> 00:23:01.460
We just want to go left
as much as possible.

00:23:01.460 --> 00:23:04.310
When I say go left, I
mean this iteration node

00:23:04.310 --> 00:23:08.000
equals node.left.

00:23:08.000 --> 00:23:10.460
If you just look
at our definition,

00:23:10.460 --> 00:23:13.968
all the nodes in the left come
before X and all the nodes

00:23:13.968 --> 00:23:14.510
in the right.

00:23:14.510 --> 00:23:18.560
So it's got to be on the
left subtree if there is one.

00:23:18.560 --> 00:23:21.440
Of course, we can't
do this forever.

00:23:21.440 --> 00:23:28.560
So say until we would
fall off the tree, which

00:23:28.560 --> 00:23:32.040
means node is none.

00:23:34.700 --> 00:23:39.890
OK, we stop before
that would happen.

00:23:39.890 --> 00:23:42.180
So this is like the
directions like, oh, you

00:23:42.180 --> 00:23:44.010
keep driving until
you see the store,

00:23:44.010 --> 00:23:45.810
and it's the block
right before that.

00:23:45.810 --> 00:23:47.830
It's like, well, that's
not very helpful.

00:23:47.830 --> 00:23:50.070
So you keep iterating
node equals node.left

00:23:50.070 --> 00:23:53.670
until node becomes none,
and then you undo one step.

00:23:53.670 --> 00:23:57.000
You all know how to program
that, it's not hard.

00:23:57.000 --> 00:24:00.900
So that last non-non-node, which
might actually be the root,

00:24:00.900 --> 00:24:04.800
it might be node, maybe
it has no left children.

00:24:04.800 --> 00:24:06.750
But in that case I
claim node is the very

00:24:06.750 --> 00:24:09.000
first in its subtree
traversal order

00:24:09.000 --> 00:24:12.090
because if there are no
nodes in the left that

00:24:12.090 --> 00:24:16.130
come before X, then
x is actually first.

00:24:16.130 --> 00:24:18.150
So that's it.

00:24:18.150 --> 00:24:18.840
Return node.

00:24:21.980 --> 00:24:24.510
So I'm modifying
node in place here.

00:24:24.510 --> 00:24:27.610
And the very last one before I
hit none, that's the minimum.

00:24:27.610 --> 00:24:30.180
That's the first item
in the traversal order.

00:24:30.180 --> 00:24:33.000
Similarly, you can
define subtree last.

00:24:33.000 --> 00:24:35.430
OK, let's do a more
interesting one.

00:24:35.430 --> 00:24:43.140
Successor node.

00:24:43.140 --> 00:24:45.150
So in this case, I
want to know what

00:24:45.150 --> 00:24:56.880
is the next after none in the
overall tree's traversal order?

00:24:56.880 --> 00:25:01.440
Here, I was restricting
to a single subtree.

00:25:01.440 --> 00:25:03.030
Now I'm thinking
about the entire tree

00:25:03.030 --> 00:25:04.590
and the entire traversal order.

00:25:04.590 --> 00:25:08.250
And given a node, I want to
know which one comes next?

00:25:08.250 --> 00:25:10.920
Call this the successor.

00:25:10.920 --> 00:25:14.940
I feel like I should make some
kind of royal family joke now,

00:25:14.940 --> 00:25:17.940
but I don't know how.

00:25:17.940 --> 00:25:20.610
So every node has
a unique successor.

00:25:20.610 --> 00:25:22.840
Let's do-- let's
do some examples.

00:25:22.840 --> 00:25:25.440
So we can start with F--

00:25:25.440 --> 00:25:27.330
the successor of
F. If we just index

00:25:27.330 --> 00:25:31.890
into this list, the
successor is D. Successor

00:25:31.890 --> 00:25:35.300
D is B. The successor B is
E. It's very easy to read

00:25:35.300 --> 00:25:38.162
successors off when I have the
traversal order written down,

00:25:38.162 --> 00:25:40.120
but let's think about
how to do it in the tree.

00:25:45.150 --> 00:25:45.650
Let's see.

00:25:45.650 --> 00:25:48.370
There are going to be two cases.

00:25:48.370 --> 00:25:53.930
If we look at the successor
of A, it has a right child.

00:25:53.930 --> 00:25:57.080
And in this case, the right
child of A is the successor,

00:25:57.080 --> 00:25:58.830
but that's not always the case.

00:25:58.830 --> 00:26:02.540
I don't have an example,
but if I had another node,

00:26:02.540 --> 00:26:08.180
here let's call it
G, the successor of A

00:26:08.180 --> 00:26:12.980
is actually G. Because
all of these items

00:26:12.980 --> 00:26:15.080
come after A in the order.

00:26:15.080 --> 00:26:16.640
But which one comes first?

00:26:16.640 --> 00:26:19.040
The leftmost leaf.

00:26:19.040 --> 00:26:20.870
That's the problem
we just solved.

00:26:20.870 --> 00:26:23.330
So if A has a right
child, what we want

00:26:23.330 --> 00:26:30.100
is the leftmost leaf, the
first thing in that subtree.

00:26:30.100 --> 00:26:31.150
The right subtree.

00:26:31.150 --> 00:26:32.730
Right child subtree.

00:26:32.730 --> 00:26:33.910
So this is case 1.

00:26:33.910 --> 00:26:42.310
If node.right-- so if we have
a child, then what we want

00:26:42.310 --> 00:26:49.810
is subtree first
of the right child.

00:26:54.680 --> 00:26:55.180
OK, great.

00:26:55.180 --> 00:26:58.840
We can reduce to
this other operation.

00:26:58.840 --> 00:27:03.610
But what if the node
doesn't have a right child?

00:27:03.610 --> 00:27:05.440
For example, it could be a leaf.

00:27:05.440 --> 00:27:07.552
Say we're taking the successor--

00:27:07.552 --> 00:27:09.010
I mean, it doesn't
have to be leaf.

00:27:09.010 --> 00:27:10.552
It could be F, which
has no children.

00:27:10.552 --> 00:27:14.330
It could be D, which has one
child, but no right child.

00:27:14.330 --> 00:27:15.670
So what's the successor of F?

00:27:15.670 --> 00:27:19.802
Well, it's D, which in
this case is the parent,

00:27:19.802 --> 00:27:20.635
but it's not always.

00:27:20.635 --> 00:27:22.510
For example, if we
do a successor of E,

00:27:22.510 --> 00:27:24.970
its parent is actually
earlier in the order

00:27:24.970 --> 00:27:26.530
because E was a right child.

00:27:26.530 --> 00:27:32.890
Here, F was a left child,
and so its parent was after.

00:27:32.890 --> 00:27:35.950
The successor of
D happens to be B

00:27:35.950 --> 00:27:40.288
because it was the left
child if its parent.

00:27:40.288 --> 00:27:41.830
OK, so that seems
like the easy case.

00:27:41.830 --> 00:27:43.413
If we're the left
child of our parent,

00:27:43.413 --> 00:27:48.785
then our successor is our parent
basing on this small example,

00:27:48.785 --> 00:27:50.410
but we can argue
generally in a moment.

00:27:50.410 --> 00:27:52.300
What's the successor of E?

00:27:52.300 --> 00:27:54.370
Well, it's not B because
that comes earlier.

00:27:54.370 --> 00:27:57.070
In fact, all the
things in B subtree

00:27:57.070 --> 00:28:01.930
come earlier or equal to E.

00:28:01.930 --> 00:28:03.880
So we have to keep going up.

00:28:03.880 --> 00:28:05.680
And then it turns out
the successor of E

00:28:05.680 --> 00:28:10.120
is A because this subtree
was the left child of A,

00:28:10.120 --> 00:28:13.780
because B was a left child
of A. So the general strategy

00:28:13.780 --> 00:28:21.140
is walk up the
tree until we go up

00:28:21.140 --> 00:28:24.750
traversal whose reverse
direction would be left.

00:28:24.750 --> 00:28:29.480
So walk up the tree.

00:28:29.480 --> 00:28:40.390
When I say walk up, I mean node
equals node.parent iteration

00:28:40.390 --> 00:28:47.140
Until we go up a left branch.

00:28:50.630 --> 00:28:53.290
So this would mean that node--

00:28:53.290 --> 00:28:57.990
before we do the change node
equals node.parent.left.

00:29:03.370 --> 00:29:04.450
So we can check that.

00:29:04.450 --> 00:29:05.950
And then after we
do that traversal,

00:29:05.950 --> 00:29:09.010
that parent is exactly the
node we're looking for.

00:29:13.950 --> 00:29:15.280
Why is this true in general?

00:29:15.280 --> 00:29:17.960
Let me draw a more
generic picture.

00:29:17.960 --> 00:29:21.920
So we're starting at some node.

00:29:21.920 --> 00:29:25.480
And let's say its
parent is to the right--

00:29:25.480 --> 00:29:28.930
so it comes later in
the order for a while.

00:29:28.930 --> 00:29:29.575
Sorry.

00:29:29.575 --> 00:29:31.540
I get this backwards,
we're doing successor.

00:29:34.720 --> 00:29:38.287
It goes to the left for a while.

00:29:38.287 --> 00:29:40.870
So these are-- all these nodes
will come earlier in the order,

00:29:40.870 --> 00:29:43.287
because by the definition,
everything in the right subtree

00:29:43.287 --> 00:29:44.050
comes after.

00:29:44.050 --> 00:29:46.550
And at some point we have a
parent that's to the right,

00:29:46.550 --> 00:29:50.140
meaning this node was the
left child of this parent.

00:29:50.140 --> 00:29:52.180
And that node, by
definition, will come

00:29:52.180 --> 00:29:55.330
after all of the nodes in here.

00:29:55.330 --> 00:30:00.740
And could there be anything in
between node and this parent,

00:30:00.740 --> 00:30:03.250
grandparent, ancestor?

00:30:03.250 --> 00:30:05.530
Only if there was
something in this subtree.

00:30:05.530 --> 00:30:08.740
And we're in the case here
where there is no right subtree

00:30:08.740 --> 00:30:10.300
of our original node.

00:30:10.300 --> 00:30:13.330
So this is where all the
nodes in between node and here

00:30:13.330 --> 00:30:13.960
would be.

00:30:13.960 --> 00:30:15.760
But there aren't any,
and therefore, this

00:30:15.760 --> 00:30:17.800
is the successor.

00:30:17.800 --> 00:30:21.880
So that's sort of a general
argument why this works.

00:30:21.880 --> 00:30:23.466
I see a question, yeah?

00:30:23.466 --> 00:30:26.330
AUDIENCE: So when you
say go up a left branch,

00:30:26.330 --> 00:30:29.530
does that mean that
you mark the root node

00:30:29.530 --> 00:30:36.603
subtree that is left child into
the traversal order children?

00:30:36.603 --> 00:30:38.520
ERIK DEMAINE: Placed
into the traversal order.

00:30:38.520 --> 00:30:41.810
So the traversal order is
never explicitly computed.

00:30:41.810 --> 00:30:44.150
What we're-- it's
always implicit.

00:30:44.150 --> 00:30:48.750
We can't afford to maintain
this as, say, an array.

00:30:48.750 --> 00:30:50.180
This is just in our heads.

00:30:50.180 --> 00:30:55.100
Maybe I will draw it
with a cloud around it.

00:30:55.100 --> 00:30:57.980
We're just thinking this.

00:30:57.980 --> 00:31:00.320
It's not in the
computer explicitly.

00:31:00.320 --> 00:31:03.200
And the computer
always stores this.

00:31:03.200 --> 00:31:05.250
And the reason is,
this is expensive,

00:31:05.250 --> 00:31:07.940
we don't-- we can't maintain
an array of things and be able

00:31:07.940 --> 00:31:10.400
to insert in the middle,
whereas this is cheap.

00:31:10.400 --> 00:31:12.680
I can afford to
maintain this structure

00:31:12.680 --> 00:31:13.710
and do all these things.

00:31:13.710 --> 00:31:15.980
And so the reason we're
talking about these operations

00:31:15.980 --> 00:31:17.820
is they're letting us
manipulate the order--

00:31:17.820 --> 00:31:21.327
or in this case, letting us
iterate through the order.

00:31:21.327 --> 00:31:22.910
So this was an
algorithm for iterating

00:31:22.910 --> 00:31:26.690
through the entire order,
but that takes linear time.

00:31:26.690 --> 00:31:28.760
This was getting
started in the order,

00:31:28.760 --> 00:31:31.520
finding the first
thing in the order,

00:31:31.520 --> 00:31:35.060
and this was given one
node, finding the next one.

00:31:35.060 --> 00:31:36.890
How long did these
operations take?

00:31:48.660 --> 00:31:49.160
Yeah?

00:31:49.160 --> 00:31:56.076
AUDIENCE: So for the first node,
[INAUDIBLE] to get to that last

00:31:56.076 --> 00:31:56.580
node--

00:31:56.580 --> 00:31:56.940
ERIK DEMAINE: Right.

00:31:56.940 --> 00:31:59.320
At most, the height of
the entire tree-- in fact,

00:31:59.320 --> 00:32:02.150
it's going to be the
depth of that first node,

00:32:02.150 --> 00:32:04.950
but in the worst case, that's
the height of the entire tree.

00:32:04.950 --> 00:32:06.660
In general, all of
these operations

00:32:06.660 --> 00:32:08.890
are going to be order h.

00:32:08.890 --> 00:32:11.370
We need to think
about it in each case.

00:32:11.370 --> 00:32:13.690
Except for this one,
which is order n,

00:32:13.690 --> 00:32:16.350
because we're iterating
through the whole thing.

00:32:16.350 --> 00:32:18.630
In this case, we're just
calling subtree first,

00:32:18.630 --> 00:32:20.470
so that takes order h time.

00:32:20.470 --> 00:32:22.470
Here, we're walking up
the tree instead of down,

00:32:22.470 --> 00:32:25.410
but that's going to cost
exactly the height of the node.

00:32:25.410 --> 00:32:28.500
We happen to stop early,
but worst case, order h.

00:32:28.500 --> 00:32:31.380
For all this all the
operations we consider today,

00:32:31.380 --> 00:32:32.970
we just want to get
an order h bound,

00:32:32.970 --> 00:32:35.520
and later we will bound h.

00:32:35.520 --> 00:32:37.740
So the point is, these are fast.

00:32:37.740 --> 00:32:41.880
If h is small, like log n,
these are almost instantaneous.

00:32:41.880 --> 00:32:45.720
Whereas if I had to update the
explicit traversal order, say,

00:32:45.720 --> 00:32:48.420
as an array, I would have to
spend linear time every time

00:32:48.420 --> 00:32:49.800
I make a change.

00:32:49.800 --> 00:32:52.590
And yes, it would be
fast to do successor

00:32:52.590 --> 00:32:55.410
if I had this stored
explicitly, but maintaining

00:32:55.410 --> 00:32:57.480
it would be impossible,
maintaining efficiently

00:32:57.480 --> 00:32:58.574
would be impossible.

00:32:58.574 --> 00:32:59.562
Question?

00:32:59.562 --> 00:33:05.000
AUDIENCE: [INAUDIBLE]

00:33:05.000 --> 00:33:07.010
ERIK DEMAINE: Yes.

00:33:07.010 --> 00:33:07.510
OK.

00:33:14.000 --> 00:33:15.640
Cool.

00:33:15.640 --> 00:33:21.250
So these were queries
where I want to follow--

00:33:21.250 --> 00:33:24.257
see what's next in the
traversal sequence.

00:33:24.257 --> 00:33:25.840
Now let's talk about
actually changing

00:33:25.840 --> 00:33:26.870
the traversal sequence.

00:33:26.870 --> 00:33:28.990
So these are insert
and delete operations.

00:33:28.990 --> 00:33:33.280
These will correspond roughly
to insert at or delete at,

00:33:33.280 --> 00:33:34.840
but they're not quite--

00:33:34.840 --> 00:33:36.850
we're not quite in the
sequence world yet.

00:33:36.850 --> 00:33:39.580
Instead, we're going to
focus on inserting or leading

00:33:39.580 --> 00:33:41.095
in the middle of a subtree.

00:33:47.560 --> 00:33:50.050
So I'm going to have two nodes.

00:33:56.920 --> 00:34:04.430
So in the traversal
order, so node

00:34:04.430 --> 00:34:06.230
already exists in the tree.

00:34:06.230 --> 00:34:09.150
New is a new node that does
not yet exist in the tree,

00:34:09.150 --> 00:34:10.340
hence I call it new.

00:34:10.340 --> 00:34:16.370
And what I'd like to do is
insert new right after node.

00:34:16.370 --> 00:34:18.770
There's a symmetric operation
which is insert before.

00:34:18.770 --> 00:34:21.540
It will be implemented
almost identically.

00:34:21.540 --> 00:34:24.828
So we'll just focus on after.

00:34:24.828 --> 00:34:27.120
So I want to insert this new
node in the reverse order,

00:34:27.120 --> 00:34:28.370
which, again, is in our heads.

00:34:28.370 --> 00:34:30.489
This is all in our
thought bubble.

00:34:33.449 --> 00:34:35.250
That's what we want to achieve.

00:34:35.250 --> 00:34:38.370
And we have to do it by
manipulating this tree,

00:34:38.370 --> 00:34:40.050
and however we
change the tree, it

00:34:40.050 --> 00:34:43.130
defines a new traversal order.

00:34:43.130 --> 00:34:44.815
So maybe let's do
an example first.

00:35:01.534 --> 00:35:06.460
Actually, I probably want
this in traversal order To.

00:35:06.460 --> 00:35:08.540
Keep track of that.

00:35:08.540 --> 00:35:13.960
So, let's say the first
thing we want to do

00:35:13.960 --> 00:35:23.900
is insert G before E.
I want to illustrate

00:35:23.900 --> 00:35:27.440
both of the operations.

00:35:27.440 --> 00:35:44.030
Insert H after E. So
insert G before E.

00:35:44.030 --> 00:35:48.320
So conceptually what we
want to do is insert G here.

00:35:48.320 --> 00:35:52.580
And the way-- so we're given the
node E and we're given a sort

00:35:52.580 --> 00:35:53.465
of empty node--

00:35:53.465 --> 00:35:55.090
I mean, a node that
just contains G. It

00:35:55.090 --> 00:35:56.780
doesn't have any pointers yet.

00:35:56.780 --> 00:35:59.750
And we would like
to put it before E.

00:35:59.750 --> 00:36:02.060
Where should I put it?

00:36:02.060 --> 00:36:04.740
Left child.

00:36:04.740 --> 00:36:07.130
And so that's-- this
is an easy case.

00:36:07.130 --> 00:36:09.920
If I'm trying to insert before
and there's no left child,

00:36:09.920 --> 00:36:10.550
stick it there.

00:36:10.550 --> 00:36:13.340
If I'm trying to insert it after
and there's no right child,

00:36:13.340 --> 00:36:14.120
stick it there.

00:36:14.120 --> 00:36:15.080
Easy.

00:36:15.080 --> 00:36:16.460
So let me write down case 1.

00:36:20.660 --> 00:36:22.520
So here, we're inserting after.

00:36:22.520 --> 00:36:36.710
So if there's no right
child, put new there.

00:36:36.710 --> 00:36:38.300
I'm using informal
language here,

00:36:38.300 --> 00:36:44.090
putting this new node
there instead of writing,

00:36:44.090 --> 00:36:47.690
for example,
node.right equals new.

00:36:47.690 --> 00:36:50.180
Because that's only one
operation you need to do.

00:36:50.180 --> 00:36:52.850
One thing you would do is
set node.right equals to new,

00:36:52.850 --> 00:36:56.090
but you also have to set
new's parent to be node.right.

00:36:56.090 --> 00:36:58.765
So instead of worrying about
those two pointer changes,

00:36:58.765 --> 00:37:00.890
because we always do
bidirectional pointer changes,

00:37:00.890 --> 00:37:02.840
I'm just going to
use pseudocode,

00:37:02.840 --> 00:37:05.060
and then a recitation you'll
see actual Python code

00:37:05.060 --> 00:37:07.820
that does all this.

00:37:07.820 --> 00:37:12.560
So then there's the other case.

00:37:12.560 --> 00:37:14.680
So that should be
the second example.

00:37:14.680 --> 00:37:21.775
Insert h after A.
Insert h after A.

00:37:21.775 --> 00:37:25.480
So we already have a node
after A in the right child

00:37:25.480 --> 00:37:26.485
in this right subtree.

00:37:29.360 --> 00:37:35.810
So where do I want to
put H relative to A?

00:37:35.810 --> 00:37:38.810
Well, it should be
to the right of A,

00:37:38.810 --> 00:37:43.400
but it should be before C. It
should be to the left of C.

00:37:43.400 --> 00:37:47.210
So that would mean we
want to put it here.

00:37:47.210 --> 00:37:50.360
In this case, it was pretty easy
because this tree was small.

00:37:50.360 --> 00:37:52.040
Where do I want to
put it in general?

00:37:52.040 --> 00:37:58.100
Well, wherever subtree
first tells me to put it.

00:37:58.100 --> 00:38:00.798
Subtree first is going
to give me the successor.

00:38:00.798 --> 00:38:02.090
These are all kind of parallel.

00:38:05.150 --> 00:38:08.870
We're in the case now where
our node has a right child.

00:38:08.870 --> 00:38:11.460
And then successor tells
us where the successor is.

00:38:11.460 --> 00:38:15.920
It is the first node, which
is the leftmost descendant,

00:38:15.920 --> 00:38:19.430
in the right
subtree of the node.

00:38:19.430 --> 00:38:21.380
A lot of pointers to
follow in that sentence,

00:38:21.380 --> 00:38:25.880
but it's clear in the picture.

00:38:25.880 --> 00:38:29.430
So in this case we had a node,
and there was no right child,

00:38:29.430 --> 00:38:33.860
so we just added new
to be its right child.

00:38:33.860 --> 00:38:37.500
In the other case,
we had a right child.

00:38:37.500 --> 00:38:41.150
So here is node.

00:38:41.150 --> 00:38:44.885
There's this node
here, node.right,

00:38:44.885 --> 00:38:46.415
which now we're
supposing exists.

00:38:49.070 --> 00:38:50.840
And it defines a whole subtree.

00:38:50.840 --> 00:38:56.210
There's this one,
which is the first node

00:38:56.210 --> 00:38:58.250
in the reverse order of
the subtree, also known

00:38:58.250 --> 00:39:00.050
as the successor of node.

00:39:00.050 --> 00:39:04.910
So I'll call the
successor of node

00:39:04.910 --> 00:39:06.740
in the current universal order.

00:39:06.740 --> 00:39:10.220
But of course, we'd like to
make new the new successor

00:39:10.220 --> 00:39:10.960
of the node.

00:39:10.960 --> 00:39:13.410
So where does it go?

00:39:13.410 --> 00:39:13.910
Here.

00:39:17.060 --> 00:39:21.500
We want to add it as a left
child to the old successor.

00:39:24.120 --> 00:39:29.520
So put node as--

00:39:40.410 --> 00:39:41.460
so take the successor.

00:39:41.460 --> 00:39:43.320
And if you look at the
code for successor,

00:39:43.320 --> 00:39:45.600
where in this case, so we
know it we'll just call

00:39:45.600 --> 00:39:48.240
subtree first of node.right.

00:39:48.240 --> 00:39:51.300
And remember, subtree
first went left as much

00:39:51.300 --> 00:39:52.990
as it possibly could.

00:39:52.990 --> 00:39:55.620
So what that means is this
successor node is guaranteed

00:39:55.620 --> 00:39:58.345
to not have a left child.

00:39:58.345 --> 00:40:00.720
Because it was defined by
going right once and then going

00:40:00.720 --> 00:40:02.550
left as much as you could.

00:40:02.550 --> 00:40:04.260
So there's no more
left, which means

00:40:04.260 --> 00:40:05.655
we can make one more left.

00:40:05.655 --> 00:40:09.240
We just add new
there and we're done.

00:40:09.240 --> 00:40:11.160
Now if you look at
the traversal order,

00:40:11.160 --> 00:40:13.980
it will be node, then new,
then the old successor

00:40:13.980 --> 00:40:16.520
and the rest of that subtree.

00:40:16.520 --> 00:40:17.790
It's kind of cool.

00:40:17.790 --> 00:40:20.640
In all cases--

00:40:20.640 --> 00:40:22.740
I mean, this was constant time.

00:40:22.740 --> 00:40:25.560
Here, we spent constant time
after we called successor.

00:40:25.560 --> 00:40:31.175
Successor costs order h
time, so this is order h.

00:40:31.175 --> 00:40:32.350
AUDIENCE: It's new or node?

00:40:32.350 --> 00:40:33.100
ERIK DEMAINE: Hmm?

00:40:33.100 --> 00:40:34.270
AUDIENCE: New or node?

00:40:34.270 --> 00:40:36.580
ERIK DEMAINE: New, new.

00:40:36.580 --> 00:40:38.650
Thank you.

00:40:38.650 --> 00:40:39.520
Put new there.

00:40:44.770 --> 00:40:45.950
Clear?

00:40:45.950 --> 00:40:47.740
OK, that was insertion.

00:40:47.740 --> 00:40:48.595
Let's do deletion.

00:40:54.390 --> 00:40:57.975
Get the spec right
and the example.

00:41:10.410 --> 00:41:13.210
All of these are going
to have two cases.

00:41:13.210 --> 00:41:16.620
So let me-- oh, I didn't update.

00:41:16.620 --> 00:41:20.387
So now H is after A. So
it should be like this.

00:41:20.387 --> 00:41:22.470
You can check, the new
traversal order of the tree

00:41:22.470 --> 00:41:23.460
is exactly that.

00:41:26.300 --> 00:41:29.240
Next, I'm going to do
a couple of deletions.

00:41:29.240 --> 00:41:38.552
Let's delete F first,
and then we're going to--

00:41:38.552 --> 00:41:43.265
wow, this is confusing.

00:41:48.120 --> 00:41:52.130
We're going to delete
A. So whereas F,

00:41:52.130 --> 00:41:55.280
we're supposing we're given a
pointer to F, this node, well,

00:41:55.280 --> 00:41:56.150
it's a leaf.

00:41:56.150 --> 00:41:59.690
So if I want to delete
it, I just erase it.

00:41:59.690 --> 00:42:01.340
Easy.

00:42:01.340 --> 00:42:03.990
Leaves are easy to delete,
there's no work to do.

00:42:03.990 --> 00:42:05.840
So what that means
is I'm removing

00:42:05.840 --> 00:42:11.240
the pointer from D to F.
We'll just erase that guy.

00:42:11.240 --> 00:42:12.590
OK, now here's a trickier one.

00:42:12.590 --> 00:42:14.510
Suppose I want to delete
the root of the tree.

00:42:14.510 --> 00:42:16.610
This is kind of
the hardest case.

00:42:16.610 --> 00:42:18.200
But in general,
it'd be somewhere

00:42:18.200 --> 00:42:20.470
in between leaf and root.

00:42:20.470 --> 00:42:23.480
So if you want to delete
A, if I just erased it,

00:42:23.480 --> 00:42:25.670
then suddenly there are
these pointers to nowhere

00:42:25.670 --> 00:42:27.600
and I disconnect the
tree into two parts.

00:42:27.600 --> 00:42:30.320
I don't want to do that, I
need to keep my tree connected.

00:42:30.320 --> 00:42:35.510
So I'm going to play
this trick, which is--

00:42:35.510 --> 00:42:38.750
I forget if I use
successor or predecessor.

00:42:38.750 --> 00:42:39.590
Predecessor.

00:42:43.740 --> 00:42:48.740
So I'm going to look at A. We
already have to find successor

00:42:48.740 --> 00:42:51.390
and thereby predecessor.

00:42:51.390 --> 00:42:54.170
So I'm going to look at
the predecessor of A, which

00:42:54.170 --> 00:42:58.370
is E. We can check that
here, the one before A

00:42:58.370 --> 00:43:01.610
is E. This is in
the left subtree.

00:43:01.610 --> 00:43:03.118
Find me the rightmost item.

00:43:03.118 --> 00:43:04.410
Keep going right until I can't.

00:43:04.410 --> 00:43:05.777
That's E.

00:43:05.777 --> 00:43:07.610
So now these guys are
adjacent in the order,

00:43:07.610 --> 00:43:09.890
and I'm about to remove
A from the order.

00:43:09.890 --> 00:43:13.940
So I can momentarily cheat
and swap their labels.

00:43:13.940 --> 00:43:20.360
I'm going to erase A and E
here and put E after A. Why?

00:43:20.360 --> 00:43:22.850
Because it moves a
down in the tree.

00:43:22.850 --> 00:43:24.648
And if I get to
a leaf, I'm done.

00:43:24.648 --> 00:43:26.690
So I'm not quite done
because this is not a leaf.

00:43:26.690 --> 00:43:28.430
So again, I look
at A's predecessor,

00:43:28.430 --> 00:43:35.030
it's now G. Predecessor,
we hope, is always in the--

00:43:35.030 --> 00:43:36.950
farther down in the tree.

00:43:36.950 --> 00:43:44.890
And then I swap A with G. I have
preserved the traversal order,

00:43:44.890 --> 00:43:48.820
except where A falls, just by
moving A earlier in the order

00:43:48.820 --> 00:43:49.360
here.

00:43:49.360 --> 00:43:51.840
And now A is a leaf
and I can erase it.

00:43:54.670 --> 00:43:56.660
So that's what we're
going to follow.

00:43:56.660 --> 00:43:58.517
Now in actuality,
it's a little tricky.

00:43:58.517 --> 00:44:00.100
Sometimes we need
to use predecessors,

00:44:00.100 --> 00:44:04.450
sometimes we need
to use successor.

00:44:04.450 --> 00:44:08.560
So the cases are,
if node is a leaf,

00:44:08.560 --> 00:44:11.590
just detach it from the parent.

00:44:11.590 --> 00:44:14.090
Easy.

00:44:14.090 --> 00:44:16.390
That's sort of our base
case in the recursion.

00:44:16.390 --> 00:44:20.510
Otherwise, there are two cases.

00:44:20.510 --> 00:44:24.640
If-- so if we're not
a leaf, that means

00:44:24.640 --> 00:44:27.860
we have a left child or
a right child or both.

00:44:27.860 --> 00:44:29.680
Both is going to
be the easy case,

00:44:29.680 --> 00:44:33.550
but in general I have either
there's the left child

00:44:33.550 --> 00:44:35.798
or there's a right child.

00:44:35.798 --> 00:44:37.340
In either case I'm
going to be happy,

00:44:37.340 --> 00:44:41.360
so I don't need a both case.

00:44:41.360 --> 00:44:41.860
OK.

00:44:41.860 --> 00:44:43.540
So what do I do?

00:44:43.540 --> 00:44:47.050
If I have a left child,
that guarantees to me

00:44:47.050 --> 00:44:50.500
that the node's predecessor is
inside that left subtree, which

00:44:50.500 --> 00:44:52.750
means it's lower in the tree.

00:44:52.750 --> 00:44:54.808
If I didn't have a left
child, the predecessor

00:44:54.808 --> 00:44:56.350
would actually be
higher in the tree,

00:44:56.350 --> 00:44:58.250
and I don't want to go higher.

00:44:58.250 --> 00:45:01.540
So if I have a left child, I
know the predecessor is lower,

00:45:01.540 --> 00:45:08.830
and so I'm going to swap my
item, the contents of my node

00:45:08.830 --> 00:45:11.200
with my predecessor's item.

00:45:19.030 --> 00:45:23.710
And then I'm going to
recursively delete predecessor.

00:45:32.013 --> 00:45:33.430
And that's the
case that we looked

00:45:33.430 --> 00:45:35.170
at in this code--
in this example

00:45:35.170 --> 00:45:36.820
because we always
had a left child.

00:45:36.820 --> 00:45:38.770
If we have a right
child but no left child,

00:45:38.770 --> 00:45:41.830
we just do the reverse, we
swap with our successor's item

00:45:41.830 --> 00:45:43.450
and then delete the successor.

00:45:43.450 --> 00:45:45.590
In either case we're going down.

00:45:45.590 --> 00:45:48.340
And so if we start at
some node like the root,

00:45:48.340 --> 00:45:52.270
every time we do this
operation, we're walking down,

00:45:52.270 --> 00:45:54.550
and then we're walking
down, and in general we'll

00:45:54.550 --> 00:45:56.870
keep walking down,
resuming where we left off,

00:45:56.870 --> 00:45:59.050
which means total
amount of time we spend

00:45:59.050 --> 00:46:03.070
is proportional to the height
of the tree, the worst case.

00:46:03.070 --> 00:46:03.905
Question?

00:46:03.905 --> 00:46:11.630
AUDIENCE: Why do you do
[INAUDIBLE] a right child to C,

00:46:11.630 --> 00:46:15.047
but it's like [INAUDIBLE]
you never had a right child?

00:46:15.047 --> 00:46:15.880
ERIK DEMAINE: Right.

00:46:15.880 --> 00:46:17.680
So E didn't used to
have a right child.

00:46:17.680 --> 00:46:19.290
So we're changing
identities of nodes

00:46:19.290 --> 00:46:23.040
when we do this, because
we didn't actually

00:46:23.040 --> 00:46:24.052
move this circle.

00:46:24.052 --> 00:46:26.010
The circle stayed in
place, and what we changed

00:46:26.010 --> 00:46:28.590
was the item that was
stored in that circle.

00:46:28.590 --> 00:46:33.220
So whether you call this node E
or A, it doesn't really matter.

00:46:33.220 --> 00:46:35.640
It is just the root node.

00:46:35.640 --> 00:46:37.890
So we're going to play a lot
of these tricks of moving

00:46:37.890 --> 00:46:38.710
the items around.

00:46:38.710 --> 00:46:40.085
So far we hadn't
been doing that.

00:46:40.085 --> 00:46:43.770
We've just been creating nodes
and placing them somewhere.

00:46:43.770 --> 00:46:45.750
But now in this
delete operation is

00:46:45.750 --> 00:46:47.460
the first time
where we're changing

00:46:47.460 --> 00:46:49.260
what's stored in the nodes.

00:46:49.260 --> 00:46:51.270
But we still can define
the traversal order.

00:46:51.270 --> 00:46:54.490
The traversal order of
this tree is D, B, G, E, H,

00:46:54.490 --> 00:47:00.162
C, which should be what we
get here if I delete F and A.

00:47:00.162 --> 00:47:02.820
AUDIENCE: But what if
we created like a tree--

00:47:02.820 --> 00:47:05.360
ERIK DEMAINE: And-- sorry, F.

00:47:05.360 --> 00:47:06.860
AUDIENCE: [INAUDIBLE]
like it really

00:47:06.860 --> 00:47:11.477
matters to you-- like it
really matters to [INAUDIBLE]

00:47:11.477 --> 00:47:13.560
ERIK DEMAINE: Trees will
not preserve connections.

00:47:13.560 --> 00:47:15.100
That's just the
name of the game.

00:47:15.100 --> 00:47:17.980
We are-- we have to allow this,
otherwise we can't do anything.

00:47:17.980 --> 00:47:21.080
That's the short version.

00:47:21.080 --> 00:47:21.580
OK.

00:47:21.580 --> 00:47:23.130
In the last few
minutes, let me talk

00:47:23.130 --> 00:47:27.360
about how we take these
trees and implement a set

00:47:27.360 --> 00:47:29.010
or sequence.

00:47:29.010 --> 00:47:30.600
I've already alluded to this.

00:47:34.930 --> 00:47:44.640
So for a sequence, we just
make the traversal order

00:47:44.640 --> 00:47:49.278
equal to the order that
we're trying to represent,

00:47:49.278 --> 00:47:50.070
the sequence order.

00:47:53.560 --> 00:47:56.590
And if we're trying to sort
a set, items with keys,

00:47:56.590 --> 00:48:02.200
we're going to make the
traversal order equal to

00:48:02.200 --> 00:48:04.840
ordered by increasing key.

00:48:04.840 --> 00:48:08.936
Increasing item key.

00:48:12.688 --> 00:48:15.200
In some sense that's
it, but then we

00:48:15.200 --> 00:48:17.150
need to think about
how do we implement

00:48:17.150 --> 00:48:19.020
all of these operations.

00:48:19.020 --> 00:48:23.150
So maybe most enlightening
is, for starters,

00:48:23.150 --> 00:48:27.660
is finding a key in a tree.

00:48:27.660 --> 00:48:31.710
So this is going to
correspond to binary search.

00:48:31.710 --> 00:48:34.490
If I'm searching for a key--

00:48:34.490 --> 00:48:37.220
let's say I'm
searching for G's key.

00:48:37.220 --> 00:48:41.010
And I know-- this going to
be hard in this example.

00:48:41.010 --> 00:48:43.860
Maybe I replace these
all with numbers

00:48:43.860 --> 00:48:48.940
so I can think about key values.

00:48:48.940 --> 00:48:58.480
So let's say 1, 7,
12, 17, 19, and 23.

00:48:58.480 --> 00:49:02.380
This is now in key order if you
think of the traversal order.

00:49:02.380 --> 00:49:05.770
The property is that all
the keys in the left subtree

00:49:05.770 --> 00:49:07.410
of the root are
less than the root,

00:49:07.410 --> 00:49:09.910
and the root is less than all
the keys in the right subtree,

00:49:09.910 --> 00:49:11.780
and recursively
all the way down.

00:49:11.780 --> 00:49:17.530
This is something called the
Binary Search Tree property,

00:49:17.530 --> 00:49:18.730
BST property.

00:49:18.730 --> 00:49:24.220
These here, we're calling them
binary tree sets or set binary

00:49:24.220 --> 00:49:26.800
trees, but there are also
none in the literature

00:49:26.800 --> 00:49:29.445
as binary search trees, a term
you may have heard before.

00:49:29.445 --> 00:49:30.820
So this is a
special case of what

00:49:30.820 --> 00:49:33.460
we're doing where we're
restoring the keys in order.

00:49:33.460 --> 00:49:37.810
And then if I want to
search for a key like 13,

00:49:37.810 --> 00:49:39.670
I compare that
key with the root.

00:49:39.670 --> 00:49:43.000
I see, oh, it's not equal,
and it's to the left

00:49:43.000 --> 00:49:44.810
because it's less than 17.

00:49:44.810 --> 00:49:50.230
So 13 is left of here, 13 is
right of 7, 13 is right of 12.

00:49:50.230 --> 00:49:54.415
And so I know that this
is where 13 would belong,

00:49:54.415 --> 00:49:55.790
but there's no
right child there,

00:49:55.790 --> 00:49:58.630
and so I know-- and find
that I just return nothing.

00:49:58.630 --> 00:50:03.550
If I was doing find previous,
I would return this node,

00:50:03.550 --> 00:50:05.860
because I have tried
to go to the right.

00:50:05.860 --> 00:50:08.230
The last time before
I fell off the tree,

00:50:08.230 --> 00:50:11.470
I was trying to go to the right,
and therefore, that last node

00:50:11.470 --> 00:50:12.790
I had was the previous item.

00:50:12.790 --> 00:50:15.380
If I was trying to find
next, what would I do?

00:50:15.380 --> 00:50:18.410
I would just take this node
and computed successor,

00:50:18.410 --> 00:50:20.140
which we already know
how to do, and that

00:50:20.140 --> 00:50:22.060
happens to be the root.

00:50:22.060 --> 00:50:24.610
So now I can do these
inexact searches.

00:50:24.610 --> 00:50:27.880
When I do find previous and find
next, when I fall off the tree,

00:50:27.880 --> 00:50:29.915
I find either the
previous or the next.

00:50:29.915 --> 00:50:31.540
And then with
predecessor or successor,

00:50:31.540 --> 00:50:33.370
I can find the other one.

00:50:33.370 --> 00:50:41.020
So that's how we can do find
and find previous and find next.

00:50:41.020 --> 00:50:47.140
To do sequences, we need
a little bit more work.

00:50:47.140 --> 00:50:50.100
We'll do that next time.