Skip to content

Commit 8bb7aad

Browse files
committed
AVL terminology, search, BST
1 parent 18ed189 commit 8bb7aad

File tree

4 files changed

+95
-146
lines changed

4 files changed

+95
-146
lines changed

src/algorithms/controllers/AVLTreeSearch.js

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
* This file contains the AVL Tree Search algorithm,
33
* alongside the visualisation code.
44
*
5+
* XXX needs a bunch more fixes. Best ignore height and balance, highlight
6+
* nodes at the right points (done), improve display of t if possible,...
7+
*
58
* The AVL Tree Search algorithm is used to find a node.
69
*
710
* The search algorithm is based on the tree created by the insertion algorithm.
@@ -41,51 +44,62 @@ export default {
4144
let current = root;
4245
let parent = null;
4346

44-
chunker.add('AVL_Search(t, k)', (vis) => {
45-
vis.graph.setFunctionInsertText(" (" + target + ") ");
47+
chunker.add('AVL_Search(t, k)', (vis, c, p) => {
48+
vis.graph.setZoom(0.55);
49+
vis.graph.setFunctionInsertText("(t, " + target + ")");
4650
vis.graph.setFunctionName("AVL_Search");
47-
});
48-
chunker.add('while t not Empty');
51+
vis.graph.visit(c, p);
52+
}, [current, parent]);
53+
if (!tree)
54+
chunker.add('while t not Empty');
4955

5056
let ptr = tree;
5157
parent = current;
5258

53-
while (ptr) {
59+
/* eslint-disable no-constant-condition */
60+
while (true) {
61+
chunker.add('while t not Empty');
62+
63+
if (current === undefined || !ptr) // should use null
64+
break;
5465

55-
chunker.add('n = root(t)', (vis, c, p) => vis.graph.visit(c, p), [current, parent]);
5666
let node = current;
5767
chunker.add('if n.key = k');
5868
if (node === target) {
59-
chunker.add('if n.key = k', (vis, c, p) => vis.graph.leave(c, p), [node, parent]);
60-
chunker.add('return t', (vis, c, p) => vis.graph.select(c, p), [node, parent]);
69+
chunker.add('return t', (vis, c, p) => {
70+
vis.graph.leave(c, p);
71+
vis.graph.select(c, p);
72+
vis.graph.setText('Key found');
73+
}, [node, parent]);
6174
return 'success';
6275
}
6376

6477
chunker.add('if n.key > k');
6578
if (target < node) {
66-
if (tree[node].left !== undefined) {
67-
// if current node has left child
68-
parent = node;
69-
current = tree[node].left;
70-
ptr = tree[node];
79+
parent = node;
80+
current = tree[node].left;
81+
ptr = tree[node];
82+
if (current !== undefined) {
7183

72-
chunker.add('t <- n.left');
84+
chunker.add('t <- n.left', (vis, c, p) => vis.graph.visit(c, p), [current, parent]);
7385
} else {
74-
break;
86+
chunker.add('t <- n.left', (vis) => vis.graph.setText('t = Empty'));
7587
}
76-
} else if (tree[node].right !== undefined) {
77-
// if current node has right child
88+
} else {
7889
parent = node;
7990
current = tree[node].right;
8091
ptr = tree[node];
81-
82-
chunker.add('t <- n.right');
83-
} else {
84-
break;
92+
// if current node has right child
93+
if (current !== undefined) {
94+
chunker.add('t <- n.right', (vis, c, p) => vis.graph.visit(c, p), [current, parent]);
95+
} else {
96+
chunker.add('t <- n.right', (vis) => vis.graph.setText('t = Empty'));
97+
}
8598
}
8699
}
87100

88-
chunker.add('return NotFound', (vis) => vis.graph.setText('RESULT NOT FOUND'));
101+
chunker.add('return NotFound', (vis) => vis.graph.setText('Key not found'));
89102
return 'fail';
90103
},
91-
};
104+
};
105+

src/algorithms/pseudocode/AVLTreeInsertion.js

Lines changed: 44 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -10,93 +10,17 @@ renamed according to new structure
1010
\\Note{ modified from BST - best check actual running BST Real code for
1111
search and use that XXX still needs unification with BST
1212
13-
Terminology (might change???)
14-
For BST we confound t.key and t->key, eg, we have c <- c.left. Its not
15-
too bad with BST code, but here the code gets more complex, with
16-
multiple levels of the tree involved using c.left.left is a bit too
17-
dodgy(?). So we use:
18-
19-
root(t) = (*t)
20-
left(t) = *(t->left) (or Empty) ?????
21-
right() similarly
22-
root(t).key, root(t).height, etc
23-
left(t).height, etc ???
24-
XXX maybe use height(t), key(t), left(t), right(t)
13+
Terminology (changed, might change again but this looks OK I reckon)
14+
XXX should change BST (et al?) so it is consistent
15+
We brush over the fact that pointers are used and use record notation
16+
"." where C "->" would be used (implicit dereference of pointer).
17+
t <- t.left etc is the most dubious looking code if we think of records
18+
and not pointers.
19+
Basically t = Empty or, otherwise, t.key, t.left and t.right exist (we
20+
don't explicitly use t.height in the code but could). Creating a new
21+
singleton tree is done in a single step.
2522
\\Note}
2623
27-
\\Overview{ A binary tree is either is either empty (Empty) or else it
28-
it has a root node and two subtrees (which are binary trees).
29-
The root node t has a key, t.key. Ordinarily it would also
30-
hold other data (t.data), which the user would like to find by
31-
searching for the key. Since this attribute has no impact on
32-
how insertion and search take place, we disregard it here.
33-
Note that a newly inserted node will always appear as a leaf
34-
in the tree. The BST invariant is always maintained: for each
35-
subtree t, with root key t.key, the left subtree, t.left,
36-
contains no node with key greater than k, and the right subtree,
37-
t.right, contains no node with key smaller than k.
38-
XXX AVL trees balanced, shorten above
39-
Need to have these rotation explanations here as we can't format
40-
explanations properly it seems:
41-
42-
## The left-left case
43-
44-
If the new key was added to the left child of the left child (the
45-
left-left case) and the resulting tree is too unbalanced, the balance can be
46-
restored with a "Right rotation" operation, as explained in the diagram
47-
below. The 6 and 4 nodes and the edge between them rotate clockwise, and
48-
the 5 node changes parents from 4 to 6. This reduces the distance from
49-
the root to the 1 (where the new node was added), restoring the balance
50-
(the distance to the node rooted at 7 is increased but this does not
51-
cause the AVL tree balance condition to be violated). Right rotation is
52-
done by calling rightRotate(t6), where t6 is the tree rooted at 6.
53-
54-
'''
55-
6 2
56-
/ \\ Right Rotation / \\
57-
2 7 - - - - - - - > 1 6
58-
/ \\ < - - - - - - - / \\
59-
1 4 Left Rotation 4 7
60-
'''
61-
62-
## The right-right case
63-
64-
The right-right case is the exact opposite. If the tree on the right in
65-
the diagram above is too unbalanced due to insertion into the subtree
66-
rooted at 7, we can call rightRotate(t2) to lift that subtree and lower
67-
the 1 subtree.
68-
69-
## The left-right case (double rotation)
70-
71-
If the new key was added to the right child of the left child (the
72-
left-right case) and the resulting tree is too unbalanced, the balance can be
73-
restored with a left rotation at node 2 followed by a right rotation at
74-
node 6.
75-
'''
76-
6 Rotate 6 Rotate 4
77-
/ \\ left at 2 / \\ right at 6 / \\
78-
2 7 - - - - - > 4 7 - - - - - > 2 6
79-
/ \\ / \\ / \\ / \\
80-
1 4 2 5 1 3 5 7
81-
/ \\ / \\
82-
3 5 1 3
83-
'''
84-
Nodes in the subtree rooted at 4 (where the extra element was added,
85-
making the tree unbalanced) are moved closer to the root.
86-
Trees rooted at 1, 3, 5 and 7 are not affected, except the distances from
87-
the root of 3, 5 and 7 are changed by one, affecting the overall balance.
88-
89-
## right-left case (double rotation):
90-
91-
If the new key was added to the left child of the right child (the
92-
right-left case) and the resulting tree is too unbalanced, it is a mirror
93-
image of the left-right case:
94-
95-
XXX edit diagram above (tree on left won't be consistent with previous
96-
examples but thats OK I think)
97-
98-
\\Overview}
99-
10024
\\Note{ For both insertion and search, the animation should be as
10125
consistent
10226
as possible with BST
@@ -124,14 +48,14 @@ AVLT_Insert(t, k) // returns t with key k inserted \\B AVLT_Insert(t, k)
12448
This is the base case of the recursion.
12549
\\Expl}
12650
\\In}
127-
if k < root(t).key \\B if k < root(t).key
51+
if k < t.key \\B if k < root(t).key
12852
\\Expl{ The key in the root determines if we insert into the left or
12953
right subtree.
13054
\\Expl}
13155
\\In{
13256
insert k into the left subtree of t \\Ref insertLeft
13357
\\In}
134-
else if k > root(t).key \\B else if k > root(t).key
58+
else if k > t.key \\B else if k > root(t).key
13559
\\Note{ XXX allow duplicate keys or not???
13660
Should be possible, but have to carefully review code to make sure its
13761
correct. What does BST code do?
@@ -169,14 +93,10 @@ recursive call plus we need a chunk at this level of recursion just
16993
before the call so we can step back to it
17094
\\Note}
17195
// *recursively* call insert with the left subtree \\B prepare for the left recursive call
172-
AVLT_Insert(left(t), k) \\B left(t) <- AVLT_Insert(left(t), k)
96+
t.left <- AVLT_Insert(t.left, k) \\B left(t) <- AVLT_Insert(left(t), k)
17397
\\Expl{
174-
The left subtree is replaced by the result of this recursive call
98+
The (possibly empty) left subtree is replaced by the result of this recursive call.
17599
\\Expl}
176-
\\Note{
177-
XXX should this be left(t) <- AVLT_Insert(left(t), k) or is the
178-
explanation enough? (same for right)
179-
\\Note}
180100
\\Code}
181101
182102
@@ -188,16 +108,16 @@ recursive call plus we need a chunk at this level of recursion just
188108
before the call so we can step back to it
189109
\\Note}
190110
// *recursively* call insert with the right subtree \\B prepare for the right recursive call
191-
AVLT_Insert(right(t), k) \\B right(t) <- AVLT_Insert(right(t), k)
111+
t.right <- AVLT_Insert(t.right, k) \\B right(t) <- AVLT_Insert(right(t), k)
192112
\\Expl{
193-
The right subtree is replaced by the result of this recursive call
113+
The (possibly empty) right subtree is replaced by the result of this recursive call.
194114
\\Expl}
195115
\\Code}
196116
197117
\\Code{
198118
rotateIfNeeded
199119
switch balanceCase(t) of \\B switch balanceCase of
200-
\\Expl{ If the "balance" of t (left(t).height - right(t).height) is between -1
120+
\\Expl{ If the "balance" of t (t.left.height - t.right.height) is between -1
201121
and 1, inclusive, we just
202122
return t. Otherwise we must determine which sub-sub-tree the new element was
203123
inserted into and use "rotation" operations to raise up that subtree and
@@ -216,7 +136,7 @@ case Balanced:// sufficiently balanced \\B case Balanced
216136
case Left-Left:// Left-Left insertion, unbalanced \\B perform right rotation to re-balance t
217137
\\Expl{
218138
Key k was inserted into the left-left subtree and made t unbalanced
219-
(balance > 1 and k < left(t).key).
139+
(balance > 1 and k < t.left.key).
220140
We must re-balance the tree with a "right rotation" that lifts up this
221141
subtree. See Background (click at the top of the right panel)
222142
for diagrams etc explaining rotations.
@@ -227,7 +147,7 @@ case Left-Left:// Left-Left insertion, unbalanced \\B perform right rotation to
227147
case Right-Right:// Right-Right insertion, unbalanced \\B perform left rotation to re-balance t
228148
\\Expl{
229149
Key k was inserted into the right-right subtree and made t unbalanced
230-
(balance < -1 and k > right(t).key).
150+
(balance < -1 and k > t.right.key).
231151
We must re-balance the tree with a "left rotation" that lifts up this
232152
subtree. See Background (click at the top of the right panel)
233153
for diagrams etc explaining rotations.
@@ -238,38 +158,50 @@ case Right-Right:// Right-Right insertion, unbalanced \\B perform left rotation
238158
case Left-Right:// Left-Right insertion, unbalanced \\B perform left rotation on the left subtree
239159
\\Expl{
240160
Key k was inserted into the left-right subtree and made t unbalanced
241-
(balance > 1 && k > left(t).key).
242-
Balance can be restored by performing a "left rotation" on left(t) (this
161+
(balance > 1 && k > t.left.key).
162+
Balance can be restored by performing a "left rotation" on t.left (this
243163
lifts up the subtree) followed by a right rotation of t (in case the first
244164
rotation made the left-left subtree too deep).
245165
See Background (click at the top of the right panel)
246166
for diagrams etc explaining rotations.
247167
\\Expl}
248168
\\In{
249-
perform leftRotate(left(t)); // raise Left-Right subtree \\B left(t) <- leftRotate(left(t));
169+
t.left <- leftRotate(t.left); // raise Left-Right-Right subtree \\B left(t) <- leftRotate(left(t));
250170
\\Expl{
251-
The result returned is the new left(t). This lowers the Left-Left
252-
subtree.
171+
This also raises the root of the Left-Right subtree.
172+
The Left-Right-Left subtree remains at the same level but is now the
173+
Left-Left-Right subtree (it is raised in the next step).
253174
\\Expl}
254175
return rightRotate(t) // raise Left-Left subtree to balance \\B return rightRotate(t) after leftRotate
176+
\\Expl{
177+
This raises what was previously the Left-Right-Left subtree, so the
178+
whole of the previous Left-Right subtree is now higher (and the
179+
Right subtree is lower).
180+
\\Expl}
255181
\\In}
256182
case Right-Left:// Right-Left insertion, unbalanced \\B perform right rotation on the right subtree
257183
\\Expl{
258184
Key k was inserted into the right-left subtree and made t unbalanced
259-
(balance < -1 && k < right(t).key).
260-
Balance can be restored by performing a "right rotation" on right(t) (this
185+
(balance < -1 && k < t.right.key).
186+
Balance can be restored by performing a "right rotation" on t.right (this
261187
lifts up the subtree) followed by a left rotation of t (in case the first
262188
rotation made the right-right subtree too deep).
263189
See Background (click at the top of the right panel)
264190
for diagrams etc explaining rotations.
265191
\\Expl}
266192
\\In{
267-
perform rightRotate(right(t)); // raise Right-Left subtree \\B right(t) <- rightRotate(right(t));
193+
t.right <- rightRotate(t.right); // raise Right-Left-Left subtree \\B right(t) <- rightRotate(right(t));
268194
\\Expl{
269-
The result returned is the new right(t). This lowers the Right-Right
270-
subtree.
195+
This also raises the root of the Right-Left subtree.
196+
The Right-Left-Right subtree remains at the same level but is now the
197+
Right-Right-Left subtree (it is raised in the next step).
271198
\\Expl}
272199
return leftRotate(t) // raise Right-Right subtree to balance \\B return leftRotate(t) after rightRotate
200+
\\Expl{
201+
This raises what was previously the Right-Left-Right subtree, so the
202+
whole of the previous Right-Left subtree is now higher (and the
203+
Left subtree is lower).
204+
\\Expl}
273205
\\In}
274206
// ==== rotation functions ====
275207
leftRotate(t2) // raises Right-Right + lowers Left-Left subtrees \\B leftRotate(t2)
@@ -280,8 +212,8 @@ See Background (click at the top of the right panel)
280212
for diagrams etc explaining rotations.
281213
\\Expl}
282214
\\In{
283-
t6 <- right(t2) \\B t6 = right(t2)
284-
t4 <- left(t6) // may be Empty \\B t4 = left(t6)
215+
t6 <- t2.right \\B t6 = right(t2)
216+
t4 <- t6.left // may be Empty \\B t4 = left(t6)
285217
t6.left <- t2 \\B t6.left = t2
286218
t2.right <- t4 // may be Empty \\B t2.right = t4
287219
recompute heights of t2 and t6 \\B recompute heights of t2 and t6
@@ -298,8 +230,8 @@ See Background (click at the top of the right panel)
298230
for diagrams etc explaining rotations.
299231
\\Expl}
300232
\\In{
301-
t2 <- left(t6) \\B t2 = left(t6)
302-
t4 <- right(t2) // may be Empty \\B t4 = right(t2)
233+
t2 <- t6.left \\B t2 = left(t6)
234+
t4 <- t2.right // may be Empty \\B t4 = right(t2)
303235
t2.right <- t6 \\B t2.right = t6
304236
t6.left <- t4 // may be Empty \\B t6.left = t4
305237
\\Note{ Animation here should be as smooth an intuitive as possible.

src/algorithms/pseudocode/AVLTreeSearch.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,31 @@ AVLT_Search(t, k) // return subtree whose root has key k; or NotFound \\B AVL_
99
\\In{
1010
while t not Empty \\B while t not Empty
1111
\\In{
12-
n = root(t) \\B n = root(t)
13-
\\Note{ Avoids confounding pointers and nodes XXX not worth it???
14-
could use key(t), left(t), right(t) below; make as similar to
15-
AVLTree code as possible
12+
\\Note{ Old code:
13+
n = root(t) \\B n = root(t)
14+
Avoids confounding pointers and nodes XXX not worth it???
15+
now use t.key etc below; bookmarks not changed XXX
1616
\\Note}
17-
if n.key = k \\B if n.key = k
17+
if t.key = k \\B if n.key = k
1818
\\In{
1919
return t \\B return t
2020
\\Expl{ We have found a node with the desired key k.
2121
\\Expl}
2222
\\In}
23-
if n.key > k \\B if n.key > k
23+
if k < t.key \\B if n.key > k
2424
\\Expl{ The BST condition is that nodes with keys less than the
2525
current node's key are to be found in the left subtree, and
2626
nodes whose keys are greater are to be in the right subtree.
2727
\\Expl}
2828
\\In{
29-
t <- n.left \\B t <- n.left
29+
t <- t.left \\B t <- n.left
3030
\\In}
3131
else
3232
\\In{
33-
t <- n.right \\B t <- n.right
33+
t <- t.right \\B t <- n.right
3434
\\In}
35-
return NotFound \\B return NotFound
3635
\\In}
36+
return NotFound \\B return NotFound
3737
\\In}
3838
\\Code}
3939
`);

0 commit comments

Comments
 (0)