Skip to content

Commit 42c9de7

Browse files
ClémentClément
authored andcommitted
Improving notes on BTrees.
1 parent e82fb15 commit 42c9de7

6 files changed

Lines changed: 180 additions & 45 deletions

File tree

source/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,7 @@ PREREQ: $(TARGET_DIAG) $(TARGET_EXO) $(TARGET_IMAGES_FILES)
310310

311311
.PHONY: CLEAN-PREREQ
312312
CLEAN-PREREQ:
313-
rm -f $(DIAG_DIR)*/*.md $(DIAG_DIR)*/*.png $(DIAG_DIR)*/*m.svg && rm -rf $(EXO_DIR) && rm -rf $(TARGET_IMAGES_FILES)
314-
313+
rm -f $(DIAG_DIR)*/*.md $(DIAG_DIR)*/*.png $(DIAG_DIR)*/*.svg && rm -rf $(EXO_DIR) && rm -rf $(TARGET_IMAGES_FILES)
315314

316315
# PREVIOUS RULE
317316
# $(CLA_DIR)%.md: $(CLA_DIR)%.txt | $(CLA_DIR)%.svg
@@ -385,13 +384,15 @@ $(GRA_DIR)%.svg: $(GRA_DIR)%.txt
385384
@echo "Creating $@"
386385
echo "graph TB" > $@_tmp \
387386
&& cat $< >> $@_tmp \
387+
&& echo "\nclassDef hidden display: none;" >> $@_tmp \
388388
&& mmdc -p .puppeteer.json -i $@_tmp -o $@ \
389389
&& rm $@_tmp
390390

391391
$(GRA_DIR)%.png: $(GRA_DIR)%.txt
392392
@echo "Creating $@"
393393
echo "graph TB" > $@_tmp \
394394
&& cat $< >> $@_tmp \
395+
&& echo "\nclassDef hidden display: none;" >> $@_tmp \
395396
&& mmdc -s 2 -p .puppeteer.json -i $@_tmp -o $@ \
396397
&& rm $@_tmp
397398

source/code/projects/Tree/Tree/BTree.cs

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
public abstract class BTree<T>
55
where T : IComparable<T>
66
{
7+
// We begin by defining a node class.
78
protected class Node
89
{
910
public T Data { get; set; }
@@ -26,9 +27,12 @@ public override string ToString()
2627
return "| " + Data.ToString() + " |";
2728
}
2829
}
30+
// We can now define the BTree class
31+
// using this notion of nodes.
2932

33+
// Constructor, Clear and IsEmpty
34+
// are relying on the root Node.
3035
protected Node root;
31-
3236
public BTree()
3337
{
3438
root = null;
@@ -43,38 +47,8 @@ public bool IsEmpty()
4347
{
4448
return root == null;
4549
}
46-
47-
public override string ToString()
48-
{
49-
string returned = "Depth: " + Depth() + "\n";
50-
if (root != null)
51-
{
52-
returned += Stringify(root, 0);
53-
}
54-
return returned;
55-
}
56-
57-
private string Stringify(Node nodeP, int depth)
58-
{
59-
string returned = "";
60-
if (nodeP != null)
61-
{
62-
for (int i = 0; i < depth; i++)
63-
{
64-
returned += " ";
65-
}
66-
returned += nodeP + "\n"; // Calls Node's ToString method.
67-
if (nodeP.left != null)
68-
{
69-
returned += "L" + Stringify(nodeP.left, depth + 1);
70-
}
71-
if (nodeP.right != null)
72-
{
73-
returned += "R" + Stringify(nodeP.right, depth + 1);
74-
}
75-
}
76-
return returned;
77-
}
50+
// We now look at how to
51+
// compute the Depth of a tree.
7852

7953
public int Depth()
8054
{
@@ -105,6 +79,7 @@ private int Depth(Node nodeP, int depth)
10579
}
10680
return result;
10781
}
82+
// Finding is also recursive.
10883

10984
public virtual bool Find(T dataP)
11085
{
@@ -135,6 +110,8 @@ private bool Find(Node nodeP, T dataP)
135110
return found;
136111
}
137112

113+
// Done with finding.
114+
138115
public abstract void Insert(T dataP);
139116
public abstract bool Delete(T dataP);
140117

@@ -210,4 +187,39 @@ private string TraversePo(Node nodeP)
210187
}
211188
return returned;
212189
}
190+
191+
192+
// The ToString method is simply here to help debug.
193+
194+
public override string ToString()
195+
{
196+
string returned = "Depth: " + Depth() + "\n";
197+
if (root != null)
198+
{
199+
returned += Stringify(root, 0);
200+
}
201+
return returned;
202+
}
203+
204+
private string Stringify(Node nodeP, int depth)
205+
{
206+
string returned = "";
207+
if (nodeP != null)
208+
{
209+
for (int i = 0; i < depth; i++)
210+
{
211+
returned += " ";
212+
}
213+
returned += nodeP + "\n"; // Calls Node's ToString method.
214+
if (nodeP.left != null)
215+
{
216+
returned += "L" + Stringify(nodeP.left, depth + 1);
217+
}
218+
if (nodeP.right != null)
219+
{
220+
returned += "R" + Stringify(nodeP.right, depth + 1);
221+
}
222+
}
223+
return returned;
224+
}
213225
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
A((10))-->B((7))
2+
B-->C((5))
3+
B-->D((8))
4+
A-->E((11))
5+
E~~~H0:::hidden
6+
E-->F((30))
7+
F-->G((12))
8+
G~~~H2:::hidden
9+
G-->H1((15))
10+
F~~~H3:::hidden
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
d1:::depthClass
2+
d2:::depthClass
3+
d3:::depthClass
4+
d4:::depthClass
5+
d5:::depthClass
6+
7+
subgraph d1 [Depth 0]
8+
A((10))
9+
end
10+
subgraph d2 [Depth 1]
11+
B((7))
12+
E((11))
13+
end
14+
subgraph d3 [Depth 2]
15+
C((5))
16+
D((8))
17+
F((30))
18+
end
19+
subgraph d4 [Depth 3]
20+
G((12))
21+
end
22+
subgraph d5 [Depth 4]
23+
H((15))
24+
end
25+
26+
A-->B
27+
B-->C
28+
B-->D
29+
A-->E
30+
E~~~H0:::hidden
31+
E-->F
32+
F-->G
33+
G~~~H2:::hidden
34+
G-->H
35+
F~~~H3:::hidden
36+
37+
classDef depthClass width:30em, height:4em, display:flex, justify-content: flex-start, align-items:flex-end;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
A((10))-->B((7))
2+
B-->C((5))
3+
B-->D((8))
4+
A-->E((11))
5+
E-->N1((null))
6+
E-->F((30))
7+
F-->G((12))
8+
G--->N2((null))
9+
G-->H1((15))
10+
F--->N3((null))

source/lectures/data/trees.md

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,98 @@ As an abstract data type, it generally uses the following definitions:
1313
- A binary tree is made of *nodes*, each of which contain *one value*, can have up to 2 *children*.
1414
- 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.
1515
- 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.
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$.
1717
- The *depth of a tree* is the greatest distance of its nodes.
18-
- A *subtree* is the tree obtain by considering a particular node in a tree as the root of the tree made of its children.
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.
1919

2020
From there, operations generally include, as usual
2121

2222
- Creating an empty tree,
2323
- Adding a node to a tree,
24-
- Finding the smalles value in the tree,
25-
- Removing a node from the tree,
24+
- Finding the smallest value in the tree,
25+
- Removing a node from the tree,
26+
- etc.
2627

27-
<!--
28-
### Abstract Data Type
28+
In the following example:
2929

30-
### Difference with array
31-
-->
30+
!include diag/gra/bstree_example_1_with_depth.md
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 (30): we call it "the right child", and observe that 11 has no "left child",
36+
- The depth of the tree is 3,
37+
- The nodes 7, 5 and 8 taken together form a subtree.
3238

3339
## Possible Implementation
3440

3541
### Binary Tree
3642

37-
We implement a binary tree class abstractly, because two methods will be missing: how to insert a value, and how to delete a value.
43+
#### Node Class
44+
45+
Defining a `BTree` class start by defining a `Node` class:
46+
47+
```{download="./code/projects/Tree.zip"}
48+
!include`snippetStart="// We begin by defining a node class.", snippetEnd="// We can now define the BTree class"` code/projects/Tree/Tree/BTree.cs
49+
```
50+
51+
As we can see, a `Node` has three elements:
52+
53+
- `Data` is the value it is holding,
54+
- `left` denotes its "left child",
55+
- `right` denotes its "right child".
56+
57+
If we wanted to be more technically correct in our drawing, we would explicitly label some nodes as `null`, and the previous tree would actually be as follows:
58+
59+
!include diag/gra/bstree_example_1_with_null.md
60+
61+
#### Initializing
62+
63+
Then, a `BTree` object is simply … the `root` `Node`, and we can construct, empty, and test for emptiness accordingly:
64+
65+
```{download="./code/projects/Tree.zip"}
66+
!include`snippetStart="// are relying on the root Node.", snippetEnd="// We now look at how to"` code/projects/Tree/Tree/BTree.cs
67+
```
68+
69+
#### Computing the Depth
70+
71+
Now, assume that we are given a `BTree` object. How can we compute its depth?
72+
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.
73+
Of course, if the `BTree` is `null`, then deciding its depth is easy: it is $0$.
74+
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+
For this, we will use *recursion*.
76+
77+
In short, for a tree to determine its node, it needs to
78+
79+
- Have its `root` "ask its children" what their deepest node is,
80+
- Take the maximum value returned.
81+
82+
For the `root`'s children to determine what the deepest node under them is, they need both to
83+
84+
- "Ask its children" what is their deepest node,
85+
- Take the maximum value returned.
86+
87+
Etc., etc. Hence, we get:
88+
89+
```{download="./code/projects/Tree.zip"}
90+
!include`snippetStart="// compute the Depth of a tree.", snippetEnd="// Finding is also recursive."` code/projects/Tree/Tree/BTree.cs
91+
```
92+
93+
#### Displaying Trees
94+
95+
#### Implementation Detail
96+
97+
We implemented the binary tree class abstractly, because two methods are still missing: how to insert a value, and how to delete a value (we will add them later on).
98+
This is the reason why we marked the `Node` class as `protected`, and not private: it will still be accessible by the class inheriting from `BTree`.
99+
100+
#### Finding a Value
101+
38102
We also mark the `Find` method as `virtual` because we will override it for something more efficient.
39103
Note, finally, that we use the `protected` keyword, so that classes inheriting the `BTree` class will be able to manipulate `Node`s.
40104

105+
41106
```{download="./code/projects/Tree.zip"}
42-
!include code/projects/Tree/Tree/BTree.cs
107+
!include`snippetStart="// Finding is also recursive.", snippetEnd="// Done with finding."` code/projects/Tree/Tree/BTree.cs
43108
```
44109

45110
### Binary Search Tree

0 commit comments

Comments
 (0)