You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: source/lectures/data/trees.md
+27-24Lines changed: 27 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,38 +10,38 @@ tags:
10
10
A [binary tree](https://en.wikipedia.org/wiki/Binary_tree) is a precise mathematical concept that can be defined as a restriction on graphs.
11
11
As an abstract data type, it generally uses the following definitions:
12
12
13
-
- A binary tree is made of *nodes*, each of which contain*one value*, can have up to 2 *children*.
13
+
- A binary tree is made of *nodes*, each of which holds*one value*, can have up to 2 *children*.
14
14
- A (rooted) binary tree has exactly one node with 0 parent (that is not the child of any other node), called *the root*. Except for the root, all the nodes have exactly one parent.
15
-
- A *leaf* is a node *without children*.
16
-
- The *depth of a node* is the distance (i.e., the number of times we must go to its parent) from it to the root. This means in particular that the depth of a root is $0$.
17
-
- The *depth of a tree* is the greatest distance of its nodes.
15
+
- A node without children is called *a leaf*.
16
+
- The *depth of a node* is the distance (i.e., the number of times we must go to its parent) from it to the root. This means in particular that the depth of the root is $0$.
17
+
- The *depth of a tree* is the maximum depth of the nodes it contain.
18
18
- A *subtree* is the tree obtain by considering a particular node in a tree as the root of the tree made of all the nodes "below" it, starting with its children.
19
19
20
20
From there, operations generally include, as usual
21
21
22
22
- Creating an empty tree,
23
23
- Adding a node to a tree,
24
24
- Finding the smallest value in the tree,
25
-
- Removing a node from the tree,
25
+
- Removing a node holding a specific value from the tree,
26
26
- etc.
27
27
28
28
In the following example:
29
29
30
30
!include diag/gra/bstree_example_1_with_depth.md
31
31
32
-
- The root has value 10,
33
-
- The root has two children, 7 and 11,
34
-
- The leaf with value 5 has $0$ children,
35
-
- The node with value 11 has one child (with value 30): we call it "the right child", and observe that 11 has no "left child",
32
+
- The root holds the value 10,
33
+
- The root has two children, holding the values 7 and 11,
34
+
- The node holding the value 5 has $0$ children, hence it is a leaf,
35
+
- The node with value 11 has one child (holding the value 30): we call it "the right child", and observe that the node holding the value 11 has no "left child",
36
36
- The depth of the tree is $4$,
37
-
- The nodes 7, 5 and 8 taken together form a subtree, of depth $1$.
37
+
- The nodes holding the values 7, 5 and 8 taken together form a subtree, of depth $1$.
38
38
39
39
## Possible Implementation
40
40
41
41
### Binary Tree
42
42
43
43
We implemented the binary tree class abstractly, because two methods will be missing at the beginning: how to insert a value, and how to delete a value (we will add them later on, in a class that will inherit from this `BTree` class).
44
-
This is the reason why we mark the `Node` class as `protected` below, and not private: it will still be accessible by the class inheriting from `BTree`.
44
+
This is the reason why we mark the `Node` class as `protected` below, and not `private`: it will still be accessible by the class inheriting from `BTree`.
45
45
46
46
#### Node Class
47
47
@@ -63,18 +63,20 @@ If we wanted to be more technically correct in our drawing, we would explicitly
63
63
64
64
#### Initializing
65
65
66
-
A `BTree` object is simply … the `root``Node`, and we can construct, empty, and test for emptiness accordingly:
66
+
A `BTree` object is simply the `root``Node`, and we can construct, empty, and test for emptiness accordingly:
67
67
68
68
```{download="./code/projects/Tree.zip"}
69
69
!include`snippetStart="// are relying on the root Node.", snippetEnd="// We now look at how to"` code/projects/Tree/Tree/BTree.cs
70
70
```
71
71
72
-
#### Computing the Depth
72
+
#### Computing the Depth of the tree
73
73
74
74
Now, assume that we are given a `BTree` object. How can we compute its depth?
75
-
Its depth is the depth of the "deeper" node, but each node do not know their depth, only that they have 0, 1 or 2 children.
76
-
Of course, if the `BTree` is `null`, then deciding its depth is easy: it is $0$.
77
-
Then, the idea is that each node knows that its depth is $1$ more than the depth of its parent: remains to find which node has the biggest depth.
75
+
Its depth is the maximum depth of the nodes it contain.
76
+
However, only the root knows its depth (it is $0$), all the other nodes do not know their depth, only that they have 0, 1 or 2 children.
77
+
78
+
Of course, if the `BTree` is `null` or if its `root` has $0$ children, then deciding its depth is easy: it is $0$.
79
+
Otherwise, the idea is that each tree knows that its depth is $1$ more than the depth of the its two sub-trees: remains to find which sub-tree has the biggest depth.
78
80
For this, we will use *recursion*.
79
81
80
82
In short, for a tree to determine its node, it needs to
@@ -93,21 +95,21 @@ Etc., etc. Hence, we get:
93
95
!include`snippetStart="// compute the Depth of a tree.", snippetEnd="// Finding is also recursive."` code/projects/Tree/Tree/BTree.cs
94
96
```
95
97
96
-
Note that we have *two* recursive calls: one for the `left``Node`, one for the `right``Node` (if they are not empty).
98
+
Note that we have *two* recursive calls: one for the `left``Node`, one for the `right``Node` (if they are not `null`).
97
99
98
100
#### Displaying Trees
99
101
100
-
There are essentially three ways of "linearizing" a tree (that is, listing its value as a list), depending how we organize the recursive calls.
102
+
There are essentially three ways of "linearizing" a tree (that is, listing its value in a sequence), depending how we organize the recursive calls.
101
103
102
104
-*Inorder* traversal displays
103
105
- First the left sub-tree,
104
-
- Secondly the data of the current node,
106
+
- Secondly the data held by the current node,
105
107
- Thirdly the right sub-tree.
106
108
107
109
For our recurring example, we obtain "5 7 8 10 11 12 15 30".
108
110
109
111
-*Preorder* traversal displays
110
-
- First the data of the current node,
112
+
- First the data held by the current node,
111
113
- Secondly the left sub-tree,
112
114
- Thirdly the right sub-tree.
113
115
@@ -116,7 +118,7 @@ There are essentially three ways of "linearizing" a tree (that is, listing its v
116
118
-*Postorder* traversal displays
117
119
- First the left sub-tree,
118
120
- Secondly the right sub-tree,
119
-
- Thirdly the data of the current node.
121
+
- Thirdly the data held by the current node.
120
122
121
123
For our recurring example, we obtain "5 8 7 15 12 30 11 10".
122
124
@@ -154,7 +156,7 @@ A binary *search* tree (BST) is a specific type of binary tree that ensures that
154
156
- each node's value is less than all the values stored in its right subtree,
155
157
- a value cannot occur twice.
156
158
157
-
Our example is a binary search thee:
159
+
Our recurring example happens to be a binary search tree:
158
160
159
161
- All the values "to the left of" the root are less than $10$,
160
162
- All the values "to the right of" the root are greater than $10$,
@@ -163,10 +165,11 @@ Our example is a binary search thee:
163
165
- etc.
164
166
165
167
Note that this is the reason why the node with value $30$ is drawn "to the right of" the node with value $11$: we always need to make the difference between left and right children, even if there is only one child.
168
+
A tree almost identical to our recurring example, but where $30$ was at the right of the node holding the value $11$ would not be a binary *search* tree, but simply a binary tree.
166
169
167
170
#### Implementation detail
168
171
169
-
Note that since we need to be able to compare our values, we must tell C# that we will not just be using any `T`generic type, but a type that realizes the [IComparable](https://learn.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=net-9.0) interface.
172
+
Note that since we need to be able to compare our values, we must tell C# that we will not just be using any generic type`T`, but a type that realizes the [IComparable](https://learn.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=net-9.0) interface.
170
173
This forces `T` to have a `CompareTo` method, that we will use to compare the data held by the nodes as follows:
171
174
172
175
```
@@ -178,7 +181,7 @@ will return
178
181
- a value less than $0$ if `dataP < nodeP.Data`,
179
182
- a value greater than $0$ if `dataP > nodeP.Data`.
180
183
181
-
Similarly to the `Equals` method, this is because the `>` and `<` operators are not overloaded by default, so we must use this more convoluted way of determining if `dataP` is less than or greater than `nodeP.Data`. Of course, if neither is `true`, it means that `dataP` is equl to `nodeP.Data`.
184
+
Similarly to the `Equals` method, this is because the `>` and `<` operators are not overloaded by default, so we must use this more convoluted way of determining if `dataP` is less than or greater than `nodeP.Data`. Of course, if neither is `true`, it means that `dataP` is equal to `nodeP.Data`.
0 commit comments